CTF | wargame

RPISEC 연습문제 / crackme0x0?? (기초 리버싱, radare2 연습)

nopdata 2018. 2. 27. 21:36
문제는 간단하다. password를 받고 고정된 값과 같으면 성공 메시지를 출력한다.

strings로 긁어낼 수도 있다. 먼저 radare2를 이용하기 전이라면 사용했을 gdb를 이용한다.

[ gdb / b *main+70 ]

main+70에는 strcmp가 들어있다. 비교구문을 잡으면 스택에 비교하는 데이터들을 확인할 수 있기 때문.
보면 1234는 입력한 값이고 g00dJ0B!이 flag가 된다.



radare2를 이용한 풀이이다.
아직 문제를 더 풀어 보아야 할 듯 하다.
기본적인 명령어
aa - analyze all
pdf @ function name - function
[0x08048430]> pdf @main
            ;-- main:
/ (fcn) sym.main 133
|   sym.main ();
|           ; var int local_4h @ esp+0x4
|           ; var int local_13h @ esp+0x13
|           ; var int local_2ch @ esp+0x2c
|              ; DATA XREF from 0x08048447 (entry0)
|           0x080484e4      55             push ebp
|           0x080484e5      89e5           mov ebp, esp
|           0x080484e7      83e4f0         and esp, 0xfffffff0
|           0x080484ea      83ec30         sub esp, 0x30               ; '0'
|           0x080484ed      65a114000000   mov eax, dword gs:[0x14]    ; [0x14:4]=-1 ; 20
|           0x080484f3      8944242c       mov dword [local_2ch], eax
|           0x080484f7      31c0           xor eax, eax
|              ; JMP XREF from 0x08048560 (sym.main)
|       .-> 0x080484f9      b840860408     mov eax, str.Enter_password: ; 0x8048640 ; "Enter password: "
|       :   0x080484fe      890424         mov dword [esp], eax
|       :   0x08048501      e8cafeffff     call sym.imp.printf         ; int printf(const char *format)
|       :   0x08048506      b851860408     mov eax, 0x8048651          ; "%s"
|       :   0x0804850b      8d542413       lea edx, [local_13h]        ; 0x13 ; 19
|       :   0x0804850f      89542404       mov dword [local_4h], edx
|       :   0x08048513      890424         mov dword [esp], eax
|       :   0x08048516      e805ffffff     call sym.imp.__isoc99_scanf
|       :   0x0804851b      8d442413       lea eax, [local_13h]        ; 0x13 ; 19
|       :   0x0804851f      89442404       mov dword [local_4h], eax
|       :   0x08048523      c7042424a004.  mov dword [esp], str.g00dJ0B ; obj.pass.1685 ; [0x804a024:4]=0x64303067 ; "g00dJ0B!"
|       :   0x0804852a      e891feffff     call sym.imp.strcmp         ; int strcmp(const char *s1, const char *s2)
|       :   0x0804852f      85c0           test eax, eax
|      ,==< 0x08048531      7521           jne 0x8048554
|      |:   0x08048533      c70424548604.  mov dword [esp], str.Congrats ; [0x8048654:4]=0x676e6f43 ; "Congrats!"
|      |:   0x0804853a      e8b1feffff     call sym.imp.puts           ; int puts(const char *s)
|      |:   0x0804853f      90             nop
|      |:   0x08048540      b800000000     mov eax, 0
|      |:   0x08048545      8b54242c       mov edx, dword [local_2ch]  ; [0x2c:4]=-1 ; ',' ; 44
|      |:   0x08048549      653315140000.  xor edx, dword gs:[0x14]
|     ,===< 0x08048550      7415           je 0x8048567
|    ,====< 0x08048552      eb0e           jmp 0x8048562
|    ||`--> 0x08048554      c704245e8604.  mov dword [esp], str.Wrong  ; [0x804865e:4]=0x6e6f7257 ; "Wrong!"
|    || :   0x0804855b      e890feffff     call sym.imp.puts           ; int puts(const char *s)
|    || `=< 0x08048560      eb97           jmp 0x80484f9
|    ||        ; JMP XREF from 0x08048552 (sym.main)
|    `----> 0x08048562      e879feffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|     `---> 0x08048567      c9             leave
\           0x08048568      c3             ret
[0x08048430]>

밑줄친 부분을 보면 strcmp를 call 하는데 비교 값이 g00dJ0B!이다.

flag : g00dJ0B!


crackme0x00b
이번 문제도 radare2를 이용해서 pdf @main을 했더니 바로 답이 나왔다.
알아보니 radare2의 최신 버전에서는 알아서 파싱 해주기 때문에 바로 풀린다고 한다.

이번 문제의 경우 문자열 비교 함수가 strcmp가 아닌 wcscmp로 wchar_t 형태의 문자열을 비교하게 된다. 이는 유니코드 문자열의 경우 주로 사용하며 null 이전까지의 문자열을 비교 한다.

flag : w0wgreat



crackme0x01

[0x08048330]> pdf @main
/ (fcn) main 113
|   main ();
|           ; var int local_4h @ ebp-0x4
|           ; var int local_4h_2 @ esp+0x4
|              ; DATA XREF from 0x08048347 (entry0)
|           0x080483e4      55             push ebp
|           0x080483e5      89e5           mov ebp, esp
|           0x080483e7      83ec18         sub esp, 0x18
|           0x080483ea      83e4f0         and esp, 0xfffffff0
|           0x080483ed      b800000000     mov eax, 0
|           0x080483f2      83c00f         add eax, 0xf
|           0x080483f5      83c00f         add eax, 0xf
|           0x080483f8      c1e804         shr eax, 4
|           0x080483fb      c1e004         shl eax, 4
|           0x080483fe      29c4           sub esp, eax
|           0x08048400      c70424288504.  mov dword [esp], str.IOLI_Crackme_Level_0x01 ; [0x8048528:4]=0x494c4f49 ; "IOLI Crackme Level 0x01\n"
|           0x08048407      e810ffffff     call sym.imp.printf         ; int printf(const char *format)
|           0x0804840c      c70424418504.  mov dword [esp], str.Password: ; [0x8048541:4]=0x73736150 ; "Password: "
|           0x08048413      e804ffffff     call sym.imp.printf         ; int printf(const char *format)
|           0x08048418      8d45fc         lea eax, [local_4h]
|           0x0804841b      89442404       mov dword [local_4h_2], eax
|           0x0804841f      c704244c8504.  mov dword [esp], 0x804854c  ; [0x804854c:4]=0x49006425
|           0x08048426      e8e1feffff     call sym.imp.scanf          ; int scanf(const char *format)
|           0x0804842b      817dfc9a1400.  cmp dword [local_4h], 0x149a ; [0x149a:4]=-1
|       ,=< 0x08048432      740e           je 0x8048442
|       |   0x08048434      c704244f8504.  mov dword [esp], str.Invalid_Password ; [0x804854f:4]=0x61766e49 ; "Invalid Password!\n"
|       |   0x0804843b      e8dcfeffff     call sym.imp.printf         ; int printf(const char *format)
|      ,==< 0x08048440      eb0c           jmp 0x804844e
|      |`-> 0x08048442      c70424628504.  mov dword [esp], str.Password_OK_: ; [0x8048562:4]=0x73736150 ; "Password OK :)\n"
|      |    0x08048449      e8cefeffff     call sym.imp.printf         ; int printf(const char *format)
|      |       ; JMP XREF from 0x08048440 (main)
|      `--> 0x0804844e      b800000000     mov eax, 0
|           0x08048453      c9             leave
\           0x08048454      c3             ret
[0x08048330]>

비교 값을 보녀 0x149a로 되어 있다. 0x149a는 5274로 5274를 답으로 넣어주면 된다.

풀이를 보면 0x149a를 얻는 과정에서 radare2에 포함된 rax2를 이용한다.
여러가지 형변환을 해주는데 알아두면 유용할 듯 하다.


crackme0x02
[0x08048330]> pdf @main
/ (fcn) main 144
|   main ();
|           ; var int local_ch @ ebp-0xc
|           ; var int local_8h @ ebp-0x8
|           ; var int local_4h @ ebp-0x4
|           ; var int local_4h_2 @ esp+0x4
|              ; DATA XREF from 0x08048347 (entry0)
|           0x080483e4      55             push ebp
|           0x080483e5      89e5           mov ebp, esp
|           0x080483e7      83ec18         sub esp, 0x18
|           0x080483ea      83e4f0         and esp, 0xfffffff0
|           0x080483ed      b800000000     mov eax, 0
|           0x080483f2      83c00f         add eax, 0xf
|           0x080483f5      83c00f         add eax, 0xf
|           0x080483f8      c1e804         shr eax, 4
|           0x080483fb      c1e004         shl eax, 4
|           0x080483fe      29c4           sub esp, eax
|           0x08048400      c70424488504.  mov dword [esp], str.IOLI_Crackme_Level_0x02 ; [0x8048548:4]=0x494c4f49 ; "IOLI Crackme Level 0x02\n"
|           0x08048407      e810ffffff     call sym.imp.printf         ; int printf(const char *format)
|           0x0804840c      c70424618504.  mov dword [esp], str.Password: ; [0x8048561:4]=0x73736150 ; "Password: "
|           0x08048413      e804ffffff     call sym.imp.printf         ; int printf(const char *format)
|           0x08048418      8d45fc         lea eax, [local_4h]
|           0x0804841b      89442404       mov dword [local_4h_2], eax
|           0x0804841f      c704246c8504.  mov dword [esp], 0x804856c  ; [0x804856c:4]=0x50006425
|           0x08048426      e8e1feffff     call sym.imp.scanf          ; int scanf(const char *format)
|           0x0804842b      c745f85a0000.  mov dword [local_8h], 0x5a  ; 'Z' ; 90
|           0x08048432      c745f4ec0100.  mov dword [local_ch], 0x1ec ; 492
|           0x08048439      8b55f4         mov edx, dword [local_ch]
|           0x0804843c      8d45f8         lea eax, [local_8h]
|           0x0804843f      0110           add dword [eax], edx
|           0x08048441      8b45f8         mov eax, dword [local_8h]
|           0x08048444      0faf45f8       imul eax, dword [local_8h]
|           0x08048448      8945f4         mov dword [local_ch], eax
|           0x0804844b      8b45fc         mov eax, dword [local_4h]
|           0x0804844e      3b45f4         cmp eax, dword [local_ch]
|       ,=< 0x08048451      750e           jne 0x8048461
|       |   0x08048453      c704246f8504.  mov dword [esp], str.Password_OK_: ; [0x804856f:4]=0x73736150 ; "Password OK :)\n"
|       |   0x0804845a      e8bdfeffff     call sym.imp.printf         ; int printf(const char *format)
|      ,==< 0x0804845f      eb0c           jmp 0x804846d
|      |`-> 0x08048461      c704247f8504.  mov dword [esp], str.Invalid_Password ; [0x804857f:4]=0x61766e49 ; "Invalid Password!\n"
|      |    0x08048468      e8affeffff     call sym.imp.printf         ; int printf(const char *format)
|      |       ; JMP XREF from 0x0804845f (main)
|      `--> 0x0804846d      b800000000     mov eax, 0
|           0x08048472      c9             leave
\           0x08048473      c3             ret
[0x08048330]>

이번 문제의 경우 고정된 값이긴 하나 연산이 필요하다
먼저 입력 값의 경우 local_4에 저장이 된다.
이후, esp에 0x50006425값을 쓰는데 이 값은 상수 값으로 %d가 된다.
그 다음, local_8에 고정값 0x5a, local_c에 고정값 0x1ec를 넣는다. 이후 연산을 보면 다음과 같다.
edx = 0x1ec
local_8 += edx (0x1ec) ; (0x5a + 0x1ec)
eax = local_8**2 ; (582*582)
= 338724

연산 결과인 338724를 입력 형태(%d)에 맞게 넣어주면 된다.

flag : 338724