0xGame 2024 WriteUp
Misc
Happy 1024!
AI搜索关键词
1  | 根据搜索结果,同时包含“star”、“boat”、“dream”、“water”、“sky”这些元素的诗词是元代诗人唐珙的《题龙阳县青草湖》中的名句:“醉后不知天在水,满船清梦压星河。”  | 
Crypto
ECC-DH
共享密钥等于其中一方的私钥乘以另一方的公钥
1  | a = 10809567548006703521  | 
1  | ┌──(root㉿Spreng)-[~]  | 
1  | 请输入proof: htC8hwrveKHEj447  | 
ECC-baby
用sage计算
1  | from sage.all import *  | 
1  | from Crypto.Cipher import AES  | 
EzLogin-I
使用CBC字节翻转攻击:规定密文为C(已知),解密后的密文为B(未知),原来的明文为P(已知),他们满足 ,现在可以篡改IV, 使得 ,这样就能篡改cookie。
1  | #!/usr/local/bin/python  | 
1  | ┌──(root㉿Spreng)-[~]  | 
1  | [+] Enter your cookie:  | 
EzLogin-II
PaddingOracleAttack:与CBC翻转攻击类似,依然是,只不过这次的P是未知的,由于unpad过程有报错提示,可以据此判断P的情况。对B的对应字节进行枚举,例如枚举最后一个字节,当时,提示JSON Wrong,否则提示Unkown Wrong,一般希望得到的是,这样就可以反推出B和P。枚举其他字节时,利用前面字节确定的B就可以定向控制P。
1  | #!/usr/local/bin/python  | 
LLL-I
先用LLL还原,正交矩阵会被约掉
1  | mt = matrix(ZZ, 0, 4)  | 
还原flag:
1  | # 假设 Length 是 8  | 
理解这道题为什么用 LLL 可以直接得出答案需要理解两个点:
- 在 flag 信息较小的情况下,M 极大概率能用 LLL 还原出 flag。
 - M 和 C*M 表示的格是相同的,对 M 和 C*M 进行格基规约是等效的。
 
第一点,举一个简单的例子,对于二维的格基(10,7)和(21,114514)进行格基规约,一定会保留(10,7),但(21,114514)一定会被约简。这道题也是,数量级小的 flag 信息和数量级大的 noise 同时格基规约,flag 信息极大概率会保留,除非两个数量级大的 noise 相减能得到比 flag 更小的格基但这几乎是不可能。
第二点,这个性质与三角、正交矩阵没关系,而是因为 C 行列式等于 1,像这样行列式等于 1 或-1 的矩阵叫单模矩阵。C*M 相当于一个对 M 的线性变换,这样的格基构成的格一定在 M 构成的格中。而格的行列式是个定量,对于同一个格的格基行列式总是相等的,由于 C*M 行列式没有变化,显然格也是不变的。
LLL-II
先推公式:
\begin{align} C_{i} = aC_{i-1}+b \mod m \\ km - aC_{i-1}+C_{i} = b \mod m \\ \end{align}
构造矩阵:
对第二个矩阵进行LLL即可
1  | Cs = [ 11804527453299586684489593808016317337345238230165321056832279785591503368758306671170625597063579251464905729051049524014502008954170088604924368057540940, 4930922884306486570759661288602557428608315558804950537470100263019228888817481617065454705843164809506859574053884206133344549895853064735361336486560981, 5380263856446165449531647111260010594620416730932539097782399557603420658350407080366132490174060420530708293564252852668431923560882648691392446521188465, 10746696290782998433216934286282230556131938525513632178308443345441147075710552571129957873399395862207656161609046567289600084193860244770966610161184627, 2195032957511830992558961021566904850278796737316238566513837995297394215638259916944087623923636789312134734949452839561765171446217520081402769962517110  | 
1  | from Crypto.Util.number import getPrime, inverse  | 
LLL-III
多元Coppersmith解法
1  | import itertools  | 
1  | # sage  | 
1  | 
  | 
这题当时用的多元 coppersmith 做的:多元 copper 脚本,h+p=a*seed+b,求解 p, seed 正好只有一组解。
构造格的过程如下,p 的数量级是 2^115^,这里的 K 应该设为 2^115^适宜。
Reverse
BabyASM
先化简原文
1  | data = [20, 92, 43, 69, 81, 73, 95, 23, 72, 22, 24, 69, 25, 27, 22, 17, 23, 29, 24, 73, 17, 24, 85, 27, 112, 76, 15, 92, 24, 1, 73, 84, 13, 81, 12, 0, 84, 73, 82, 8, 82, 81, 76, 125]  | 
转为python代码就是:
1  | data = [20, 92, 43, 69, 81, 73, 95, 23, 72, 22, 24, 69, 25, 27, 22, 17, 23, 29, 24, 73, 17, 24, 85, 27, 112, 76, 15, 92, 24, 1, 73, 84, 13, 81, 12, 0, 84, 73, 82, 8, 82, 81, 76, 125]  | 
LittlePuzzle
在线反编译jar,转python
1  | def exit():  | 
只要把数独给解了,把填入的数组合在一起运行一下就出来了
1  | import java.util.Scanner;  | 
Tea
由于C和python的位运算符不太一样,而且程序本来就是C写的,脚本就用C了
tea的解密只要把程序倒过来抄一遍就可以了
1  | 
  | 
The Matrix
这道题最开始叫Mad Matrix
这道题读程比较麻烦,hello就是给矩阵赋值的,前几位保存行数列数,代码中只用到了3阶矩阵
matmul就是矩阵的乘法
加密过程就是用输入做出7个矩阵,其中存在数据的复用。然后再轮流左乘k对应的4个矩阵,与data对比。
1  | 
  | 
解密过程也很简单,data左乘k的逆矩阵就是flag。
1  | # 3阶矩阵赋值  | 
Justsoso | Review
由题,flag 用 key 加密经过 base64 编码等于 encryptedFLAG,那么只要知道 key 并逆向 ReversC4.encrypt 即可。
1  | encryptedFLAG==b64encode(ReversC4.encrypt(flag, key))  | 
getKey()在 native 层,IDA 分析 so 文件源码:

看上去挺复杂,其实就是把 source 二倍后异或 0x7F,这样就得到了 key
1  | public static int[] getKey() {  | 
加密过程很好逆向,其中 inital、i、i2 只要随便编一个 44 位的 flag 放进 encrypt 里面跑一下,就能知道末状态的值,将他们作为初始值放进 decrypt 里面即可。
1  | public static byte[] decrypt(byte[] bArr, int[] iArr) {  | 
跑一下:
1  | public static void main(String[] args) {  | 
