문제는 간단하다. 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
'CTF | wargame' 카테고리의 다른 글
DFChallenge 2021 / 301 - What is the secret information (0) | 2021.05.23 |
---|---|
hdcon 2016 / runme (mips 프로그램 실행) (0) | 2018.02.27 |
labyrenth 2017 / Mobile 2 - routerlocker (mips 리버싱, gdb set follow-fork-mode child) (0) | 2018.02.27 |
labyrenth 2017 / Mobile 1 - Ezdroid(안드로이드 코드 리버싱, 자바 연산상 오류 ) (0) | 2018.02.27 |
radare2 / sym 파싱 오류, sym to str (0) | 2018.02.26 |