12.15 ciscn&“长城杯”铁人三项 部分题解
前言
做出来的两道密码到最后都只有五十分了(悲)
先把做出来的题分析一下,之后有时间了把剩下两道密码题补一下。
rasnd
一开始看标题以为是什么随机数(?),折腾老半天
题目内容:
怎么全是114514啊,他有什么用呢
题目附件:
1 | from Crypto.Util.number import getPrime, bytes_to_long |
其实是很简单的解方程
Part.1
\[ \left\{\begin{matrix} h_1 &=& x_1 p + y_1 q - \text{0x114}\\ h_2 &=& x_2 p + y_2 q - \text{0x514}\\ n &=& pq \end{matrix}\right. \]
\(3\) 个方程,\(6\) 未知元 (\(x_1, x_2\) 可爆破,\(y_1\) 难以爆破,\(y_2, p,q\) 不可爆破)
直接解肯定是不行的,得想想办法
最开始想直接碰撞 \(x_1 = x_2\) 的情况来着,但是下发的容器太慢了,跟有工作量证明一样慢(
尝试消元
先记 \(h_1' = h_1 + \text{0x114}, h_2' = h_2 + \text{0x514}\)
感觉像做齐次化一样: \[ \left\{\begin{matrix} x_2 h_1' &=& x_2 x_1 p + x_2 y_1 q\\ x_1 h_2' &=& x_1 x_2 p + x_1 y_2 q\\ \end{matrix}\right. \] 这样就好办了 \[ x_2 h_1' - x_1 h_2' = (x_2 y_1 - x_1 y_2) q\\ q = \gcd(n, x_2 h_1' - x_1 h_2') \]
1 | def solve1(): |
Part.2
关键是 hint = pow(514*p - 114*q, n - p - q, n)
\[
h = (514p-114q)^{n-p-q} \mod{n}
\] 注意到 \[
n-p-q= \varphi(n) - 1
\] 则根据欧拉定理有 \[
h \equiv (514p-114q)^{n-p-q} \pmod{n}\\
h \equiv (514p-114q)^{\varphi(n) - 1} \pmod{n}\\
h \equiv (514p-114q)^{-1} \pmod{n}\\
514p-114q \equiv h^{-1} \pmod{n}
\] 联立 \(n = pq\) 解之
1 | def solve2(): |
完整脚本: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78from Crypto.Util.number import getPrime, bytes_to_long, long_to_bytes
from random import randint
import os
from gmpy2 import gcd
from tqdm import tqdm
from Pwn4Sage.pwn import * # 为什么 sagemath 不能直接用 pwntools 啊 QAQ
def solve1():
n = int(r.recvline().decode().strip())
c = int(r.recvline().decode().strip())
hint1 = int(r.recvline().decode().strip())
hint2 = int(r.recvline().decode().strip())
hint1 += 0x114
hint2 += 0x514
for x1 in tqdm(range(0, 2**11)):
for x2 in range(0, 2**11):
q = gcd(hint2*x1 - hint1*x2, n)
p = n // q
if p != 1 and q != 1:
print("p =", p)
print("q =", q)
print("n =", n)
phi = (p-1)*(q-1)
d = int(pow(0x10001, -1, phi))
m = int(pow(c, d, n))
print(long_to_bytes(m))
return long_to_bytes(m)
def solve2():
# problem 2
n = int(r.recvline().decode().strip())
c = int(r.recvline().decode().strip())
hint = int(r.recvline().decode().strip())
koiship_114q = int(pow(hint, -1, n))
print(koiship_114q)
p, q = var('p q')
equ = [koiship_114q - 514*p+114*q, p*q - n]
res = solve([*equ], p, q)
print(res)
p = res[0][0].right()
q = res[0][1].right()
assert n == p * q
d = int(pow(0x10001, -1, n - p - q + 1))
m = int(pow(c, d, n))
print(long_to_bytes(m))
return long_to_bytes(m)
r = remote("39.105.45.179", 28774)
print(r.recvline())
flag1 = solve1()
print(r.recvline())
flag2 = solve2()
flag = flag1 + flag2
print(flag)
r.close()
# [94m[INFO][0m Connected to 39.105.45.179:28774
# b'==================================================================\n'
# 79%|███████▉ | 1622/2048 [01:00<00:15, 26.66it/s]p = 113931722055442701446227924225349342923035624336145681834183562625057779377412924188573492959081360857781622186384116214966258654184221455843401118314188230036225081356507628890053642334996763558081421549633854635489449005191128321348912176542344609801537585688185055218829569712481850220492418068455562521829
# q = 149687346278749733067771297796945134099573873882567708652528570721488495821734755104637927800569308648962222037872291706921428733233538343781900144390625108429477113911807232022408337280198004423317446408070180889503468830562635209615088067864562884988577416076468399790923049267827295132481119445792416795149
# n = 17054137131447319945462384577254586097818250280780440320505467706897381254398747857859611806051972107698572439639775195808276084624856874341810622198050944075029080669224262914186173634532945387572640585931189004598187516938998086186995618166426870493457572040586964035600503428663382122178741406778161779710515037520476192110503002807973029096714007655422047760141304087057135939835116788750148377067980861167227866440162107916225595534428842407827591690743865754799172493177485957066320753065436091614874565684831073947206929492837357883825511923747732779932353056073142795755044524329528614552186610574732533807521
# b'flag{ee62271a-b54b-'
# b'==================================================================\n'
# 35610761698930940955771524558264010431522232657139038026752170697961012150702331649488019804859068437215686128408212178056949158912363869075711016212204864344389859925409597955876297487978180421187133658719883091149063748060508765695828722993056359306928172621966424898685428613654429194960129005375870671933276
# [
# [p == 91296421208611922009772689366803267564928168341171916989523970204539467723847488273321200980271550391186875290590716338929702908310241534732665172498948370179431797142127466879844213504727818818087679198845566652075146859497667657189899764407074267181251805245319917664997604618612003883760286995861012937971, q == 99259638616627955765365243651516395586410928686169537770729385852388370696098923885956820166671126875915506762766807194323843297886844559446305986423285946735421787768806315968102002223262442555350293416550334807171594190537652720173506630808594859861712765562526427904590703160632814046426829039444648931437],
# [p == (-5657799401147793478625818888136434548425422935111663652931574993586137129677638661499538749500254231927183885477708010076459067979550139888439441226127298963919041902821960010181814126725959225654966724743369084008780868860646205049889877956089907012117627637064006390561670080156070400646329255248344989091909/257), q == (-23463180250613263956511581167268439764186539263681182666307660342566643205028804486243548651929788450535026949681814099104933647435732074426294949332229731136113971865526758988119962870715049436248533554103310629583312742890900587897804239452618086665581713948047218839904384386983284998126393757936280325058547/57)]
# ]
# b'468f-87e0-78730eebf8b2}'
# b'flag{ee62271a-b54b-468f-87e0-78730eebf8b2}'
# [94m[INFO][0m Connection closed
fffffhash
题目内容
听说hash函数不可逆?我不信
题目附件
1 | import os |
解题
本题要实现一个哈希碰撞
经过查询魔数,可以搜到这个先乘再异或是一种 FNV hash
参考 https://github.com/DownUnderCTF/Challenges_2023_Public/blob/main/crypto/fnv/solve/solution_joseph_LLL.sage
每一步的异或,都可以等价为加减某个数,因此可以写出式子
\[ G \oplus r = G \pm s \] 其中 \(r, s\) 都是小量,满足 \[ \left \lceil \lg r_{max} \right \rceil = \left \lceil \lg s_{max} \right \rceil = \left \lceil \lg 2^{8} \right \rceil = 8 \] 可以构造多项式 \[ TargetHash = Hash_0 p^n + s_0 p^{n-1} + s_1 p^{n-2} + s_2 p^{n-3} + \cdots + s_{n-2} p^{1} + s_{n-1} p^{0} = Hash_0 p^n + \sum _{i=0}^{n-1} s_i p^{n-1-i} \] 构造格 \[ \begin{bmatrix} s_0, s_1, s_2, \cdots, s_{n-2}, s_{n-1}, 1, k \end{bmatrix} \begin{bmatrix} p^{n-1} & 1 & & & & & & \\ p^{n-2} & & 1 & & & & & \\ p^{n-3} & & & 1 & & & & \\ \vdots & & & & \ddots & & & \\ p^{1} & & & & & 1 & &\\ p^{0} & & & & & & 1 &\\ h_0p^n - t & & & & & & & 1 & \\ N & 0 & 0 & 0 & \cdots & 0 & 0 & 0 & \end{bmatrix} = \begin{bmatrix} 0, s_0, s_1, \cdots, s_{n-3}, s_{n-2}, s_{n-1}, 1 \end{bmatrix} \]
1 | TARGET = 201431453607244229943761366749810895688 |
格基规约后再把 +
转为 ^
即可
Kiwi
很有意思的题(因为是唯一拿到的高分题目)
给了一段流量包和病毒样本,解密 Windows 密码
感谢我们的逆向大神,tql!
IDA:
程序首先隐藏了自己的窗口,使用 mimikatz
来获取
SAM
等敏感信息,加密后通过 upload
函数上传,上传流量可以在流量包附件中查看。
流量包中有超级多的请求,导致一开始分析了老半天上传方式。只找到一个可疑的流量包
1 | l1Mvs8wZ1LI/v3Vup1zF8bzdp1B51zz0e0xdfIXNBQMOe1wFEg+Z03ljczfC1qGdp0Y6bWnJ7rUqnQrZmVT9nFPRXqYpURBxuBKInjI5Q2xVgs56q4VRCQWbiyv00Aw7D0CKEotHSy6sQAC1x3T9wDx6xPCioqx/0nwNgrvJnF1Oq7NFZsVpnAxaZC5BVfKSEttFPjYgv3uSfmtxeJg7pPCHmJ8qf/Sd7W7n3gKSB2BELb== |
像一段 base64,但实际上解不出来任何东西
通过瞎翻 IDA,发现上传数据前,先进行了一段加密,再进行了换表 base64 编码
表:d+F3DwWj8tUckVGZb57S1XsLqfm0vnpeMEzQ2Bg/PTrohxluiJCRIYAyH6N4aKO9
像我这种不熟悉逆向和 IDA 的 crypto
手来说,我一开始就是没看出来这个表是从 64h
开始而非从
28h
开始的(
加密后会在下一个函数中上传数据
到这里差不多就理清了,解换表 base64 后再解密
解换表
1 | # By MetaMiku |
解密
1 | // By txpoki |
拿到明文
1 | User=Administrator |
最后的 NTLM=23d1e086b85cc18587bbc8c33adefe07
找在线网站破解
破解 https://ntlm.pw/
检验 https://www.xdtool.com/ntlm
300分,get (`・ω・´)
__END__