HKCERT24 Rev bashed 和 MBTI Radar WP
字数 1333 2025-08-20 18:17:48
HKCERT24逆向题目解析:bashed与MBTI Radar
bashed题目解析
题目概述
- 提供一个名为❤️.sh的bash脚本文件
- 脚本接受一个87字符长度的flag作为参数
- 使用大量emoji进行数据处理和流程控制
- 最终检查标志位GALF是否为0来验证flag
Bash关键特性分析
特性一:不严格的函数定义
- Bash中变量和函数可以同名,函数优先执行
- 当函数名作为参数传递时,会被当作字符串处理
- 题目中emoji同时作为函数名和参数使用
特性二:动态更新与执行顺序
- 脚本使用wget动态更新自身内容
- Bash执行时会一次性读入脚本内容到内存
- 行末的
\会影响PC(程序计数器)的移动规则:- 执行完带
\的行后,会跳过后续连续带\的行 - 动态修改后,以新文件内容重新判断
\的影响
- 执行完带
特性三:整数溢出
- Bash使用64位整数运算
- 连续乘法会导致高位溢出,最终可能得到0
- 题目利用此特性进行最终验证
题目逻辑解析
-
emoji_table结构:
- 256行emoji_line组成
- 每行第一个emoji定义函数,其余为参数
- 共88个不同的emoji_table文件
-
执行流程:
- emoji_line[0]函数将emoji_line[1:8]重排序
- 检查flag子串的sha1值(emoji_line[1:3])
- 根据检查结果:
- 成功:GALF *= emoji_line[6],跳转emoji_line[4]
- 失败:GALF *= emoji_line[7],跳转emoji_line[5]
- 行号idx根据
\规则递增
-
算法模型:
- 88张emoji_table,每张256行
- 根据flag子串sha1值决定跳转路径
- 最终要求GALF溢出为0
解题步骤
1. 深度遍历搜索
def calc_next_idx(emoji_filename, idx):
table = g_emoji_table[emoji_filename]
line = table[idx]
while line[-1] == "\\":
idx += 1
line = table[idx]
return idx + 1
def search_correct(emoji_filename, emoji_line, GALF, idx):
start = ord(emoji_line[0]) - ord('ear')
length = ord(emoji_line[1]) - ord('ear')
c_1 = hex(ord(emoji_line[2]) - ord('ear')[2:]
if GALF*ord(emoji_line[5]) & 0xffffffffffffffff != 0 and len(c_1) == 1:
GALF *= ord(emoji_line[5])
GALF &= 0xffffffffffffffff
target = emoji_line[3]
idx = calc_next_idx(emoji_filename, idx)
if len(g_emoji_table[target]) < idx or idx >= 256:
return True
new_line = g_emoji_table[target][idx]
g_result[idx]=(start, start+length, True, c_1)
new_line = mapping_emojis(new_line[0], new_line, g_emoji_mapping)
search_correct(target, new_line, GALF, idx)
if GALF*ord(emoji_line[6]) & 0xffffffffffffffff != 0:
target = emoji_line[4]
GALF *= ord(emoji_line[6])
GALF &= 0xffffffffffffffff
idx = calc_next_idx(emoji_filename, idx)
if len(g_emoji_table[target]) < idx or idx >= 256:
return True
new_line = g_emoji_table[target][idx]
g_result[idx]=(start, start+length, False, c_1)
new_line = mapping_emojis(new_line[0], new_line, g_emoji_mapping)
search_correct(target, new_line, GALF, idx)
2. 回溯搜索flag
from hashlib import sha1
def get_sha1_second_char(s):
return sha1(s.encode()).hexdigest()[1]
def backtrack(current_string, n, constraints, index_constraints):
if len(current_string) == n:
return current_string
for c in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}":
current_string += c
valid = True
for (start, end, target_char) in index_constraints.get(len(current_string), []):
substring = current_string[start:end]
if get_sha1_second_char(substring) != target_char:
valid = False
break
if valid:
result = backtrack(current_string, n, constraints, index_constraints)
if result:
return result
current_string = current_string[:-1]
return None
MBTI Radar题目解析
题目概述
- Unity游戏程序,使用IL2CPP编译
- 输入1-6字符的名字,生成MBTI类型序列
- 需要预测随机数生成结果匹配目标序列
关键逻辑分析
-
初始化阶段:
- 输入字符映射到
0123456789abcdefghijklmnopqrstuvwxyz的下标 - 转换为36进制整数作为随机数种子
- 输入字符映射到
-
随机数生成:
- 使用类似MT算法的伪随机数生成器
- 生成浮点数范围在0-1之间
- 乘以201后映射到MBTI类型
-
验证逻辑:
- 共6个阶段,输入长度1-6的字符
- 生成的MBTI序列与目标比较
- 完全匹配则记录flag部分
解题步骤
1. 实现随机数生成器
class MyRandom(object):
def __init__(self):
self.random_num = [0] * 8
self.table = "0123456789abcdefghijklmnopqrstuvwxyz"
def random_seed(self, seed):
self.random_num[0] = seed
for i in range(1,4,1):
self.random_num[i] = (self.random_num[i-1] * 0x6C078965 + 1)&0xffffffff
def get_random_seed(self):
v1 = self.random_num[0] ^ ((self.random_num[0] << 11)&0xffffffff)
self.random_num[0] = self.random_num[1]
self.random_num[1] = self.random_num[2]
v2 = self.random_num[3]
self.random_num[2] = self.random_num[3]
self.random_num[3] = v1 ^ v2 ^ ((v1 ^ (v2 >> 11)) >> 8)
n = (self.random_num[3] & 0x7FFFFF)
return n * 0.0000001192093
2. MBTI类型映射
def get_ans(n):
if n < 54.0:
if n < 33.0:
if n < 12.0:
StrTagObj = "INFJ"
if n >=3.0: StrTagObj = "INFP"
else:
StrTagObj = "ENFP"
if n >= 28.0: StrTagObj = "ENFJ"
elif n <44.0:
StrTagObj = "INTJ"
if n >= 37.0: StrTagObj = "INTP"
else:
StrTagObj = "ENTP"
if n >= 50.0: StrTagObj = "ENTJ"
elif n <147.0:
if n <105.0:
StrTagObj = "ISTJ"
if n > 77.0: StrTagObj = "ISFJ"
else:
StrTagObj = "ESTJ"
if n >= 122.0: StrTagObj = "ESFJ"
elif n < 176.0:
StrTagObj = "ISTP"
if n >= 158.0: StrTagObj = "ISFP"
else:
StrTagObj = "ESTP"
if n > 184.0: StrTagObj = "ESFP"
return StrTagObj
3. 爆破搜索
stage = 5
target = mbti[stage].split(' ')
for seed in range(36**stage,36**(stage+1)):
mr = MyRandom()
mr.random_seed(seed)
res = []
for i in range(50):
n = mr.get_random_seed()
each_mbti = get_ans(n*201.0)
if each_mbti != target[i]: break
res.append(each_mbti)
if len(res) == 50:
ans = ''
while seed > 0:
ans = mr.table[seed % 36] + ans
seed //= 36
print(ans)
exit(0)
总结与技巧
bashed题目关键点
- 理解bash中函数和变量的同名机制
- 掌握动态脚本修改对执行流程的影响
- 利用整数溢出特性进行最终验证
- 将复杂bash逻辑转化为可搜索的算法模型
MBTI Radar题目关键点
- 识别IL2CPP编译的Unity程序结构
- 分析随机数生成算法并实现等效版本
- 理解种子生成机制(36进制转换)
- 使用爆破方法搜索符合条件的输入
通用逆向技巧
- 对于混淆代码,编写小型测试程序验证猜测
- 动态调试与静态分析结合
- 将复杂逻辑分解为可管理的部分
- 注意数据类型的转换和边界条件