Reverse
re1
有video.mp4与loader elf初始化运行后生成stager.pyc

Cat stager.pyc

字节较短,默认为混淆项
在loader中发现大量base64

Objdump看到主要流程
检查video.mp4存在,解码内置base64写出stager.pyc并chmod 0755
拼接命令python3 <script> video.mp4
并利用sysetm()执行利用loader中的base64提取pyc

反编译

分析,有xor。逆向脚本应该从附件提供的cideo解析bit串并异或0XAA

得到一个elf
用ida打开看下字符串

得到关键数组,但是暂时不清楚方式,在虚拟机里跑一下

提取md5并解析得到flag(.data段而非.rodata)
本题完
re2
1.看pe结构,入口0x4156c0

在4158F9下断点

单步跳转

得到ascii值NGeQwv8eCRpINEcO
验证无误

在%temp%下发现文件

重命名后运行看下

丢ida

观察得到
32key

16iv

起始密文

写个脚本得到flag
(
BP_MAIN = 0x401550
DEC_FUNC = 0x404D80
KEY_OFF, IV_OFF, CT_OFF = 0x01, 0x21, 0x31
)

re3
分析题得,pcap里有传出密文,需要解析程序加密逻辑
Die看到

Ida里发现

尝试找CArchive cookie

python -c “from pathlib import Path; b=Path(‘client’).read_bytes(); m=b’MEI\x0c\x0b\x0a\x0b\x0e’; print(b.rfind(m))”
得到偏移量

解析 TOC 并提取 client与crypt_core.so


把提取到的crypt_core.so丢ida

找到encode关键字
有点像SM4但是不太标准
分析下认为轮数是24而非默认32
常量表(SBOX/FK/CK)来自 rodata,可以用little-endian word解释
再回来看client
提取到逻辑_obf_exec(base64.b85decode(超长字符串).decode())
B85解码后继续
- base64.b85decode
- (k1, k2, rn)循环 XOR
- 字母做反向 Caesar 偏移(-rn)
- 数字也做
-rn的模 10 偏移
是ython marshal code object,非原生elf
有crypt_core.encode_data(plaintext, key[:16])
KEY_B64 = “eUYme4MkN1KSC1bWJZJ2w3FUJCiEXT13D2u1KmiNtfhXKZYE”
FILES_TO_SEND = [“readme.txt”, “flag.txt”, “config.txt”]
encrypt_file=crypt_core.encode_data(plaintext, key[:16])
把这些提取出来写脚本

得flag
题完
Misc
misc1
附件缺失文件头

但是通过27 1c 判断为7z文件,补全解压得到一个png,随波逐流提示rgb 位隐写zip

Stegsolve提取出来有flag.zip与pass*.zip(*=1~4)
因为crc32对固定4字节可逆;所以可以直接从 CRC 反推出明文

Flag.zip 密码为c1!xxtLf%fXYPkaA
尝试解压得到零宽

发现不是正常的零宽解码
观察一下发现均为0x200c与0x200b
尝试替换为01

U+200B=0, U+200C=1条件下得到flag
题完
Crypto
rsa
1.审计generate-plaintexts.py
S = int.from_bytes(secret_bytes, 'big')
ki = S % di
share_str = f"{di:x}:{ki:x}:{original_bits:x}"
plaintext-j.txt的规律
第 1 行:message1
第 2~10 行:分别是 message2-0 的第 j 份 share。
- encrypt.py
n_bits >= 2048:RSA-OAEP(32-byte key) + AES-GCM
n_bits < 2048:原 pow(m, e, n)``(16-byte key) + AES-GCM
3.思路
先解rsa
拿到plaintext-j一定量后再去解message
4.统计key-*.pem的(n_bits, e)并两次最大公约数
发现key1与key2共用1024bits因子
Key4与key15共用262bits因子
- 共享素数攻击
计算两个模数 Na、Nb 的最大公约数得到 p
用 Na / p 得到另一个素数 qa。
用 Nb / p 得到另一个素数 qb。
计算 φ(n) = (p−1)(q−1)。
计算 私钥指数 d = e 的模 φn逆元。
得到key-1, key-2, key-4, key-15的私钥
6.对可疑大 e 的 key 跑 Wiener,得到key6/12/17
分支 A (n_bits>=2048):header=RSA_OAEP(cipherkey)
分支 B (n_bits<2048):header=pow(key,e,n)
解密成功映射:
ciphertext-2 -> key-6
ciphertext-3 -> key-4
ciphertext-5 -> key-17
ciphertext-8 -> key-1
因此拿到4 个 plaintext-j
对每个 messagei (i=2..10),从 4 份明文中取 4 个同余:
Si ≡ k{i,1} (mod d_{i,1})
Si ≡ k{i,4} (mod d_{i,4})
然后 CRT 合并得 S_i,再按 bits转字节串。
均满足M_bits > original_bits
故4份ciphertext-j就可以恢复message

密码为9Zr4M1ThwVCHe4nHnmOcilJ8
解压得到lv2
8.看task.py分析
随机生成 512-bit 素数p, q和 180-bit 小素数d
lam = lcm(p-1, q-1),e = inverse(d, lam)
c1 = m1^e mod n,其中 m1 = b”Secret message: ” + b”A”*16
计算 flag_hash = sha256(str(p+q)),并输出 flag = “next pass is {flag_hash}”
给出 n, e, c1, c2, c3 和掩蔽后的多项式系数
- 枚举小整数 t( 1 400)
对 t*e/n`做连分数并取每个收敛分数 k/d
用已知明文快速验真:检查 pow(c1, d, n) == m1
得到t = 4
d = 1022911946105965821118646394713728017371180638538072123(180-bit)
10.由ed-1分解n
成功得到p = 9107629749578703007521753435128188255997152813554367948373413785978810344628038189563213036161837882971963700600044412434325055960560499599730973768232229
q = 10932961240863053140021227333995503042196506533433133299916502568289020826078008576745192725272664686384293526720057562101790406102729886343233171385110689`
p+q = 20040590990441756147542980769123691298193659346987501248289916354267831170706046766308405761434502569356257227320101974536115462063290385942964145153342918
计算python
password = sha256(str(p+q).encode()).hexdigest()

利用密码解压lv3
10.分析task.py
注意到
leak = ( (p _ CONST1) ^ (q _ CONST2) ^ ((p & q) << 64) ^ ((p | q) << 48) ^ ((p ^ q) _ CONST3) ) + ((p + q) % MOD128) ^ ((p _ q) & MASK64)
但是python语言中+优先级高于^
故这里实际上是leak = (A + B) ^ C
这里的
A = (pCONST1) ^ (qCONST2) ^ ((p&q)<<64) ^ ((p|q)<<48) ^ ((p^q)*CONST3)
B = (p+q) mod 2^128
B = (p+q) mod 2^64
且p*q = n已知
所以C = n mod 2^64是已知常数
令L = leak ^ CL= A + B

题目完
Comments