[CTF从0到1]BeginCTF2024 Reverse 部分题解

发布于 2024-02-20  182 次阅读


过完年咕咕咕了十来天,现在简单总结一下年前的BeginCTF的逆向部分题解。面向WP学习CTF

红白机

附件是一个txt文本文件,里面是类似汇编的东西,没见过。后来才知道压缩包名字“6502”指的就是6502CPU汇编。

嗯看代码然后翻译成人话即可。

对照着指令集翻译。

6502指令集

或者直接把汇编跑一遍:在线编译

xor

题目很明显是异或相关。查壳发现是upx,还是最新版的,

脱掉后拖进ida,竟然没找到主函数。

点进start函数,跟进几次,进入这么一个函数:

代码倒是挺复杂,不过直接看最后返回值是Code,而代码中Code = sub_1400130F0(),那就继续跟进。然后进入了这个函数:

这个函数很有意思。乍一看挺复杂,但是有很多Sleep函数,最后还有gets函数,看着像程序的初始化和输入字符界面,然后调用了sub_14001120D函数。双击跟进后发现有很多函数,随便进去几个发现都是长这样的:

和题目的“xor”对上了。回到sub_14001120D函数,直接从返回值的函数进行回溯,最终进入了这个函数:

显而易见是拿v5数组和byte_14001D7C0数组逐位对比。结合前面的好几个异或函数,只要把v5逆回去就能得到flag。

总结一下异或逻辑(太绕了):

算法先将前32个输入字符拆分成相同长度的两段,输入1和输入2,再将长度为32的密钥同样拆分为两段,密钥1和密钥2

第一轮中会将:
输入1和密钥2异或
输入2和密钥1异或
输入1和密钥1异或
输入2和密钥2异或
输入1和逆序密钥2异或
输入2和逆序密钥1异或
输入1和逆序密钥1异或
输入2和逆序密钥2异或

第二轮加密同理,只是将之前的密钥换成了其他密钥。

两次密钥在这:

在两轮加密结束后,将输入2和输入1合并,变成密文。

脚本如下:

key = [52, 49, 56, 48, 51, 56, 55, 51, 54, 50,
       53, 57, 48, 49, 51, 54, 51, 48, 57, 50,
       54, 48, 54, 54, 51, 50, 55, 56, 55, 57,
       52, 55]
key1 = [54, 51, 50, 57, 48, 55, 57, 52, 50, 48,
        55, 55, 49, 53, 53, 56, 55, 54, 55, 57,
        54, 50, 49, 51, 56, 54, 55, 51, 53, 48,
        48, 48]
hbkey = key[0:16] + [0]
qmkey = key[16:32] + [0]
enc = [ord(i) for i in "`agh{^bvuwTooahlYocPtmyiijj|ek'p"]
qm = enc[0:16]
hb = enc[16:32]
for i in range(16):
    qm[i] ^= qmkey[16 - i]
    qm[i] ^= hbkey[16 - i]
    hb[i] ^= hbkey[16 - i]
    hb[i] ^= qmkey[16 - i]
for i in range(16):
    qm[i] ^= qmkey[i]
    qm[i] ^= hbkey[i]
    hb[i] ^= hbkey[i]
    hb[i] ^= qmkey[i]
hbkey = key1[0:16] + [0]
qmkey = key1[16:32] + [0]
for i in range(16):
    qm[i] ^= qmkey[16 - i]
    qm[i] ^= hbkey[16 - i]
    hb[i] ^= hbkey[16 - i]
    hb[i] ^= qmkey[16 - i]
for i in range(16):
    qm[i] ^= qmkey[i]
    qm[i] ^= hbkey[i]
    hb[i] ^= hbkey[i]
    hb[i] ^= qmkey[i]
flag = "".join([chr(i) for i in qm + hb])
print(flag)

俄语学习

这道题方法很多,偷懒写个最简单的:

拖进IDA直接F5看主函数代码,前面基本都是俄语题目相关的还带答案,直接拉到最后,果然把题目答完还得填进去flag,题目没啥用。

先看if条件里的函数,跟进几次找到了疑似密文的东西:

继续跟进,找到了RC4:

回到主函数里。if条件的上一行的函数,跟进发现这里也用到了RC4,不过和上面提到过的用的密钥似乎不一样。

动态调试一下发现两处用到的密钥其实一样,那这个RC4其实没啥用???

直接密文去混淆就行了,

bbq1 = [53,109,53,100,53,119,53,100,53,98,53,110,53,109,53,100,
        53,119,53,100,53,98,53,110,53,109,53,100,53,119,53,100,53,98,53,110,142]  

bbq2 = [43,105,38,91,64,89,58,103,56,91,38,108,36,102,56,83,56,118,36,89,38,101,62,123] 

input_str = ""
for i in range(len(bbq2)):
    if i >= len(bbq1):
        break
    input_char = chr(bbq2[i] - bbq1[i] + 112)
    input_str += input_char
print("Recovered input:", input_str)

ezpython

直接pyinstxtractor和uncompyle6连环拳反编译出python源码,发现是个SM4加密,

再反编译import那引用的pyc文件,但是我在文件夹里没找到??????

最后发现是python版本错了。原程序是python3.8编译的,那就必须用对应版本进行解包,不然解不出附属的库来。

反编译secret.pyc,得到key和enc,

尝试在线工具直接解SM4,但是失败了。

看到上面还引用了gmssl,猜测SM4被魔改了,直接把gmssl文件夹里的sm4.pyc反编译,发现对key进行了异或,对象是37,

那就搞到原始key然后直接解码,

CyberChef这个网站确实好用。

出题人的密码是什么

这道没学会,先欠着

arc


这附件好像是某个音游?没玩过。不过图标好像大小姐啊

按套路把py源码文件搞出来,结果发现被混淆了,

一看就犯恶心,先跑一下代码看看,

随便输入begin{

输出True。大吃一惊,flag是不是可以爆破出来?

直接gpt写exp,这里贴爆破最后一位的代码:

官方WP暂时没看明白,等以后搞懂了再复盘。

Superguesser

题目提示的很明确,这道题考察的是动调,

拖进IDA里静态分析啥也没看出来。字符串里有点线索:

给字符串下硬件断点,然后在start函数下断点,单步步入,看到了好像是密文一样的东西:

其实这里按F5就能看伪代码,

后面的加密逻辑应该是密文逐位异或。v0-25的值其实是0x33。

尝试一下爆破:

稀里糊涂地做出来了。官方WP有空再研究。

not main

看了WP发现是VEH异常处理,之前没见过这种题,超纲了属于是。学会了再来看。

ezvm babyvm

这更是超纲。vm逆向等两天再说。

goforfun

懒了。

stick game

js逆向,还有ob混淆。

打开js文件,找到被混淆的部分,

直接在线解之,

直接看见flag了23333。

real checkin xor

伟大的签到题。

异或的密文和key都给出来了,直接异或回去。

最后更新于 2024-02-20