-
-
[原创]强网杯2025决赛复现
-
发表于: 2025-11-26 23:26 1609
-
本篇文章作个人复现 2025 强网杯决赛赛题的记录。
这道题是 rust 的综合题,总体难度算很高的了,并要求选手掌握很深的逆向功底,密码学技术和 shellcode 编写技术。

上来一串加密的数据,让人看得一脸懵逼,只能开逆了,主逻辑在 sub_1AB40 中,通过字符串发现一个菜单

顺着这个 menu 字符串可以找到关键结构

很显然,1FA20 就是所谓的加密函数了。

很好,非常无敌的加密,猜测一下 a1 的结构,如下:
根据加密的算法可以看出来,这是一个流式的加密,密钥递推符合如下公示:
其中 k 和 b 是随机生成的,其中只有 a[0] 是已知的,也就是该结构体 key 的初始值。

v8 对原文仅仅做了异或操作,而流式 key 保存在 v6,经过一系列的变化得到了 v8,在 v6->v7 和 v7->v8 的过程显然都是可逆的,那么只需要拿到异或得到的值,即可解出原 key。由于它四个 key 是轮转的,这就导致了开头的 32 字节加密是固定的,后续全部是随机。开头输出的菜单原文是已知的,也就是说,现在已知原文,密文,那么开头原文的一系列密钥是已知的,即说对于这四个数列 key1[n],key2[n],key3[n],key4[n],可以知道它们的前几项。
我们又已知数列的递推公式均满足 key[n] = (k * key[n-1] + b) mod pow(2,64) | (n>=1)
经过逆向把这些信息总结出来之后,就是 call 队伍里的密码学师傅了,个人认为解释的非常清楚了.

密码学师傅非常给力,很快给了我脚本,根据前几项来推测 k 和 b 的值,尽管可能有多解,实测发现多解情况随便选一组解不影响加解密。
把这个脚本保存为 m.py,可以构造交互了,因为系统会将用户输入的 hex 也加密一遍之后去理解含义,所以输入的时候需要进行一次加密(这个流加密可以验证加密和解密都能使用同一个函数),但是它们共享密钥生成器,所以这里需要做好分配。
初始密钥直接断函数看栈数据就行。

下面是交互脚本:
这样就可以成功和这个系统交互了,注意功能 1 并没有加密,而是直接输出,所以密钥不能轮转,事实上 1 功能在比赛中是用不到的功能。

分析登录功能,同样顺着字符串找关键位置,但是因为选手不可能手动和这个 ELF 交互,必须用 pwntools,所以需要借助 dbg_server 的附加功能完成调试,操作步骤为:
附截图,开启server,运行 exp

调试选项选附加

选择对应的进程

然后就可以美美调试了。

根据逻辑可知,用户名必须为 admin,password 经过调试是随机生成的。

每次判断密码正确会 sleep 5ms,根据这个特性可以逐字节爆破。
为了本地调试方便,把密码 patch 了,让它永远返回正确,因为后面才是大头。

简单粗暴点就行。
根据功能 3 找到具体执行的位置。

这里可以看到用 mmap 分配了权限为 7 的内存段。

它在执行之前会把可写权限关闭,并且满足一定的条件下会随机打乱输入的 shellcode。
全部算法如下
shellcode每连续的三个字节为一组进行如下游戏校验:
游戏背景:
每个回合中执行如下操作:
把游戏抽象为数学模型,不妨设三个玩家的生命值为 5x + a , 5y + b , 5z + c,Boss 血量根据要求为 5(x + y + z) + (a + b + c) | (a,b,c < 5)。
说白了,这游戏就不太可能可以赢,因为一个 5x + a 血量的人物只能给 Boss 造成 5x 的伤害,但是好在玩家先手,如果前面两个人(可以证明,游戏输赢和攻击顺序无关)死亡的情况下,剩下最后一个人,双方血量分别为 5z + c 和 5z + a + b + c,经过 z - 1 个回合之后,血量变成 5 + z 和 5 + a + b + c,最后一刻,必须给 Boss 致命一击,即攻击过后 a + b + c < 5,不然它再打过来玩家必输。
这里的 a,b,c 自然就是 byte % 5 的值,所以 shellcode 必须满足下面的要求。
只要任意三个连续的字节 %5 相加的值大于等于 5,这个 shellcode 就是不合法的。
所以尽量要选择权值(%5得到的值)尽可能低的指令去输入,一些比较好用的指令:
其余一些 mov 指令巨难用,一不小心就会超过,所以推荐用 xchg r1,r2,它的优点就是,如果正着来权值过大可以反过来,即写 xchg r2,r1,指令效果完全等价。

执行 shellcode 之前,它把几乎所有寄存器都清零了,也就是找不到一个可写的地址。
在此之前,也先看看沙箱

这里我选择是直接 patch main 函数,直接执行 sandbox 函数,得到的沙箱结果。
这个沙箱很简单,直接 openat + sendfile 即可,但是可写内存没有,因此我选择了 mmap 去分配内存,然后将栈定向到这块内存中去(虽然没用到),这块内存可以用于去写 /flag 字符串。
这个题目在执行 shellcode 之后还关闭了标准输入,导致我们没有办法重写 shellcode,只能按照它的要求和规则去书写。
下面是我写的 shellcode
shellcode满足要求之后直接写 exp 脚本,这里省略了爆破密码的步骤。
最终也是直接拿到 flag。

这道题只能 patch 沙箱的配置文件,一共 10 个 ban 位,openat 加白了,原生 orw 天然 ban 位,主要禁止的地方是读取文件,以下系统调用都能够读取文件。
总的来说,这题的质量还是非常高的,虽然比赛被折磨的很难受吧)
题目文档:
**题目名称:**trustSQL
**旗帜名称:**TSTSQ
**题目描述:**附件中给出了一个Ubuntu虚拟机,该虚拟机与台上靶机内的虚拟机环境完全相同,仅有系统密码不同。请挖掘并利用/home/qwb/sqlite3中的漏洞,构造一个恶意的数据库文件(假设用户完全信任并加载该数据库文件),实现用户在虚拟机中利用sqlite3打开该数据库文件,并执行特定的查询后,能自动弹出系统计算器。上台演示的时候注意关闭exp的调试信息。
附件信息: 附件中的虚拟机与台上靶机内的虚拟机环境完全相同,仅有系统密码不同。附件中虚拟机系统用户名为qwb,密码为admin。
**台上拓扑:**交换机同时连接选手攻击机和靶机。靶机中使用vmware(最新版)开启附件中提供的虚拟机环境(操作系统Ubuntu,仅系统密码和附件中的虚拟机不同),该虚拟机已在/home/qwb/sqlite3正确安装sqlite3。
**展示目标:**选手携带自己的攻击机上台,将可以完成漏洞利用的恶意数据库文件上传到自己的HTTP服务器。操作员将在靶机的Ubuntu虚拟机中,下载并利用sqlite3加载选手HTTP服务器上的恶意数据库文件(/home/qwb/sqlite3 malicious.db),然后在sqlite3中依次执行特定的查询命令(PRAGMA trusted_schema = ON; select users from qwbDB;)。在加载数据库并执行特定查询命令后的规定时间内,自动在Ubuntu虚拟机中弹出系统计算器。
题目已经帮忙开启了 PRAGMA trusted_schema = ON,直接用 sqlite3 的 edit 函数,直接执行计算器命令即可。
如果任意执行 SQL 命令,很容易想到

但是因为它要求只能执行特定查询,所以创建一个视图去触发最终的 payload。

其余的题目还在复现中,希望有精力复现吧。。
struct encryptData{ __int64 k[4]; __int64 b[4]; __int64 key[4]; __int64 idx;};struct encryptData{ __int64 k[4]; __int64 b[4]; __int64 key[4]; __int64 idx;};a[n] = k * a[n-1] + ba[n] = k * a[n-1] + b# 输入:已有的若干项(无符号 64 位,Python int 足够)from math import gcdM = 1 << 64def mod64(x): return x & (M - 1)# 解线性同余 k*dx ≡ dy (mod M)# 返回候选 k 的列表(每个在 [0, M-1])def solve_for_k(dx, dy): dx = mod64(dx); dy = mod64(dy) if dx == 0: # 0 * k ≡ dy (mod M) -> 有解当且仅当 dy ≡ 0 (mod M) return [0] if dy == 0 else [] # 特殊:dx==0 不约束 k,如果 dy==0 则任意 k 可,返回 placeholder g = gcd(dx, M) if dy % g != 0: return [] # 除以 g,在模 M' 下求逆 dxp = dx // g dyp = dy // g Mp = M // g # 计算 (dxp)^(-1) mod Mp # 使用扩展欧几里得或 pow since Mp 不是素数但 gcd(dxp, Mp)==1 inv = pow(dxp, -1, Mp) # Python 3.8+ k0 = (dyp * inv) % Mp # 所有解为 k0 + t*Mp, t=0..g-1 return [(k0 + t * Mp) % M for t in range(g)]def find_k_b_from_sequence(seq): n = len(seq) if n < 2: return None # 信息太少(任意 k,b 可) # 尝试用第一个能约束的相邻三项(或多处)来生成候选 k candidates = None for i in range(n - 2): dx = (seq[i + 1] - seq[i]) % M dy = (seq[i + 2] - seq[i + 1]) % M ks = solve_for_k(dx, dy) if ks == []: return [] # 在此处无解 -> 整个序列不可能来自同一线性映射 # 若 dx==0 且 dy==0 意味着这三项对 k 不产生约束,继续找下一组 if dx == 0 and dy == 0: continue # 否则 ks 为候选集合(注意:若 dx==0 and dy==0 we skipped) candidates = ks break # 如果一直没有约束(全部相等或每组三项都 dx==0,dy==0),处理特殊情形 if candidates is None: # 所有相邻差都为0 => seq 都相同 => (k-1)*c + b ≡ 0 (mod M),无限多解 return "ALL_EQUAL" # 提示无限多解(或需要更多约束) # 验证候选,保留能让所有已知项成立的那些 valid = [] for k in candidates: b = (seq[1] - (k * seq[0])) % M ok = True for i in range(n - 1): if ((k * seq[i] + b) - seq[i + 1]) % M != 0: ok = False; break if ok: valid.append((k, b)) return valid# 输入:已有的若干项(无符号 64 位,Python int 足够)from math import gcdM = 1 << 64def mod64(x): return x & (M - 1)# 解线性同余 k*dx ≡ dy (mod M)# 返回候选 k 的列表(每个在 [0, M-1])def solve_for_k(dx, dy): dx = mod64(dx); dy = mod64(dy) if dx == 0: # 0 * k ≡ dy (mod M) -> 有解当且仅当 dy ≡ 0 (mod M) return [0] if dy == 0 else [] # 特殊:dx==0 不约束 k,如果 dy==0 则任意 k 可,返回 placeholder g = gcd(dx, M) if dy % g != 0: return [] # 除以 g,在模 M' 下求逆 dxp = dx // g dyp = dy // g Mp = M // g # 计算 (dxp)^(-1) mod Mp # 使用扩展欧几里得或 pow since Mp 不是素数但 gcd(dxp, Mp)==1 inv = pow(dxp, -1, Mp) # Python 3.8+ k0 = (dyp * inv) % Mp # 所有解为 k0 + t*Mp, t=0..g-1 return [(k0 + t * Mp) % M for t in range(g)]def find_k_b_from_sequence(seq): n = len(seq) if n < 2: return None # 信息太少(任意 k,b 可) # 尝试用第一个能约束的相邻三项(或多处)来生成候选 k candidates = None for i in range(n - 2): dx = (seq[i + 1] - seq[i]) % M dy = (seq[i + 2] - seq[i + 1]) % M ks = solve_for_k(dx, dy) if ks == []: return [] # 在此处无解 -> 整个序列不可能来自同一线性映射 # 若 dx==0 且 dy==0 意味着这三项对 k 不产生约束,继续找下一组 if dx == 0 and dy == 0: continue # 否则 ks 为候选集合(注意:若 dx==0 and dy==0 we skipped) candidates = ks break # 如果一直没有约束(全部相等或每组三项都 dx==0,dy==0),处理特殊情形 if candidates is None: # 所有相邻差都为0 => seq 都相同 => (k-1)*c + b ≡ 0 (mod M),无限多解 return "ALL_EQUAL" # 提示无限多解(或需要更多约束) # 验证候选,保留能让所有已知项成立的那些 valid = [] for k in candidates: b = (seq[1] - (k * seq[0])) % M ok = True for i in range(n - 1): if ((k * seq[i] + b) - seq[i + 1]) % M != 0: ok = False; break if ok: valid.append((k, b)) return validfrom pwn import *from m import find_k_b_from_sequencecontext.log_level = 'debug'context.arch = 'amd64'import osimport sysfrom pwn import *# from z3 import *def ror64(value, shift, bits=64): """64位循环右移 - rol64的逆操作""" shift %= bits return ((value >> shift) | (value << (bits - shift))) & ((1 << bits) - 1)def rol64(value, shift, bits=64): """64位循环左移""" shift %= bits return ((value << shift) | (value >> (bits - shift))) & ((1 << bits) - 1)def mix(v6): v7 = v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2) ^ ((v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2)) >> 4) ^ ( (v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2) ^ ((v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2)) >> 4)) >> 8) ^ ( (v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2) ^ ((v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2)) >> 4) ^ (( v6 ^ ( v6 >> 1) ^ ( ( v6 ^ ( v6 >> 1)) >> 2) ^ ( ( v6 ^ ( v6 >> 1) ^ ( ( v6 ^ ( v6 >> 1)) >> 2)) >> 4)) >> 8)) >> 16) v7 = v7 & 0xFFFFFFFFFFFFFFFF v7h = v7 >> 32 v8 = rol64(v7 ^ v7h, 7) return v8def inverse_xor_shift(y, k): """逆异或变换:从 y 恢复 x,满足 y = x ^ (x >> k)""" x = y shift = k while shift < 64: x = x ^ (x >> shift) shift *= 2 return x & 0xFFFFFFFFFFFFFFFFdef inverse_mix(v8): """mix 函数的逆向算法""" # 步骤1: 循环右移7位得到 u u = ror64(v8, 7) # 步骤2: 从 u 恢复 v7 u_high = (u >> 32) & 0xFFFFFFFF u_low = u & 0xFFFFFFFF v7_high = u_high v7_low = u_low ^ u_high v7 = (v7_high << 32) | v7_low # 步骤3-7: 逐步逆异或变换恢复 v6 x4 = inverse_xor_shift(v7, 16) x3 = inverse_xor_shift(x4, 8) x2 = inverse_xor_shift(x3, 4) x1 = inverse_xor_shift(x2, 2) x0 = inverse_xor_shift(x1, 1) return x0OOO = bytes.fromhex('''3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D3D 20 54 4F 59 20 45 4E 43 52 59 50 54 45 44 2053 45 52 56 49 43 45 20 3D 3D 3D 3D 3D 3D 3D 3D3D 3D 3D 3D 3D 3D 3D 3D 3D 0A 31 29 20 45 63 686F 20 62 61 63 6B 20 77 68 61 74 20 79 6F 75 2073 65 6E 64 0A 32 29 20 41 64 6D 69 6E 20 6C 6F67 69 6E 0A 33 29 20 4D 61 67 69 63 43 6F 64 6520 72 75 6E 6E 65 72 0A 34 29 20 53 68 6F 77 2063 6F 6E 66 69 67 0A 35 29 20 51 75 69 74 0A 0A2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D2D 2D 2D 2D 2D 2D 2D 2D 2D 0A 59 6F 75 72 20 6368 6F 69 63 65 3A 20''')def setKey(hexdata): data = bytes.fromhex(hexdata.decode()) global KEYA, KEYB, KEYC, KEYX kc = [0, 0, 0, 0] kb = [0, 0, 0, 0] ka = [0, 0, 0, 0] for i in range(0xC0 // 8): if (i % 4 == 0): print() num1 = u64(data[i * 8:i * 8 + 8]) num2 = u64(OOO[i * 8:i * 8 + 8]) KEYX.append(num1 ^ num2) KEYC_TMP.append(inverse_mix(num1 ^ num2)) # print(hex(KEYX[i]),hex(KEYC[i])) print("----------") for i in range(4, 8): num1 = u64(data[i * 8:i * 8 + 8]) num2 = u64(OOO[i * 8:i * 8 + 8]) if i == 5 or i == 7: KEYB[i & 3] = KEYC_TMP[i] # print(hex(KEYB[i & 3])) k1 = [KEYC_TMP[0], KEYC_TMP[4], KEYC_TMP[8], KEYC_TMP[12]] k2 = [KEYC_TMP[1], KEYC_TMP[5], KEYC_TMP[9], KEYC_TMP[13]] k3 = [KEYC_TMP[2], KEYC_TMP[6], KEYC_TMP[10], KEYC_TMP[14]] k4 = [KEYC_TMP[3], KEYC_TMP[7], KEYC_TMP[11], KEYC_TMP[15]] res1 = find_k_b_from_sequence(k1) res2 = find_k_b_from_sequence(k2) res3 = find_k_b_from_sequence(k3) res4 = find_k_b_from_sequence(k4) print(res1) print(res2) print(res3) print(res4) if len(res1) == 1 and len(res2) == 1 and len(res3) == 1 and len(res4) == 1 or 1==1: KEYA[0] = res1[0][0] KEYA[1] = res2[0][0] KEYA[2] = res3[0][0] KEYA[3] = res4[0][0] KEYB[0] = res1[0][1] KEYB[1] = res2[0][1] KEYB[2] = res3[0][1] KEYB[3] = res4[0][1] print("KEYA:", [hex(i) for i in KEYA]) print("KEYB:", [hex(i) for i in KEYB])def getKeyStream(): global KEYA, KEYB, KEYC, KEYX KEYX = [i for i in KEYC] i = 0 while (1): realkey = mix(KEYX[i & 3]) yield realkey.to_bytes(8, 'little') KEYX[i & 3] = (KEYB[i & 3] + KEYA[i & 3] * KEYX[i & 3]) & 0xFFFFFFFFFFFFFFFF i += 1KEYGEN = getKeyStream()def decrypt(hexdata): KEY = b'' data = bytes.fromhex(hexdata.decode()) dec = bytearray(data) for i in range(len(data)): if i % 8 == 0: KEY = next(KEYGEN) dec[i] ^= KEY[i % len(KEY)] # print(dec.hex()) return decdef encrypt(data): KEY = b'' enc = bytearray(data) for i in range(len(data)): if i % 8 == 0: KEY = next(KEYGEN) enc[i] ^= KEY[i % len(KEY)] # print(dec) return enc.hex().replace(" ", "")for i in range(1): KEYA = [0, 0, 0, 0] KEYB = [0, 0, 0, 0] KEYC_TMP = [] # [0x9E3779B97F4A7C15, 0x0000000000000000, 0x94D049BB133111EB, 0x0000000000000000] KEYC = [0x9E3779B97F4A7C15, 0x0000000000000000, 0x94D049BB133111EB, 0x0000000000000000] KEYX = [] r = process("./somebox") firstData = r.recvline() setKey(firstData) if (KEYA[1] == 0): r.close() sys.exit(0) decrypt(firstData) while True: inp = input('$') if inp == 'exit': break r.sendline(encrypt(inp.encode())) b = r.recvline() print(decrypt(b).decode())from pwn import *from m import find_k_b_from_sequencecontext.log_level = 'debug'context.arch = 'amd64'import osimport sysfrom pwn import *# from z3 import *def ror64(value, shift, bits=64): """64位循环右移 - rol64的逆操作""" shift %= bits return ((value >> shift) | (value << (bits - shift))) & ((1 << bits) - 1)def rol64(value, shift, bits=64): """64位循环左移""" shift %= bits return ((value << shift) | (value >> (bits - shift))) & ((1 << bits) - 1)def mix(v6): v7 = v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2) ^ ((v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2)) >> 4) ^ ( (v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2) ^ ((v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2)) >> 4)) >> 8) ^ ( (v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2) ^ ((v6 ^ (v6 >> 1) ^ ((v6 ^ (v6 >> 1)) >> 2)) >> 4) ^ (( v6 ^ ( v6 >> 1) ^ ( ( v6 ^ ( v6 >> 1)) >> 2) ^ ( ( v6 ^ ( v6 >> 1) ^ ( ( v6 ^ ( v6 >> 1)) >> 2)) >> 4)) >> 8)) >> 16) v7 = v7 & 0xFFFFFFFFFFFFFFFF v7h = v7 >> 32 v8 = rol64(v7 ^ v7h, 7) return v8def inverse_xor_shift(y, k): """逆异或变换:从 y 恢复 x,满足 y = x ^ (x >> k)""" x = y shift = k while shift < 64: x = x ^ (x >> shift) shift *= 2 return x & 0xFFFFFFFFFFFFFFFFdef inverse_mix(v8): """mix 函数的逆向算法""" # 步骤1: 循环右移7位得到 u u = ror64(v8, 7) # 步骤2: 从 u 恢复 v7 u_high = (u >> 32) & 0xFFFFFFFF u_low = u & 0xFFFFFFFF v7_high = u_high v7_low = u_low ^ u_high v7 = (v7_high << 32) | v7_low # 步骤3-7: 逐步逆异或变换恢复 v6 x4 = inverse_xor_shift(v7, 16) x3 = inverse_xor_shift(x4, 8) x2 = inverse_xor_shift(x3, 4) x1 = inverse_xor_shift(x2, 2) x0 = inverse_xor_shift(x1, 1) return x0OOO = bytes.fromhex('''3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D3D 20 54 4F 59 20 45 4E 43 52 59 50 54 45 44 2053 45 52 56 49 43 45 20 3D 3D 3D 3D 3D 3D 3D 3D3D 3D 3D 3D 3D 3D 3D 3D 3D 0A 31 29 20 45 63 686F 20 62 61 63 6B 20 77 68 61 74 20 79 6F 75 2073 65 6E 64 0A 32 29 20 41 64 6D 69 6E 20 6C 6F67 69 6E 0A 33 29 20 4D 61 67 69 63 43 6F 64 6520 72 75 6E 6E 65 72 0A 34 29 20 53 68 6F 77 2063 6F 6E 66 69 67 0A 35 29 20 51 75 69 74 0A 0A2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D2D 2D 2D 2D 2D 2D 2D 2D 2D 0A 59 6F 75 72 20 6368 6F 69 63 65 3A 20''')def setKey(hexdata): data = bytes.fromhex(hexdata.decode()) global KEYA, KEYB, KEYC, KEYX kc = [0, 0, 0, 0] kb = [0, 0, 0, 0] ka = [0, 0, 0, 0] for i in range(0xC0 // 8): if (i % 4 == 0): print() num1 = u64(data[i * 8:i * 8 + 8]) num2 = u64(OOO[i * 8:i * 8 + 8]) KEYX.append(num1 ^ num2) KEYC_TMP.append(inverse_mix(num1 ^ num2)) # print(hex(KEYX[i]),hex(KEYC[i])) print("----------") for i in range(4, 8): num1 = u64(data[i * 8:i * 8 + 8]) num2 = u64(OOO[i * 8:i * 8 + 8]) if i == 5 or i == 7: KEYB[i & 3] = KEYC_TMP[i] # print(hex(KEYB[i & 3])) k1 = [KEYC_TMP[0], KEYC_TMP[4], KEYC_TMP[8], KEYC_TMP[12]] k2 = [KEYC_TMP[1], KEYC_TMP[5], KEYC_TMP[9], KEYC_TMP[13]] k3 = [KEYC_TMP[2], KEYC_TMP[6], KEYC_TMP[10], KEYC_TMP[14]] k4 = [KEYC_TMP[3], KEYC_TMP[7], KEYC_TMP[11], KEYC_TMP[15]] res1 = find_k_b_from_sequence(k1) res2 = find_k_b_from_sequence(k2) res3 = find_k_b_from_sequence(k3) res4 = find_k_b_from_sequence(k4) print(res1) print(res2) print(res3) print(res4) if len(res1) == 1 and len(res2) == 1 and len(res3) == 1 and len(res4) == 1 or 1==1: KEYA[0] = res1[0][0] KEYA[1] = res2[0][0] KEYA[2] = res3[0][0] KEYA[3] = res4[0][0] KEYB[0] = res1[0][1] KEYB[1] = res2[0][1] KEYB[2] = res3[0][1] KEYB[3] = res4[0][1] print("KEYA:", [hex(i) for i in KEYA]) print("KEYB:", [hex(i) for i in KEYB])def getKeyStream(): global KEYA, KEYB, KEYC, KEYX KEYX = [i for i in KEYC] i = 0 while (1): realkey = mix(KEYX[i & 3]) yield realkey.to_bytes(8, 'little') KEYX[i & 3] = (KEYB[i & 3] + KEYA[i & 3] * KEYX[i & 3]) & 0xFFFFFFFFFFFFFFFF i += 1KEYGEN = getKeyStream()def decrypt(hexdata): KEY = b'' data = bytes.fromhex(hexdata.decode()) dec = bytearray(data) for i in range(len(data)): if i % 8 == 0: KEY = next(KEYGEN) dec[i] ^= KEY[i % len(KEY)] # print(dec.hex()) return decdef encrypt(data): KEY = b'' enc = bytearray(data) for i in range(len(data)): if i % 8 == 0: KEY = next(KEYGEN) enc[i] ^= KEY[i % len(KEY)] # print(dec) return enc.hex().replace(" ", "")for i in range(1): KEYA = [0, 0, 0, 0] KEYB = [0, 0, 0, 0] KEYC_TMP = [] # [0x9E3779B97F4A7C15, 0x0000000000000000, 0x94D049BB133111EB, 0x0000000000000000] KEYC = [0x9E3779B97F4A7C15, 0x0000000000000000, 0x94D049BB133111EB, 0x0000000000000000] KEYX = [] r = process("./somebox") firstData = r.recvline() setKey(firstData) if (KEYA[1] == 0): r.close() sys.exit(0) decrypt(firstData) while True: inp = input('$') if inp == 'exit': break r.sendline(encrypt(inp.encode())) b = r.recvline() print(decrypt(b).decode())def brutePassword(): password = bytearray(16) current = 0 for i in range(128): found = False for c in range(33,0x7F): password[current] = c r.sendline(encrypt(b'2').encode()) decrypt(r.recvline()).decode() r.sendline(encrypt(b'admin').encode()) decrypt(r.recvline()).decode() # enter password r.sendline(encrypt(password.strip(b'\x00')).encode()) result = decrypt(r.recvline()).decode() pos = result.find('(') rpos = result.find('ms)') if(rpos == -1): print("!!!",password.strip(b'\x00')) return password.strip(b'\x00') T = int(result[pos+1:rpos]) if(T >= 5*current +5): print(password.strip(b'\x00'),result,T) current += 1 found = True if(found): break if(not found): password[current] = 0 current -= 1 return passworddef brutePassword(): password = bytearray(16) current = 0 for i in range(128): found = False for c in range(33,0x7F): password[current] = c r.sendline(encrypt(b'2').encode()) decrypt(r.recvline()).decode() r.sendline(encrypt(b'admin').encode()) decrypt(r.recvline()).decode() # enter password r.sendline(encrypt(password.strip(b'\x00')).encode()) result = decrypt(r.recvline()).decode() pos = result.find('(') rpos = result.find('ms)') if(rpos == -1): print("!!!",password.strip(b'\x00')) return password.strip(b'\x00') T = int(result[pos+1:rpos]) if(T >= 5*current +5): print(password.strip(b'\x00'),result,T) current += 1 found = True if(found): break if(not found): password[current] = 0 current -= 1 return passwordint __fastcall sub_56F17A9626C0(void *src, size_t n){ _BYTE *v2; // rax size_t v3; // rbx _BYTE *v4; // r14 char v5; // al __int64 v6; // rcx int b1; // esi unsigned __int16 b2; // cx int b3; // eax unsigned int v10; // r14d char v11; // bl char i; // bp unsigned int *v13; // rcx unsigned int v14; // eax unsigned int v15; // edx bool v16; // cf unsigned int v17; // r14d __int64 v18; // rbx size_t v19; // r13 unsigned int v21; // [rsp+Ch] [rbp-8Ch] BYREF void *v22; // [rsp+10h] [rbp-88h] BYREF int v23; // [rsp+18h] [rbp-80h] _DWORD v24[2]; // [rsp+1Ch] [rbp-7Ch] BYREF _BYTE v25[4]; // [rsp+24h] [rbp-74h] int v26; // [rsp+28h] [rbp-70h] int v27; // [rsp+2Ch] [rbp-6Ch] char v28; // [rsp+30h] [rbp-68h] int v29; // [rsp+34h] [rbp-64h] int v30; // [rsp+38h] [rbp-60h] char v31; // [rsp+3Ch] [rbp-5Ch] size_t v32; // [rsp+40h] [rbp-58h] _BYTE *v33; // [rsp+48h] [rbp-50h] size_t v34; // [rsp+50h] [rbp-48h] __int64 v35; // [rsp+58h] [rbp-40h] __int64 v36; // [rsp+60h] [rbp-38h] v22 = 0; getrandom(&v22, 4, 0); v22 = (void *)((_QWORD)v22 << 12); v2 = mmap(v22, 0x1000u, 7, 34, -1, 0); if ( v2 == (_BYTE *)-1LL ) return (int)v2; v3 = 2048; if ( n < 0x800 ) v3 = n; if ( !n ) return (int)v2; v4 = v2; memcpy(v2, src, v3); v32 = v3; memset(&v4[v3], 0, 4096 - v3); if ( n < 3 ) goto LABEL_29; v34 = v32 - 3; v5 = *v4; v6 = 0; v33 = v4; LABEL_8: v36 = v6 + 1; b1 = (char)v4[v6 + 1]; v35 = v6; b2 = (char)v4[v6 + 2]; b3 = (unsigned __int16)v5; v23 = b1; v24[0] = b3 + 255; v24[1] = 5; v25[0] = 1; v26 = (unsigned __int16)b1 + 255; v27 = 5; v28 = 1; v29 = b2 + 255; v30 = 5; v31 = 1; v10 = b2 + (unsigned __int16)b1 + b3 + 510 + 255; v11 = 1; for ( i = 1; ; i = 0 ) { while ( 1 ) { v21 = 0; getrandom(&v21, 4, 0); if ( !v25[12 * (v21 % 3)] ) { v14 = v10; goto LABEL_10; } v13 = &v24[3 * (v21 % 3)]; v14 = 0; v15 = 0; if ( *v13 >= 5 ) break; *v13 = 0; v16 = v10 < v13[1]; v17 = v10 - v13[1]; if ( v16 ) goto LABEL_14; LABEL_19: v14 = v17; if ( v15 < 5 ) goto LABEL_20; LABEL_15: if ( (i & 1) == 0 ) goto LABEL_21; LABEL_9: if ( v14 <= 4 ) { LABEL_7: v4 = v33; v5 = v23; v6 = v36; if ( v35 == v34 ) goto LABEL_29; goto LABEL_8; } LABEL_10: v10 = v14; } v15 = *v13 - 5; *v13 = v15; v16 = v10 < v13[1]; v17 = v10 - v13[1]; if ( !v16 ) goto LABEL_19; LABEL_14: if ( v15 >= 5 ) goto LABEL_15; LABEL_20: *((_BYTE *)v13 + 8) = 0; i = v25[0]; v11 = v28; if ( (v25[0] & 1) != 0 ) goto LABEL_9; LABEL_21: if ( (v11 & 1) != 0 ) goto LABEL_9; if ( v31 != 1 || v14 <= 4 ) break; v11 = 0; v10 = v14; } if ( v31 || v14 <= 4 ) goto LABEL_7; LOWORD(v24[0]) = 0; v18 = 0; v4 = v33; v19 = v32; do { getrandom(v24, 2, 0); v4[v18++] ^= LOBYTE(v24[0]); } while ( v19 != v18 ); LABEL_29: if ( !fork() ) { mprotect(v4, 0x1000u, 5); sandbox(); __asm { jmp rax } } LODWORD(v2) = wait(0); return (int)v2;}int __fastcall sub_56F17A9626C0(void *src, size_t n){ _BYTE *v2; // rax size_t v3; // rbx _BYTE *v4; // r14 char v5; // al __int64 v6; // rcx int b1; // esi unsigned __int16 b2; // cx int b3; // eax unsigned int v10; // r14d char v11; // bl char i; // bp unsigned int *v13; // rcx unsigned int v14; // eax unsigned int v15; // edx bool v16; // cf unsigned int v17; // r14d __int64 v18; // rbx size_t v19; // r13 unsigned int v21; // [rsp+Ch] [rbp-8Ch] BYREF void *v22; // [rsp+10h] [rbp-88h] BYREF int v23; // [rsp+18h] [rbp-80h] _DWORD v24[2]; // [rsp+1Ch] [rbp-7Ch] BYREF _BYTE v25[4]; // [rsp+24h] [rbp-74h] int v26; // [rsp+28h] [rbp-70h] int v27; // [rsp+2Ch] [rbp-6Ch] char v28; // [rsp+30h] [rbp-68h] int v29; // [rsp+34h] [rbp-64h] int v30; // [rsp+38h] [rbp-60h] char v31; // [rsp+3Ch] [rbp-5Ch] size_t v32; // [rsp+40h] [rbp-58h] _BYTE *v33; // [rsp+48h] [rbp-50h] size_t v34; // [rsp+50h] [rbp-48h] __int64 v35; // [rsp+58h] [rbp-40h] __int64 v36; // [rsp+60h] [rbp-38h] v22 = 0; getrandom(&v22, 4, 0); v22 = (void *)((_QWORD)v22 << 12); v2 = mmap(v22, 0x1000u, 7, 34, -1, 0); if ( v2 == (_BYTE *)-1LL ) return (int)v2; v3 = 2048; if ( n < 0x800 ) v3 = n; if ( !n ) return (int)v2; v4 = v2; memcpy(v2, src, v3); v32 = v3; memset(&v4[v3], 0, 4096 - v3); if ( n < 3 ) goto LABEL_29; v34 = v32 - 3; v5 = *v4; v6 = 0; v33 = v4; LABEL_8: v36 = v6 + 1; b1 = (char)v4[v6 + 1]; v35 = v6; b2 = (char)v4[v6 + 2]; b3 = (unsigned __int16)v5; v23 = b1; v24[0] = b3 + 255; v24[1] = 5; v25[0] = 1;[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
赞赏
- [原创]强网杯2025决赛复现 1610
- [原创]强网杯S9初赛逆向 writeup 2072
- [原创]2025腾讯游戏安全技术竞赛决赛题解 11315
- [原创]腾讯游戏安全大赛2025初赛题解 11250
- [原创]某二次元开放世界冒险游戏反作弊分析报告 19996