-
-
看雪CTF.TSRC 2018 团队赛 第十一题 伊甸园 (非正经解法)
-
发表于: 2018-12-23 04:17 5285
-
做一半感觉这题质量有点低,不想做了,于是偷了个懒。
题目(又<sup>4</sup>)给出了一个 32 位控制台 Windows 程序,运行一下发现还是经典的输入一个 key 告诉你对不对的题目。
简单看一看会发现程序里面大量用到了 C++,MSVC 的 RTTI 信息暴露了一些类名出来,有 StrCheck、Base62、CTreeNode 等,另外字符串中有一些 pNode->Data().uOperatorIndex
pNode->Data().uTagIndex
之类的东西,抛异常的时候用到了,可以作为辅助分析使用。
程序的主要逻辑在 004033B0 这个函数中,看 vtable 和对应的 RTTI 信息可以识别被 inline 进来的一些构造函数。其大致逻辑是:
StrCheck 是最后解密成功提示的时候用的,暂时不用看。这个所谓的“Base62”,仔细看看会发现其实就是把值超过60的数用 "9A"、"9B"、"9C"、"9D" 来进行表示了,因此直接字符串替换一下就可以当成 base64 编码/解码:
观察最后比较的答案,大概是一个形如这样的东西:
结合 parse 的代码看,似乎就是一棵表达式树的先序遍历(以逗号分隔的),可以简单写几行 Python 代码对应着读进来备用。
树中有三种节点,对应 type 0 到 2,参考题目中的异常错误信息字符串可以确定分别是 Operator、Tag 和 Immediate。其中 Operator 有 +,-,*,/,Log,Power_ax,Power_xa,Sin,Cos
,Tag 有 x,e,pi
,Immediate 就是个立即数,程序中是用 double 存的,不过给的表达式中都是整数。另外给的表达式中没有 Sin、Cos。
相信敏感的读者看到 Power_ax、Power_xa 竟然有区分这么古怪的事情的时候心中应该已经对那个“变换”是什么有点数了,不过姑且描述一下变换的过程:
很明显是一个实现十分粗糙的对 x 的符号微分。
到这里检查的条件已经很明显了,就是把一个表达式中间抠掉了一部分,要求填充回去之后对其微分的结果等于给定的结果。由于给出的最终结果没有经过复杂的 simplify,所以我们当然是不用真的求积分的,稍微观察一下可以发现最终结果满足:
验证一下可以发现这确实是应用除法定则弄出来的一个结构,直接把其中的 f,g 抠出来,则 f / g 即为原函数。然而我们发现 f / g 的表示远没有 12715 字符这么长。仔细观察一下被扣掉一部分的输入,会发现里面有大量的 Log,x,x
和 *,1,XXX
会在求微分过程中被这个程序给化简掉。因此这样没法直接还原出原始输入。不过简单观察一下(写个程序画成树的形式或者脑补),可以发现这个表达式里面有大量重复的子结构,有点像是本身就是这个程序对某个比较简单的输入重复跑了几次之后的输出,对着观察一下基本能确定被扣掉的部分开头是 pi,75
。考虑到被抠掉的部分不长(计算一下可以知道解码后对应 59 个字符),不妨试试被抠的部分是不是在原来的输入串的其他部分也有出现过。
运行可以得到五个可能的答案:
都输入原来的程序试一下,对于最后一个,程序输出了:
看来赌中了,所以这就是答案了。
没仔细看那个求符号微分的代码,我猜可能结合里面的化简对于 *,Log,x,x,XXX
和直接的 XXX
求出来的结果还是不一样的,所以大概还是能正经解的吧。不过最后那个解密成功提示的部分就有点强行避免多解了,没仔细看,前面部分多解的解空间要是足够大的话说不定还是能构造出来多解来着,呵呵。
本题质量有点低,不过看了看出题团队的背景,好像也情有可原吧。
def b62tob64(data): return data.replace('9D', '=').replace('9C', '/').replace('9B', '+').replace('9A', '9') def b64tob62(data): return data.replace('9', '9A').replace('+', '9B').replace('/', '9C').replace('=', '9D')
/,-,*,-,-,/,-,*,/,/,/,-,*,*,*,Power_xa,-,Power_ax,58,x,x,33,-,*,Power_ax,58,x,Log,e,58,1,34,Log,/,Power_ax,100,*,*,*,Power_xa,-,Power_xa,*,Log,Power_ax,90,Log,/,
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课