吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1637|回复: 4
收起左侧

[CTF] ByteCTF Re WP

[复制链接]
rea1 发表于 2024-9-22 13:24
babyapk
首先分析了下java层的东西,然后发现和平常做的安卓不太一样,搜索后发现这是使用Flutter框架写的安卓apk,所以从网上找了下资料后发现可以使用blutter工具,具体的使用在此不再详说,网上有很多详细资料,在使用该工具初步解析apk后获得如下文件。
image.png

image.png
其中的main.dart可以说已经看清了该apk的主要逻辑。
image.png
该test函数可以轻易看到和验证有关的大量逻辑。
在下面发现最主要的是调用了 m3N4B5V6()函数进行判断。
image.png
右边的注释则说明了该函数所属的package。
进而找到simple.dart
image.png

接着跟进。
image.png
在这里我一度思路中断,因为我对Rust以及FFI调用的实现并不了解。
但是我注意到其中大量出现的API和Simple字样,于是在IDA中进行搜索发现该字符。
image.png
向上查看交叉引用发现了加密函数,
image.png
同时从加密函数那里继续向上查看引用多次最终索引到了这里。
image.png
这里是我之前搜索过m3n4b5v6分析过的函数,但是由于其中内部逻辑很多很乱,我实在没有分析下去,才转战dart文件去分析。除去前面这些过程实际上我还对native层的这些函数包括app.so内的一些和交互有关以及可疑的函数进行了多次fridaHOOK,但也成效甚微,不过还好总算找到加密逻辑处了。
然后这里也是因为之前HOOK时发现很多函数没反应于是猜测有长度检测,不断改变长度查看HOOK情况得到长度为0x2d,{}内为36位。
image.png
分析加密函数,倒着分析,得到该部分大致逻辑,判断为纯纯的z3.
image.png
用z3约束后发现约束出的数组都是可显字符,即32e750c8fb214562af22973fb5176b9c,猜测离flag很接近了。
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
from z3 import *
 
# 声明 v58 数组,每个变量为 16 位
for  j in range(4):
    v58 = [BitVec(f'v58[{i}]', 32) for i in range(8)]  # 假设有8个变量
 
    # 密文数组
    cmp = [
        0x0001EE59, 0x0000022A, 0x00001415, 0x00040714, 0x000013E0, 0x000008B8, 0xFFFDCEA0, 0x0000313B,
        0x0003D798, 0xFFFFFE6B, 0x00000C4E, 0x00023884, 0x0000008D, 0x00001DB4, 0xFFFC1328, 0x00001EAC,
        0x00043C64, 0x0000142B, 0xFFFFF622, 0x00023941, 0xFFFFEF6D, 0x0000120C, 0xFFFBD30F, 0x00001EBE,
        0x00045158, 0xFFFFEF66, 0x00001D3F, 0x0004C46B, 0xFFFFF97A, 0x00001BFD, 0xFFFBA235, 0x00001ED2
    ]
 
    # 创建求解器
    s = Solver()
 
    # 添加变量的范围限制 (0 <= num <= 65535)
    for i in range(8):
        s.add(v58[i] >= 0, v58[i] <= 0x10FFFF)
 
    # 添加约束条件
    num2 = v58[2]
    num3 = v58[3]
    num0 = v58[0]
    num1 = v58[1]
    num4 = v58[4]
    num5 = v58[5]
    num6 = v58[6]
    num7 = v58[7]
 
    # 计算公式的约束条件
    s.add(num7 + num1 * num3 * num5 - (num0 + num6 + num2 * num4) == cmp[0+j*8])
    s.add(num3 - num4 - num0 * num5 + num7 * num1 + num2 + num6 == cmp[1+j*8])
    s.add(num0 * num5 - (num4 + num7 * num1) + num2 + num6 * num3 == cmp[2+j*8])
    s.add(num1 + num4 * num0 - (num7 + num2) + num6 * num5 * num3 == cmp[3+j*8])
    s.add(num5 * num3 + num1 + num2 * num4 - (num6 + num7 * num0) == cmp[4+j*8])
    s.add(num0 * num5 + num1 * num3 + num2 - (num6 + num4 * num7) == cmp[5+j*8])
    s.add(num7 - num1 + num2 * num5 + num6 - num0 * num4 * num3 == cmp[6+j*8])
 
    # 最后一轮的约束
    s.add(num3 - num7 - (num1 + num5) + num4 * num0 + num6 * num2 == cmp[7+j*8])
 
    # 求解
 if s.check() == sat:
        model = s.model()
        v58_values = [model[v58[i]].as_long() for i in range(8)]
        print("数组解是:", v58_values)
    else:
        print("没有解。")

image.png
这种逻辑的似乎涉及到编码转化,不影响flag的值。
这里发现了对-的约束,于是再根据很可显的字符串的长度为32,立马想到有四个-插在中间。
image.png
思考后感觉z3不好写而且情况也不多,于是直接写了穷举的爆破脚本。
[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
from itertools import combinations
 
# 原始字符串
original_string = "32e750c8fb214562af22973fb5176b9c"
 
# 定义用于验证的 byte 数组(byte_18E46)
byte_18E46 = [ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
    0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
# 验证逻辑函数
def validate_hyphen_positions(input_str):
    byte = byte_18E46
    input_bytes = [ord(c) for c in input_str]
    
    # 模拟你提供的验证逻辑
    v2 = byte[input_bytes[0]]
    if v2 == 36:
        return False
    v3 = byte[input_bytes[v2]] + v2
    if v3 == 36:
        return False
    v4 = v3 + byte[input_bytes[v3]]
    if v4 == 36:
        return False
    v5 = v4 + byte[input_bytes[v4]]
    if v5 == 36:
        return False
    v6 = v5 + byte[input_bytes[v5]]
    if v6 == 36:
        return False
    v7 = v6 + byte[input_bytes[v6]]
    if v7 == 36:
        return False
    v8 = v7 + byte[input_bytes[v7]]
    if v8 == 36:
        return False
    v9 = v8 + byte[input_bytes[v8]]
    if v9 == 36:
        return False
    v10 = input_bytes[v9]
    if v10 != ord('-'):
        return False
    v12 = v9 + byte[input_bytes[v9]]
    if v12 == 36:
        return False
    v13 = v12 + byte[input_bytes[v12]]
    if v13 == 36:
        return False
    v14 = v13 + byte[input_bytes[v13]]
    if v14 == 36:
        return False
    v15 = v14 + byte[input_bytes[v14]]
    if v15 == 36:
        return False
    v16 = v15 + byte[input_bytes[v15]]
    if v16 == 36:
        return False
    v18 = input_bytes[v16]
    if v18 != ord('-'):
        return False
    v20 = v16 + byte[input_bytes[v16]]
    if v20 == 36:
        return False
    v21 = v20 + byte[input_bytes[v20]]
    if v21 == 36:
        return False
    v22 = v21 + byte[input_bytes[v21]]
    if v22 == 36:
        return False
    v23 = v22 + byte[input_bytes[v22]]
    if v23 == 36:
        return False
    v24 = v23 + byte[input_bytes[v23]]
    if v24 == 36:
        return False
    v25 = input_bytes[v24]
    if v25 != ord('-'):
        return False
    v27 = v24 + byte[input_bytes[v24]]
    if v27 == 36:
        return False
    v28 = v27 + byte[input_bytes[v27]]
    if v28 == 36:
        return False
    v29 = v28 + byte[input_bytes[v28]]
    if v29 == 36:
        return False
    v30 = v29 + byte[input_bytes[v29]]
    if v30 == 36:
        return False
    v31 = v30 + byte[input_bytes[v30]]
    if v31 == 36:
        return False
    v32 = input_bytes[v31]
    if v32 != ord('-'):
        return False
    
    return True
 
 
# 生成插入 '-' 的位置的组合
positions = list(combinations(range(len(original_string) + 1), 4))  # 选择 4 个插入位置
 
# 计数器
count = 0
valid_count = 0  # 成功验证的组合计数器
 
# 遍历所有组合
for pos in positions:
    temp_str = original_string
    # 插入时要注意位置的偏移,每次插入后,字符串长度增加
    for i, p in enumerate(pos):
        temp_str = temp_str[:p + i] + '-' + temp_str[p + i:]  # 插入 '-' 并调整位置索引
     
    # 验证插入的 '-' 是否符合条件
    if validate_hyphen_positions(temp_str):
        print(f"Valid combination: {temp_str}")
        valid_count += 1  # 计数通过验证的组合
     
    # 计数
    count += 1
 
# 打印总次数
print(f"Total combinations: {count}")
print(f"Total valid combinations: {valid_count}")

最终Flag:ByteCTF{32e750c8-fb21-4562-af22-973fb5176b9c}

ByteBuffer
根据题目提示了解了下flatbuffer,大致明白就是把数据以某种形式转化为一维的数组这样子。
然后用010打开。
发现有很多的Edge,Dot字样
image.png
所以大致能猜到这些线和点能画出来Flag。
于是将dot和Edge的一份数据分别提取一份喂给Gpt,然后它成功猜测到可能的数据结构:
image.png
一开始Edge的分析成了两个坐标,后来才发现它的分析的起始坐标很有规律,于是猜到了是代表的下面的点的序号及之间的连接。
遂训练AI写出脚本解出。
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
import matplotlib.pyplot as plt
 
# 点的坐标数据
dot_coordinates = [
    (75, 75),(25, 75),(75, 25),(25, 25),(25, 125),(75, 125),(100, 75),(100, 25),(150, 25),(150, 75),
    (100, 125),(150, 125),(175, 75),(175, 25),(225, 25),(225, 75),(225, 125),(250, 75),(250, 25),(300, 25),
    (300, 75),(250, 125),(300, 125),(325, 75),(325, 25),(375, 75),(375, 25),(375, 125),(400, 75),(400, 25),
    (450, 25),(450, 75),(400, 125),(450, 125),(475, 75),(475, 25),(475, 125),(525, 75),(550, 75),(550, 25),
    (600, 25),(600, 75),(550, 125),(600, 125),(625, 75),(625, 25),(675, 25),(675, 75),(625, 125),(675, 125),
    (700, 75),(700, 25),(750, 25),(750, 75),(750, 125),(700, 125),(775, 75),(775, 25),(825, 25),(825, 75),
    (775, 125),(825, 125),(850, 75),(850, 25),(900, 25),(900, 75),(850, 125),(900, 125),(925, 75),(925, 25),
    (975, 25),(975, 75),(925, 125),(975, 125),(1000, 75),(1000, 25),(1050, 25),(1050, 75),(1000, 125),(1050, 125),
    (1075, 75),(1075, 25),(1125, 25),(1125, 75),(1125, 125),(1075, 125),(1150, 75),(1150, 25),(1200, 25),(1200, 75),
    (1200, 125),(1225, 75),(1225, 25),(1225, 125),(1275, 75),(1300, 75),(1300, 25),(1350, 25),(1350, 75),(1300, 125),
    (1350, 125),(1375, 75),(1375, 25),(1425, 25),(1425, 75),(1375, 125),(1425, 125),(1450, 75),(1450, 25),(1500, 25),
    (1500, 75),(1450, 125),(1500, 125),(1525, 75),(1525, 25),(1575, 25),(1575, 75),(1525, 125),(1575, 125),(1600, 75)
]
 
# 边的连接关系 (基于点的序号,序号从0开始)
edges = [
    (119, 117), (119, 118), (117, 114), (116, 115), (115, 114),
    (113, 111), (113, 112), (112, 108), (111, 108), (110, 109),
    (109, 108), (107, 105), (107, 106), (106, 102), (105, 102),
    (105, 104), (104, 103), (103, 102), (101, 99), (101, 100),
    (99, 96), (98, 97), (97, 96), (94, 92), (93, 92), (91, 90),
    (90, 89), (89, 88), (86, 81), (86, 85), (85, 84), (84, 83),
    (83, 82), (82, 81), (80, 78), (80, 79), (78, 75), (78, 77),
    (77, 76), (76, 75), (74, 73), (73, 69), (72, 69), (72, 71),
    (71, 70), (68, 66), (68, 67), (66, 63), (66, 65), (65, 64),
    (64, 63), (62, 60), (62, 61), (61, 57), (60, 57), (59, 58),
    (58, 57), (56, 51), (56, 55), (55, 54), (54, 53), (53, 52),
    (52, 51), (50, 48), (50, 49), (48, 45), (47, 46), (46, 45),
    (44, 42), (44, 43), (43, 39), (42, 39), (42, 41), (41, 40),
    (40, 39), (37, 35), (36, 35), (34, 33), (33, 29), (32, 29),
    (32, 31), (31, 30), (28, 26), (27, 26), (26, 24), (25, 24),
    (23, 21), (23, 22), (21, 18), (20, 19), (19, 18), (17, 16),
    (16, 15), (15, 14), (12, 11), (11, 7), (10, 7), (10, 9),
    (9, 8), (6, 1), (6, 5), (4, 3), (3, 1), (2, 1)
]
 
# 创建图形
plt.figure(figsize=(12, 12))
 
# 绘制点
for i, (x, y) in enumerate(dot_coordinates):
    plt.scatter(x, y, c='blue', zorder=2)
    plt.text(x, y, f"{i+1}", fontsize=8, ha='right', zorder=3)
 
# 绘制连接关系
for start, end in edges:
    x_values = [dot_coordinates[start-1][0], dot_coordinates[end-1][0]]
    y_values = [dot_coordinates[start-1][1], dot_coordinates[end-1][1]]
    plt.plot(x_values, y_values, 'k-', zorder=1)
 
# 优化显示
plt.title("Optimized Dot and Edge Connections")
plt.xlabel("X Coordinate")
plt.ylabel("Y Coordinate")
plt.grid(True)
plt.axis('equal'# 保持比例相同
plt.show()

image.png
发现图还有点问题,第三个一看就很有特点,是7,于是镜像翻转
image.png
flag:ByteCTF{327542185069230715865}
image.png

免费评分

参与人数 1威望 +1 吾爱币 +20 热心值 +1 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Doorsman 发表于 2024-9-26 23:27
楼主,你ByteBuffer那题主要是对010editor的分析对吗,我看了很多flatbuffer也不是很懂,所以其实这个flatbuffer是不是其实不用特别关注
 楼主| rea1 发表于 2024-9-27 12:30
Doorsman 发表于 2024-9-26 23:27
楼主,你ByteBuffer那题主要是对010editor的分析对吗,我看了很多flatbuffer也不是很懂,所以其实这个flatb ...

出题人想了两种解,一种是偏逆向思路的写一个简单的解析器来解析文件,这个是和flatbuffer沾边的,另一种思路就是这种偏misc直接猜。
Doorsman 发表于 2024-10-11 18:29
rea1 发表于 2024-9-27 12:30
出题人想了两种解,一种是偏逆向思路的写一个简单的解析器来解析文件,这个是和flatbuffer沾边的,另一种 ...

第一种解法的相关Writeup有吗
wantwill 发表于 2025-3-17 18:42
blutter
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-1 09:06

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表