rea1 发表于 2024-9-22 13:24

ByteCTF Re WP

babyapk
首先分析了下java层的东西,然后发现和平常做的安卓不太一样,搜索后发现这是使用Flutter框架写的安卓apk,所以从网上找了下资料后发现可以使用blutter工具,具体的使用在此不再详说,网上有很多详细资料,在使用该工具初步解析apk后获得如下文件。



其中的main.dart可以说已经看清了该apk的主要逻辑。

该test函数可以轻易看到和验证有关的大量逻辑。
在下面发现最主要的是调用了 m3N4B5V6()函数进行判断。

右边的注释则说明了该函数所属的package。
进而找到simple.dart


接着跟进。

在这里我一度思路中断,因为我对Rust以及FFI调用的实现并不了解。
但是我注意到其中大量出现的API和Simple字样,于是在IDA中进行搜索发现该字符。

向上查看交叉引用发现了加密函数,

同时从加密函数那里继续向上查看引用多次最终索引到了这里。

这里是我之前搜索过m3n4b5v6分析过的函数,但是由于其中内部逻辑很多很乱,我实在没有分析下去,才转战dart文件去分析。除去前面这些过程实际上我还对native层的这些函数包括app.so内的一些和交互有关以及可疑的函数进行了多次fridaHOOK,但也成效甚微,不过还好总算找到加密逻辑处了。
然后这里也是因为之前HOOK时发现很多函数没反应于是猜测有长度检测,不断改变长度查看HOOK情况得到长度为0x2d,{}内为36位。

分析加密函数,倒着分析,得到该部分大致逻辑,判断为纯纯的z3.

用z3约束后发现约束出的数组都是可显字符,即32e750c8fb214562af22973fb5176b9c,猜测离flag很接近了。
from z3 import *

# 声明 v58 数组,每个变量为 16 位
forj in range(4):
    v58 = ', 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 >= 0, v58 <= 0x10FFFF)

    # 添加约束条件
    num2 = v58
    num3 = v58
    num0 = v58
    num1 = v58
    num4 = v58
    num5 = v58
    num6 = v58
    num7 = v58

    # 计算公式的约束条件
    s.add(num7 + num1 * num3 * num5 - (num0 + num6 + num2 * num4) == cmp)
    s.add(num3 - num4 - num0 * num5 + num7 * num1 + num2 + num6 == cmp)
    s.add(num0 * num5 - (num4 + num7 * num1) + num2 + num6 * num3 == cmp)
    s.add(num1 + num4 * num0 - (num7 + num2) + num6 * num5 * num3 == cmp)
    s.add(num5 * num3 + num1 + num2 * num4 - (num6 + num7 * num0) == cmp)
    s.add(num0 * num5 + num1 * num3 + num2 - (num6 + num4 * num7) == cmp)
    s.add(num7 - num1 + num2 * num5 + num6 - num0 * num4 * num3 == cmp)

    # 最后一轮的约束
    s.add(num3 - num7 - (num1 + num5) + num4 * num0 + num6 * num2 == cmp)

    # 求解
if s.check() == sat:
      model = s.model()
      v58_values = ].as_long() for i in range(8)]
      print("数组解是:", v58_values)
    else:
      print("没有解。")

这种逻辑的似乎涉及到编码转化,不影响flag的值。
这里发现了对-的约束,于是再根据很可显的字符串的长度为32,立马想到有四个-插在中间。

思考后感觉z3不好写而且情况也不多,于是直接写了穷举的爆破脚本。
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 =
   
    # 模拟你提供的验证逻辑
    v2 = byte]
    if v2 == 36:
      return False
    v3 = byte] + v2
    if v3 == 36:
      return False
    v4 = v3 + byte]
    if v4 == 36:
      return False
    v5 = v4 + byte]
    if v5 == 36:
      return False
    v6 = v5 + byte]
    if v6 == 36:
      return False
    v7 = v6 + byte]
    if v7 == 36:
      return False
    v8 = v7 + byte]
    if v8 == 36:
      return False
    v9 = v8 + byte]
    if v9 == 36:
      return False
    v10 = input_bytes
    if v10 != ord('-'):
      return False
    v12 = v9 + byte]
    if v12 == 36:
      return False
    v13 = v12 + byte]
    if v13 == 36:
      return False
    v14 = v13 + byte]
    if v14 == 36:
      return False
    v15 = v14 + byte]
    if v15 == 36:
      return False
    v16 = v15 + byte]
    if v16 == 36:
      return False
    v18 = input_bytes
    if v18 != ord('-'):
      return False
    v20 = v16 + byte]
    if v20 == 36:
      return False
    v21 = v20 + byte]
    if v21 == 36:
      return False
    v22 = v21 + byte]
    if v22 == 36:
      return False
    v23 = v22 + byte]
    if v23 == 36:
      return False
    v24 = v23 + byte]
    if v24 == 36:
      return False
    v25 = input_bytes
    if v25 != ord('-'):
      return False
    v27 = v24 + byte]
    if v27 == 36:
      return False
    v28 = v27 + byte]
    if v28 == 36:
      return False
    v29 = v28 + byte]
    if v29 == 36:
      return False
    v30 = v29 + byte]
    if v30 == 36:
      return False
    v31 = v30 + byte]
    if v31 == 36:
      return False
    v32 = input_bytes
    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# 插入 '-' 并调整位置索引
   
    # 验证插入的 '-' 是否符合条件
    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字样

所以大致能猜到这些线和点能画出来Flag。
于是将dot和Edge的一份数据分别提取一份喂给Gpt,然后它成功猜测到可能的数据结构:

一开始Edge的分析成了两个坐标,后来才发现它的分析的起始坐标很有规律,于是猜到了是代表的下面的点的序号及之间的连接。
遂训练AI写出脚本解出。
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]
    y_values = , dot_coordinates]
    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()

发现图还有点问题,第三个一看就很有特点,是7,于是镜像翻转

flag:ByteCTF{327542185069230715865}

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有吗
页: [1]
查看完整版本: ByteCTF Re WP