首页
社区
课程
招聘
7
[原创]2018CTF团队赛 第十一题 伊甸园
发表于: 2018-12-23 00:27 6577

[原创]2018CTF团队赛 第十一题 伊甸园

2018-12-23 00:27
6577

用 IDA 分析程序,流程如下
全局类初始化表部分:

主函数部分:

长度分析:

[^1x]: Base62:网上没有标准,是一种为了 URL 而存在的 Base64 改进型,替换了 URL 敏感的 '+' '/' 符号,本实现具体为 '+'->'9B' '/'->'9C' '='->'9D' '9'->'9A'

先上解析代码

从流程上看,好像关键就是求这个 微分 的逆转了,好像对 F 求积不就拿到 f 了吗?

其实这是作者故意给出的陷阱,不过同时,作者也给出了糖果:

从上一章看,好像提取出 u v 就能直接得出 f 了,其实不行,具体就是从原始的 dec2 中搜不到 v

那么,定义上章获得的为 u_ v_

从 dec0(以原 u 开头) 和 u_ 对比来看,发现 dec0 到 u_ 进行了一种化简(还好 dec0 短,全手动),具体如下:

将得到的 dec0_ 与 u_ 对比,得到 code 的开头处,为 ',pi,' 与之前的推理一致

将 dec2 替换 *,Log,x,x,,分析 dec2 与 code 开头处部分(关键字 38,故意调整了对齐)
对比

得到要补充的部分,刚好 60 字节
code = ",pi,75,Log,*,-,Power_ax,23,-,Power_xa,+,Log,Power_ax,90,Log,"

使用代码求得 ipt
print b62enc(b62dec(enc0[:-2]) + code + b62dec(enc1_2[1:]))[1000: 1080]

 
 
 
 
 
 
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
with open("yidian.exe", "rb") as f:
    f.seek(0x3cc18)
    func = f.read(10000)
    f.seek(0x3f330)
    func += f.read(10000)
    f.seek(0x41A60)
    func += f.read(10000)
    f.seek(0x44188)
    func += f.read(10000)
    f.seek(0x468a8)
    func += f.read(10000)
    f.seek(0x48fc8)
    func += f.read(10000)
    f.seek(0x4b6e0)
    func += f.read(4875)
 
    f.seek(0x4c9f0)
    enc0 = f.read(1000)
    f.seek(0x4cdf8)
    enc1_2 = f.read(8000) # 组合 enc1 + enc2
    f.seek(0x4ed40)
    enc1_2 += f.read(8335)
 
class Node:
    def __init__(self, s):
        self.left = self.right = None
        self.val = s
        if s in ["+", "-", "*", "/", "Power_xa", "Power_ax", "Log", "Sin", "Cos"]:
            # 运算符
            self.type = 1
        elif s in ["x", "e", "pi"]:
            # 未知数和常数
            self.type = 2
        else:
            # 立即数
            self.type = 0
 
    # 运算符求目
    def opernum(self):
        if self.type != 1:
            raise Exception("not oper")
        if self.val in ["Sin", "Cos"]:
            return 1
        return 2
 
    # 转前缀表达式
    # 最后的结果要去除最尾逗号
    def __str__(self):
        if self.type == 1:
            if self.opernum() > 1:
                s = "{},{}{}".format(self.val, self.left, self.right)
            else:
                s = "{},{}".format(self.val, self.left)
        else:
            s = self.val + ","
        return s
 
    # 转中间表达式
    def mid(self, n, m):
        # 深度限制
        if n == m:
            return "j"
 
        if self.type == 1:
            if self.val in ["+", "-", "*", "/"]:
                s = "{} {} {}".format(self.left.mid(n+1, m), self.val, self.right.mid(n+1, m))
            elif self.val in ["Power_xa", "Power_ax"]:
                s = "{} ^ {}".format(self.left.mid(n+1, m), self.right.mid(n+1, m))
            elif self.val == "Log":
                s = "log({}, {})".format(self.left.mid(n+1, m), self.right.mid(n+1, m))
            else:
                s = "{}{}".format(self.val.lower(), self.left.mid(n+1, m))
        else:
            s = self.val
 
        return "(" + s +")"
 
pfunc = func
 
def parseinit(s):
    global pfunc
    pfunc = s
 
def parse(parent):
    global pfunc
    if pfunc is None:
        return
 
    idx = pfunc.find(",")
    if idx != -1:
        x = pfunc[:idx]
        pfunc = pfunc[idx + 1:]
    else:
        x = pfunc
        pfunc = None
 
    n = Node(x)
    if n.type == 1:
        # 若是运算符则递归解析
        parse(n)
 
    if parent is not None:
        if parent.left is not None:
            if parent.right is not None:
                raise Exception("must die")
            else:
                parent.right = n
        else:
            parent.left = n
            if parent.type == 1 and parent.opernum() > 1:
                # 双目则继续右边
                parse(parent)
 
    return n
 
import base64
 
def b62dec(b):
    b = b.replace("9D", "=").replace("9C", "/").replace("9B", "+").replace("9A", "9")
    return base64.b64decode(b)
 
def b62enc(b):
    b = base64.b64encode(b)
    return b.replace("9", "9A").replace("+", "9B").replace("/", "9C").replace("=", "9D")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def check_uv():
    tree = parse(None)
 
    # 先输出至多 3 级表达式
    print tree.mid(0, 3)
    # 输出
    # (((j * j) - (j * j)) / ((j * j) ^ (2)))
    # 满足求导公式
 
    # 进一步验证满足条件,分子中的 v 与分母中的 v 相等
    assert str(tree.left.left.right) == str(tree.right.left)
 
    u = tree.left.right.left
    v = tree.right.left
    # 输出 u v
    print str(u)[:-1]
    print str(v)[:-1]
  1. 以 10000 字节为分割初始化了7段表达式,最后汇成最终表达式 F
  2. 初始化三段字符串 enc0(1000) enc1(8000) enc2(8335)
  1. 读入输入 ipt,合成 enc = enc0 + ipt + enc1 + enc2,校验长度 17415
  2. 用 Base62[^1x] 解码,得到表达式 f,校验长度 12715
  3. 解析 f,得到由 CTreeNode 组成的 tree(PS:后文有类似解析代码)
  4. 执行了某种运算,再准备硬啃时,经过队友 新手慢慢来 提点,推断出应该是 微分(求导)、化简 过程
    聊天记录
  5. 将微分结果输出成前缀表达式 f_,与 F 对比
  6. 用 StrCheck 校验 enc(PS:不影响解题,可能是为了确保唯一解加的)
  1. enc0 + enc1 + enc2 长度 17335,所以 ipt 长度 17415 - 17335 = 80
  2. enc0 直接解 b62 会报 pad 错误,多余 2 字节,令 dec0 = b62dec(enc0[:-2]),长度 726
  3. 根据多余的 2 字节分析,接下来应该是 ',x,' 或 ',pi,'
  4. enc1_2 多余第一字节,令 dec2 = b62dec(enc1_2[1:]),长度 11929
  5. 根据多余的 1 字节分析,前面是 ',',从内容看也是
  6. 所以剩下 12715 - 726 - 11929 = 60,令这一部分为 code,其以 ',x,' 或 ',pi,' 开头,以 ',' 结尾
  1. 仔细分析表达式 f 以及 F,发现第一字节(最外层运算符)均为 ‘/’(除法)
  2. f = u / v
  3. 结合除法的求导公式
  4. 你会发现其实 f_(也就是 F)中,是包含原 f 组成部分 u v
  5. 使用代码验证设想并输出原始 u v

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2018-12-23 00:31 被kkHAIKE编辑 ,原因:
收藏
免费 7
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2022-7-27 01:51
心游尘世外
为你点赞~
2022-7-26 23:47
飘零丶
为你点赞~
2022-7-17 03:23
会飞的鱼油
为你点赞~
2019-3-25 13:21
新手慢慢来
为你点赞~
2019-3-25 13:15
Editor
为你点赞~
2018-12-24 15:42
深天深天
为你点赞~
2018-12-24 11:18
最新回复 (3)
雪    币: 1470
活跃值: (74)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
2
厉害,这个队有配合
2018-12-23 14:15
0
雪    币: 10846
活跃值: (1054)
能力值: (RANK:190 )
在线值:
发帖
回帖
粉丝
3
有团,才是队!
2018-12-23 21:53
0
雪    币: 73
活跃值: (923)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不懂数学,CTF都参加不了了
2018-12-26 17:03
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册