[csaw ctf 2014] 2013Reversing2

2017. 10. 31. 18:560x07 CTF/[스스로 푼 것]

728x90

바이너리 : x86_64

점수 : 200

날짜 : 2017-10-31 

소요 시간 : 오후 4시 ~ 오후 6시 2분 (다운로드 시간 ~ 푼 시간)

목적 : 화이트햇 준비로 인한 트레이싱 능력 기르기 + 최대한 빠르게 풀어 보려고 했음  

반성 : 빠르게 풀기 실패했다. 대회 때 혹은 일상 때 문제 풀 때는 카톡 안해야지 카톡 하다보니 자꾸 헷갈렸다....

특이점 : aslr, isdebuggerpresent 역 우회 , int 3 우회 , increment 우회 

대회 때는 ASLR 우회하고 하는 방법을 익혀야겠다. 심히 헷갈렸다.

바이너리 최종 목적 : 점프를 우회하여 xor 복호화 시키기 


시행착오 : 


00DA1040   .  6A 00         push 0x0                                        ; /MaximumSize = 0x0

00DA1042   .  6A 00         push 0x0                                        ; |InitialSize = 0x0

00DA1044   .  68 00000400   push offset apisetsc.<ModuleEntryPoint>         ; |Flags = 40000

00DA1049   .  FF15 1060DA00 call near dword ptr [<&KERNEL32.HeapCreate>]    ; \HeapCreate

HeapCreate를 보자마자 그냥 겁먹어버렸다. 힙 문제를 한번도 풀어보지 않아서 였다. 하지만, 알고보니 힙을 사용해도 지역함수에선 스택에 값이 노출되었다.  


00DA1052      A1 349BDA00   mov eax,dword ptr [0xDA9B34]                    ;  주소를 앞쪽으로 대입 (aslr적용되어잇으니조심)

00DA1057      40            inc eax                                         ;  +1 되면 뽑이 안나온다


[0xDA9B34] : 


몇 번 디버깅 결과 뒤에 루틴에서 자꾸 비교 하는 것이 이놈이었다. (16진수)


그래서 상상해보았을 때 mov eax,dword ptr [0xDA9B34]를 [0xDA9B10]으로 바꾸어야 한다고 생각했다. 이 때부터가 삽질의 시작이었다... 

당연히 BB와 같아지면 inc eax 까지 nop 처리 했었다. 


이렇게 하니 이런 결과가 나왔다. 

00DA1058   .  50            push eax                                        ; /HeapSize

00DA1059   .  6A 08         push 0x8                                        ; |Flags = HEAP_ZERO_MEMORY

00DA105B   .  FF75 FC       push dword ptr [ebp-0x4]                        ; |hHeap

00DA105E   .  FF15 0460DA00 call near dword ptr [<&KERNEL32.HeapAlloc>]     ; \HeapAlloc

00DA1064   .  8945 F4       mov dword ptr [ebp-0xC],eax

00DA1067   .  FF35 349BDA00 push dword ptr [0xDA9B34]                       ; /Arg4 = 00000024

00DA106D   .  68 109BDA00   push csaw2013.00DA9B10                          ; |Arg3 = 00DA9B10

00DA1072   .  FF35 349BDA00 push dword ptr [0xDA9B34]                       ; |Arg2 = 00000024

00DA1078   .  FF75 F4       push dword ptr [ebp-0xC]                        ; |Arg1

00DA107B   .  E8 88000000   call csaw2013.00DA1108                          ; \csaw2013.00EE1108

여기서 arg1가 원래는 023207d0인데 , 다른 값으로 바뀌어 버리면서 정확하게 매핑하지 못하여 에러가 터진다.


그래서 이 부분은 고치면 안되는 구나 하고 깨닫게 되었다.


그럼 다시 ctrl+f2를 하여 재시작 하고 트레이싱을 진행했다.


ASLR이 적용되어 있어 주소는 바뀌었으나 OPCODE는 변하지 않기 때문에 그것을 보고 쭉  일련의 과정을 반복했다.


여기서 알게 된 것은 

01081130  |. /EB 48         jmp short csaw2013.0108117A                     ;  그럼 인스트럭션이 같다는것

01081132  |> |837D 10 00    cmp [arg.3],0x0                                 ;  하기에서 두개다 0104114e로 점프(같은 곳으로 점프)

01081136  |. |74 16         je short csaw2013.0108114E

01081138  |. |3975 0C       cmp [arg.2],esi

0108113B  |. |72 11         jb short csaw2013.0108114E


[여담]

0108114E로 둘 다 분기 되기 때문에 instruction의 갯수가 일치 할거라고 판단하였고, 

0108117A로 가면 instruction이 달라질 것이라고 생각하게 되었다.



엄청나게 고민하면서 삽질 했던 구간이다... 실상은 별 거 없었다.. 이제 든 생각은 어느정도 트레이싱에 익숙해졌으니 대회 때는 시간 단축을 위해 엄청난 의심이 되지 않는 곳은 과감하게 넘어가자는 생각도 가지게 되었다.


010814A0   $  55            push ebp                                        ;  ANALYSIS START

010814A1   .  8BEC          mov ebp,esp

010814A3   .  57            push edi

010814A4   .  56            push esi

010814A5   .  8B75 0C       mov esi,dword ptr [ebp+0xC]                     ;  ebp+0xc에 이상한 값

010814A8   .  8B4D 10       mov ecx,dword ptr [ebp+0x10]

010814AB   .  8B7D 08       mov edi,dword ptr [ebp+0x8]

010814AE      8BC1          mov eax,ecx                                     ;  의심

010814B0   .  8BD1          mov edx,ecx

010814B2      03C6          add eax,esi                                     ;  eax에 0을 대입하면 어떻게 될까?

010814B4   .  3BFE          cmp edi,esi

010814B6   .  76 08         jbe short csaw2013.010814C0                     ;  EDI가 더 작은 수이기 때문에 조건 CORRECT

010814B8   .  3BF8          cmp edi,eax

010814BA   .  0F82 A0010000 jb csaw2013.01081660

010814C0   >  81F9 80000000 cmp ecx,0x80                                    ;  patch

010814C6      72 1C         jb short csaw2013.010814E4                      ;  왠지 우회 삘

010814C8      833D A8A70801>cmp dword ptr [0x108A7A8],0x0                   ;  PATCH

010814CF   .  74 13         je short csaw2013.010814E4                      ;  우회 의심 중



문제 풀이 


요약 : 이 문제는 그냥 쭉 트레이싱 하다가 messagebox가 생성되는 구간이 2군데가 있는데, 무작정 실행해보면 완전히 으깨진 문구가 나온다. 그 문구를 보통 나 같은 경우는 아주 간단하게 xor로 티나게 해두어서 그 부분만 열심히 뒤적 뒤적 거리다가 시간 소모가 많았던 것으로 간주 된다. 



보통 isDebuggerPresent는 디버깅상태일 때 종료인데, 이번 문제는 강제로 디버깅상태로 만들어도 원하는 루틴으로 내려갈 수 있었다. 물론 jmp라는 아주 좋은 eip 조작하는 아이도 있긴 하지만.... jmp보다 한번 더 개념 정리를 해보기 위해 

test값을 1로 변경하였다. 


개념

IsDebuggerPresent()는 해당 프로세스가 디버깅을 당하고있는지의 여부를 PEB구조체의 디버깅 상태값을 확인한다. 


0108108C   .  FF15 14600801 call near dword ptr [<&KERNEL32.IsDebuggerPrese>; [IsDebuggerPresent

01081092   .  85C0          test eax,eax      ; test 패치

01081094      74 23         je short csaw2013.010810B9             ;자연스레 je 불만족 


software bp가 걸려있다. 그리고 ecx를 엄청 더하는데 있으면 도움 안되는 놈이다. 

01081096      41            inc ecx

01081097      41            inc ecx

01081098      41            inc ecx

01081099      41            inc ecx

0108109A      CC            int3                                            ;  인터럽트는 과감하게 NOP


어제 사실 첨 안것이지만, int 3 (0xcc)는 디버거에서 F2를 눌렀을 때 나타나는 BP와 같다고 한다. 하지만, 사용자는 INT 3이나 OXCC로 되어 있으면 허걱 겁먹고 NOP처리 할 수 있기 때문에 실제 사용하는 instruction은 보여주고 뒤에서 조용히 0xCC 처리 한다.


즉, 그냥 나만 이해할 수 있는 문장으로 서술해보면..... 다음과 같다.


[ 0xCC가 사실상 아님]  ------> 후방에서 디버거는 0xCC를 살짝 적어둠 ------> cpu(ollydbg 인터페이스)를 트레이싱 할 때 디버거에 적혀있는 bp 리스트를 보고 아 여기서 잠시 멈춰야 하는 구나 하고 인지 할 수 있음 


이 문제는 EDX가 산술 연산을 하는 것으로 보였다. EAX또는 EDX 둘 다 산술연산을 하는 것으로 생각하고 있어야 한다. 예전에 완전한 고정관념이 있던 시절 (==개념 공부 덜 된 시절) 에 EAX만 열심히 뒤적뒤적 거려서 문제푸는데 7시간 30분 가량 걸렸다 ㅠㅠ 


0108109B   .  8B55 F4       mov edx,dword ptr [ebp-0xC]                     ;  일반적으로 하기의 CALL에 접근 가능한지 유무 


상기의 주석은 테스트할 때 call 전에 여기에 접근이 가능한지 스스로 기억하기 위해 적어둔 주석이다.


0108100E  |> /8A08          /mov cl,byte ptr [eax]

01081010  |. |40            |inc eax

01081011  |. |84C9          |test cl,cl

01081013  |.^\75 F9         \jnz short csaw2013.0108100E

여기에서 ecx의 8바이트 cl에서 0x00이 될 때까지 자꾸 자꾸 괴상한 값들이 놀기 시작한다.


0108101F  |> /31348A        /xor dword ptr [edx+ecx*4],esi

01081022  |. |41            |inc ecx

01081023  |. |3BC8          |cmp ecx,eax

01081025  |.^\72 F8         \jb short csaw2013.0108101F

여기서 [edx+ecx*4]와 esi(DDCCAABB)를 XOR하면 플래그가 나온다.


총 9번 반복하여 JB가 성립되지 않으면 하기의 instruction으로 가게 된다.


00CD07D0  00 66 6C 61 67 7B 72 65  .flag{re

00CD07D8  76 65 72 73 69 6E 67 5F  versing_

00CD07E0  69 73 5F 6E 6F 74 5F 74  is_not_t

00CD07E8  68 61 74 5F 68 61 72 64  hat_hard

00CD07F0  21 7D 00 00 00 00 00 00  !}......


이때, 히히 하고 생각없이 위의 MessageBoxA로 eip를 옮기면 완전 깔끔한 플래그가 보일 것이다.



        

지금 보면

00CD07D0  00 66 6C 61 67 7B 72 65  .flag{re

00CD07D8  76 65 72 73 69 6E 67 5F  versing_

00CD07E0  69 73 5F 6E 6F 74 5F 74  is_not_t

00CD07E8  68 61 74 5F 68 61 72 64  hat_hard

00CD07F0  21 7D 00 00 00 00 00 00  !}......


EBP-0xc는 주소 00CD07D0인데 00CD07D0은 0x00 즉, 아무 것도 없는 것으로 인식하게 된다.... 


우회에 너무 맛들리지 말아야 한다








'0x07 CTF > [스스로 푼 것]' 카테고리의 다른 글

34C3 CTF  (0) 2017.12.29
0x00ctf hello  (0) 2017.12.29
0x00 CTF challenge 001  (0) 2017.12.28
0x00 ctf guessme  (0) 2017.12.28
[csawctf2014][dumpster-diving]  (0) 2017.10.31