ahh, 因为感觉一道题发一个帖子有点太占用大家空间了, 通过回复判断其实即使我打上CTF这个标签,来看的也不一定是真想看的, 所以以后wp都五道题一发了
这五道题略水, 但是都是99-100分的题
[FlareOn3]DudeLocker
Win32程序, 给了一个PE和一个应该是被加密了的doc
全是WinAPI, MSDN先备好
关注一下预处理, 16是Desktop, Filename是~\Desktop\Briefcase,如果打开失败就说你显然不是Re, 否则进else关闭文件句柄
到第42行获取卷序列号, 要求必须是0x7DAB1D35, 下面申请堆就不关注了, 直接关注1940
a3就是上面的十六进制, a1是一个明文表, 注意端序, 应该是0x35, 0x1D, 0xAB, 0x7D
直接解一下thosefilesreallytiedthefoldertogether
1080长这样, WinCrypt, 看上去1180比较重要因为和上面的字符串有关
把上面的SHA1掉
6610则是AES256, 用哈希值产生一个秘钥, 一层层返回到main的hKey里
关注1300
4030F4是\*, 后面接一起把filename下的所有文件都加密之应该是
8003都能背下来了, MD5
把传进来的第四个参数Hash之后SetKey, 具体Set的是一个IV,之后没再做别的了, 回main关注1500
a1是key, 这瞎猜都能猜到了吧..
就是以一个明文SHA1为秘钥生成根, 用CryptoAPI生成一个AES-256的秘钥, IV是文件名的MD5
因为本身用Python模仿CryptoAPI生成秘钥挺麻烦的, 分析通了就做到这儿了.
[SUCTF2019]babyunic
看名字就看得出来是Unicorn题, 有两个so和一个func, 猜测是OPCODE
把un.so给babyunic, babyunic负责主逻辑, 这是baby的main, 读入到v5之后扔CBA里, 最后和明文对比, 拿出来不亏
unsigned char ida_chars[] =
{
0xFF, 0xFF, 0xFF, 0x94, 0xFF, 0xFF, 0xFF, 0x38, 0x00, 0x00,
0x01, 0x26, 0xFF, 0xFF, 0xFF, 0x28, 0xFF, 0xFF, 0xFC, 0x10,
0x00, 0x00, 0x02, 0x94, 0xFF, 0xFF, 0xFC, 0x9E, 0x00, 0x00,
0x06, 0xEA, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x06,
0xFF, 0xFF, 0xFF, 0x0C, 0xFF, 0xFF, 0xFD, 0xF6, 0xFF, 0xFF,
0xFA, 0x82, 0xFF, 0xFF, 0xFC, 0xD0, 0x00, 0x00, 0x01, 0x82,
0x00, 0x00, 0x03, 0xDE, 0x00, 0x00, 0x01, 0x4E, 0x00, 0x00,
0x02, 0xB2, 0xFF, 0xFF, 0xF8, 0xD8, 0x00, 0x00, 0x01, 0x74,
0xFF, 0xFF, 0xFA, 0xA6, 0xFF, 0xFF, 0xF9, 0xD4, 0x00, 0x00,
0x01, 0xC2, 0xFF, 0xFF, 0xF9, 0x7C, 0x00, 0x00, 0x03, 0x5A,
0x00, 0x00, 0x01, 0x46, 0xFF, 0xFF, 0xFF, 0x3C, 0xFF, 0xFF,
0xFA, 0x14, 0x00, 0x00, 0x01, 0xCE, 0x00, 0x00, 0x07, 0xDC,
0xFF, 0xFF, 0xFD, 0x48, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
0x08, 0x5E, 0xFF, 0xFF, 0xFD, 0xB0, 0xFF, 0xFF, 0xFF, 0xBC,
0x00, 0x00, 0x03, 0x6E, 0xFF, 0xFF, 0xFF, 0x4E, 0xFF, 0xFF,
0xF8, 0x36, 0x00, 0x00, 0x05, 0xC0, 0x00, 0x00, 0x06, 0xAE,
0x00, 0x00, 0x06, 0x94, 0x00, 0x00, 0x00, 0x22
};
这儿看起来得学一波uc
UNICORN_EXPORT
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc);
第一个是架构, 第二个是模式
typedef enum uc_arch {
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
UC_ARCH_ARM64, // ARM-64, also called AArch64
UC_ARCH_MIPS, // Mips architecture
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
UC_ARCH_SPARC, // Sparc architecture
UC_ARCH_M68K, // M68K architecture
UC_ARCH_MAX,
} uc_arch;
typedef enum uc_mode {
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
// arm / arm64
UC_MODE_ARM = 0, // ARM mode
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
// mips
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
// x86 / x64
UC_MODE_16 = 1 << 1, // 16-bit mode
UC_MODE_32 = 1 << 2, // 32-bit mode
UC_MODE_64 = 1 << 3, // 64-bit mode
// ppc
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
// sparc
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
// m68k
} uc_mode;
MIPS+MIPS32+BIGENDIAN
基本能看出来吧, 通过a1算a2, a2一共41个, 41*4应该是正好和对比数据一样大, 这样我们z3跑一下就行了, IDA真乃神器也
代码太长了就不贴了, 除了s.add以外基本上啥也没有, 就是传统z3题, 哦, 记得那些0xFFFFF打头的一看就是补码, 要转一下
{Un1c0rn_Engin3Is@_P0wer7ul_TO0ls!}
[FlareOn2]gdssagh
我直接? 我还以为是加壳, 但是这怎么直接.. 退出了? 我疑惑了一下并进行动调发现仍然是直接退出.
中间巨大的数据里面都是可见字符, 是Base64..
413H-CC1A4H, python提一下
>>> with open('./gdssagh', "rb") as f:
... b = f.read()[0x413:0xCC1A5]
... import base64
... b = base64.b64decode(b)
... ff = open("./out", "wb")
... ff.write(b)
... ff.close()
<img src="E:\ctf\wp[FlareOn2]gdssagh.assets\image-20220401111016042.png" alt="image-20220401111016042" style="zoom:150%;" />
err, 竟然是个PNG, 这他妈的不会是个隐写把.. 直接zsteg一把梭试试
这俩比较像, 但是正常人肯定都看看PE..
就它了, 导出
这他妈是Misc, 不是逆向, 狗看了都摇头
[SCTF2019]music
逛一圈关注到了这个yes和no
这个g(a)要是1
和Resource里的资源相等, 回去看看a哪里来的
000就是input
b定位到了这儿
c.a有两个参数, 一个是输入的字符串, 另一个是经过this.a变换的this.d, this.d来自于上面这个get, 是一个db
把get经过md5之后传进来, c.a的两个参数来源都有了, 回头看看c.a怎么加密
看上去像个RC4, 应该是魔改过的. 整个流程已经很清楚了: 用md5(db.iwantofind)做秘钥, 输入做明文, 加密之后hex, 然后和resource里的明文做对比
out[i] = (char)((flagenc[i] ^ S[(S[k] + S[k] % 256) % 256]) + k);
注意rc4的最后一轮是改过的
flag{IT_IS_A_NICE_SONG}
[watevrCTF 2019]sabataD
64位ELF. 丢IDA
有个0xE的signal, 去看看是哪个
后面跟着一个0x14秒Alarm, handler是退出, 我们整个过程不能超过20秒, 扬了
去看B7A
首先是这个位置, 把读入按模3剩余类操作, 先扔AEA里, 0放s1, 1放s2, 2放pattern, 151-154这四位转int放v7
要满足这两个,
s1要满足这个, 看看glob, err大概是个处理文件名的函数, 可以猜测就是打开homectf下的flag, 读v7次到v15里, 然后print出来, 进入下一个循环, 直到s1是"terminate"
AEA这样的, 字母就丢B3E里, 是个ROT13
s1 = "Fetch from file with index"
s2 = "watevr-admin"
s3 = "/home/ctf/flag.*"
inp = ""
def ROT13(ch) :
num = ord(ch)
if num >= 0x61 and num <= 0x7a :
num -= 0x61
num += 13
num %= 26
num += 0x61
elif num >= 0x41 and num <= 0x5a :
num -= 0x41
num += 13
num %= 26
num += 0x41
return chr(num)
for i in range(len(s1)) :
inp += ROT13(s1[i])
if i >= len(s2) :
inp += '_'
else :
inp += ROT13(s2[i])
if i >= len(s3) :
inp += '_'
else :
inp += ROT13(s3[i])
inp += (150-len(inp)) * "_" + "1234"
print(len(inp), inp.encode(encoding="utf-8"))
随便构造了一个, 跑通倒是通了, 但是我们想访问的是flag, 他不让, 给我的感觉就是我们要找一个方法绕过strcmp然后通过glob来访问flag.txt
支持匹配啊, 那试试
flag{f3b5b172-a26b-464d-b7ee-7599d75a111c} 木有什么难度~