用python的llvmlite库实现了一个brainfuck的解释器。通过runtime.so
的动态库中的ptrBoundChk做了内存边界检查,可读写的范围被限定在了[DATA+0x10, DATA+0X3010]的范围。所以解题的关键在于如何绕过边界检查。
先来看一下程序的几个关键函数:bfProgram
用于将brainfuck语言转换成shortended_code
的形式,就是一系列(state, imm)
的二元组。codegen
函数用于将上述的二元组转换成为llvm的IR,compile
将IR转换成为x86的机器码。execute
自然就是用于执行机器码。
这里的重点是在生成IR的过程中为了提高代码的执行效率引入了白名单机制,比赛过程中意识到了这里应该就是问题点,但是没有想到如何绕过边界检查,赛后看到别人的脚本才明白。在codegen函数里面有个递归处理的机制,如果处理的是单个代码块就直接根据二元组生成IR,如果涉及多个代码块就递归处理,这里把[]
包裹的语句视作一个代码块。
在处理子代码块的递归调用时候是这样的:
headb = self.head.codegen(module)
br1b = self.br1.codegen(module, (0, 0))
br2b = self.br2.codegen(module, (0, 0))
生成移位操作和增减值操作的IR代码:
for op, imm in self.shortened_code:
if op == 0:
continue
elif op == 1: # inc/dec ptr
if imm != 0:
ori = builder.ptrtoint(builder.load(dptr_ptr), i64)
incr = llvmIR.Const
Codegate CTF 2020 Preliminary
Challenge : SimpleMachine
Description :
(fixed-point challenge)
Classic Check Flag Challenge Machine
DOWNLOAD :
http://ctf.codegate.org/099ef54feeff0c4e7c2e4c7dfd7deb6e/116ea16dbeabe08d1fe8891a27d0f16b
point : 333 (80 team solved)
from pwn import *
stage1 = [0xb0bd, 0xbabc, 0xbeb9, 0xbaac, 0xcfce, 0xcfce]
stage2 = [0xf974, 0x2b9d, 0x4caf, 0xbee1, 0xfc0d, 0x6e48, 0xe03c, 0xd322, 0x1979, 0x36d6, 0x40e8, 0xcbf7]
val = 0xdead
flag = ''
for i in stage1:
flag += p16((0x10000 - i))
next = lambda x:x ^ ((x << 1) & 0xffff)
for i in stage2:
val = next(val)
flag += p16((0x10000 - i) ^ val)
# CODEGATE2020{ezpz_but_1t_1s_pr3t3xt}
print flag
Codegate CTF 2020 Preliminary
Challenge : Halffeed
Description :
nc 110.10.147.44 7777
DOWNLOAD :
http://ctf.codegate.org/099ef54feeff0c4e7c2e4c7dfd7deb6e/9a7f846af14e09f6b32cff3a648b80f5
point : 670 (43 team solved)
mixFeed 算法 Nonce 误用攻击
伪造AAAAAAAAAAAAAAAA;cat flag;AAAAAA
的密文和认证码:
'\x00' * 16
、'A' * 16 + '\x00' * 16
、'B' * 16 + '\x00' * 16
,取密文最后16字节。t2 , _ = feed_plus(T1, ';cat flag;AAAAAA')
"B" * 16 + xor(T1_[:8], t2[:8]) + t2[8:]
,取认证码。forge_ciphertext = xor('AAAAAAAAAAAAAAAA;cat flag;AAAAAA', T0 + T1)
ENIGMA
找规律,一个字符对应一个字母,最后flag是
CODEGATE2020{HACKERS ARE NOT BORN ONLY IT IS MADE}