2025-hscctf-wp
ancient
Base58 → Base62 → Base45 → Base85 → Base32 → Base64
按照这个顺序加密的,对着反向解密即可
密文:1
RzVJVFlaSkZGUk1HV1daWkdOQ0RFNEpJSE5RWEdOS05ISlNHSTNCT0daWVVXS1pDRzQzV01UQ0NISkVTNElKQkdKUkZFUEpYRjVIVk0zMlpIQVpXNjQyTkdaSlRBNFMzR1pKVENPMllIVjJWWVRMQ0daTERDTVpYR0JURk1TMlpHQlRWR0xDWkdaS1ZRWUo1R0ZURVFRSlNHQlRGNFQyTUc1SVRHUURFSFU3REVZSkVHNVdFS1FEUEdKUEVJS1NYRzQ0RkNRU0lITkNIQ1NaUEdWWlc0UlJZR1pZSEdRVFBHSVVXSVMzQkc0M0RHMkJIRzQ0R1lLU0VHQlFBPT09PQ==
1 | flag{cl@ss1cal_c1pher_@re_really_1nterest1ng} |
sign_in
题目:
1 | from Crypto.Util.number import * |
解题思路:
很直白的一个题,把flag的每个字符都处理为长度5的字节段,填充字节的规则为:
- 第一个字节为flag的第i个字符
- 后面的字节为flag的第i个字符的ascii码加i再对256取模
然后对每个字节段 ( m_i ) 进行线性变换:
给出了$a、S、L、C$,因为我们已知flag头,所以我们可以据此来回推出$b$,从而得到$M$。
exp: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#python
from Crypto.Util.number import *
a = 3517115977
S = 13338196046628817705384101887069807236659077
L = 5
C = [6399813929853868574459915097120849511644924, 6399813929853868574460006087942330564102834, 6399813929853868574459839271436281967929999, 6399813929853868574459930262257763020387909, 6399813929853868574460233564996033195247609, 6399813929853868574460112243900725125303729, 6399813929853868574459111344864433548266719, 6399813929853868574459930262257763020387909, 6399813929853868574460036418216157581588804, 6399813929853868574459808941162454950444029, 6399813929853868574459111344864433548266719, 6399813929853868574460036418216157581588804, 6399813929853868574459808941162454950444029, 6399813929853868574460127409037638634046714, 6399813929853868574459096179727520039523734, 6399813929853868574459930262257763020387909, 6399813929853868574459899931983936002901939, 6399813929853868574460127409037638634046714, 6399813929853868574459945427394676529130894, 6399813929853868574459172005412087583238659, 6399813929853868574460097078763811616560744, 6399813929853868574459808941162454950444029, 6399813929853868574460188069585292669018654, 6399813929853868574459960592531590037873879, 6399813929853868574460188069585292669018654, 6399813929853868574459960592531590037873879, 6399813929853868574460263895269860212733579]
def construct_m_from_char(char, L):
char_ascii = ord(char)
pad_len = L - 1
pad_bytes = bytes([(char_ascii + i + 1) % 256 for i in range(pad_len)])
seg_bytes = bytes([ord(char)]) + pad_bytes
return bytes_to_long(seg_bytes)
known_chars = ['f', 'l', 'a', 'g']
derived_b = []
for idx, char in enumerate(known_chars):
m_i = construct_m_from_char(char, L)
b = (C[idx] - a * m_i) % S
derived_b.append(b)
b = derived_b[0]
print(f"推导出的私钥b = {b}")
a_inv = inverse(a, S)
flag = ""
M = []
for c in C:
m_i = ((c - b) % S) * a_inv % S
M.append(m_i)
seg_bytes = long_to_bytes(m_i)
original_char = chr(seg_bytes[0])
flag += original_char
print(flag)
#flag{s1gn_1n_t0geth5r_xixi}
where
题目:
1 | from Crypto.Util.number import * |
output.txt太长了就不放出来了,想要的师傅可以去hscctf的靶场下载(虽然可能还没更新)
解题思路:
一个小decision:1
20: c_i为mod(n)的随机数
1: c_i为65537 + x*(1-x) +(q - x)*y + (y + x)*(q + x) --> 65537 + qx + 2qy + x
我们可以发现对于1的方程模q下,会有一个80bit的小根x,所以copper会有解,而0则没有,所以我们可以以此做出decision
exp:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#sage
from Crypto.Util.number import *
n =
c =
flag = ""
PR.<x> = PolynomialRing(Zmod(n))
for i in range(len(c)):
f = x - c[i]
res = f.small_roots(X=2^80,beta=0.49)
if(res != []):
flag += "1"
else:
flag += "0"
print(long_to_bytes(int(flag,2)))
#flag{where_1s_th5_flag_where}
stillRSA
题目:
1 | from Crypto.Util.number import * |
解题思路:
可以观察到这是一个双重RSA:
- p1是一个128位的素数,p2和q2是一个512位的素数
- s是q2的低56位
- q1 = 2 * p1 + s
- r1 = 2 * q1 + s
- 已知 $n_1$ 和 $p_1$,且 $q_1$、$r_1$ 均与 $p_1$ 相关,可在 $\mod(n_1 // p_1)$ 下通过 Copper 算法求解 $s$,进而还原 $q_1$ 和 $r_1$;
- 已知 $gift = p_2 >> 262$,且 $s$ 为 $q_2$ 的低 56 位,可通过以下方式还原 $p_2$ 的低 56 位:
$n_2 \times \text{inverse}(s, 2^{56}) \mod 2^{56}$ - 基于上述结果,再次通过 Copper 算法还原 $p_2$;
- 最终分别解两个 RSA 即可完成解题。
exp:
1 | #sage |
EZRSA
题目:
1 | from Crypto.Util.number import * |
我们可以发现:
- 先生成256位的素数s
- p由256位的s,通过0变成10,1变成01的方式拓展成的512位的素数,其中首两位是11
- q是前128的s+128位的1+后128位的s+128位的1得到的
解题思路:
很明显是一个剪枝问题,按照生成方式约束一下深搜即可
exp: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#python
from Crypto.Util.number import *
nbit = 256
e = 65537
n = 97500437901440388417198788454954892885829765317271438600836638419723842224011100091990654907349042873594131382232421640267091732569264390052236076620148372084122607139079558728860385251369576795723604753566616558793072715394596559965112752835650808765911364805382628147988309718393764596614456741590220757591
c = 7738615614182124736230909980262535479827406389377664909203540758689122759528168600427345931034997504030657746278863273550729288326235414854206217548620396163736109673531409510422631464901846302450760457216706035370273167926580473904029057693564485585891556568420324605915383565319685765532478198539656924536
def dfs(h, s_prefix, p_prefix):
p_remain = 2 * nbit - len(p_prefix)
p_max = int(p_prefix + "1" * p_remain, 2)
p_min = int(p_prefix + "0" * p_remain, 2)
s_half = nbit // 2
s_len = len(s_prefix)
s_remain = nbit - s_len
if s_len <= s_half:
q_pre0 = (s_prefix + "0" * (s_half - s_len)
+ "1" * s_half
+ "0" * s_half
+ "1" * s_half)
q_pre1 = (s_prefix + "1" * (s_half - s_len)
+ "1" * s_half
+ "1" * s_half
+ "1" * s_half)
else:
s_pre128 = s_prefix[:s_half]
s_suf_cur = s_prefix[s_half:]
q_pre0 = (s_pre128 + "1" * s_half
+ s_suf_cur + "0" * (s_half - (s_len - s_half))
+ "1" * s_half)
q_pre1 = (s_pre128 + "1" * s_half
+ s_suf_cur + "1" * (s_half - (s_len - s_half))
+ "1" * s_half)
q_max = int(q_pre1, 2)
q_min = int(q_pre0, 2)
if q_max * p_max < n or q_min * p_min > n:
return
if h == nbit:
p = p_max
q = int(s_prefix[:s_half] + "1" * s_half + s_prefix[s_half:] + "1" * s_half, 2)
if p * q != n:
return
if isPrime(p) and isPrime(q):
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
flag = long_to_bytes(pow(c, d, n))
print(f"flag: {flag.decode()}")
print(f"p = {p}")
print(f"q = {q}")
exit()
return
dfs(h + 1, s_prefix + "0", p_prefix + "10")
dfs(h + 1, s_prefix + "1", p_prefix + "01")
dfs(1, s_prefix="1", p_prefix="11")
#flag{n1ce_th1s_RSA_I_can_do_it}
abg
题目:
1 | from Crypto.Util.number import * |
解题思路:
其实就是很直白的ECC+RSA,其中flag本质上是被RSA加密了,其中隐藏了加密指数为ECC上的一个点s的横纵坐标之差的绝对值
虽然没有给出abg,但是给出了四个点L, s1, s2, K,所以我们可以通过任意取两个点有:
之后我们可以通过$gcd(k_1, k_2)$再消除一些小因子来得到g,之后再还原a和b
又因为给出了,根据费马小定理我们可以得到
所以我们可以通过$gcd(gift-1, n)$来得到p,之后解RSA即可
exp: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#sage
from Crypto.Util.number import *
L = (5612832632021037413595021905856059690922175615680426850888866965067320107819, 44286844991960812568914524464365492264373223903614475371204877844888511445056)
s1 = (3105425529931638108939225244969805843864193431777172585017902596003213488900, 21204057924591170352686471525538286905154747896755584173932333298433282086561)
s2 = (17163600514231693116809112204202083823354850361231568034507586407851022654385, 54523130652066750636213932541583111123904814992668862332727980305098543395332)
K = (84626796737477467367556465702814556148204747766624017939626441693356336891461, 20412858373065309258609569831347478221615957387864164638932871773748933195219)
enc = 77779248799562415787538731320739960822457760506615718084036279480880899171418681853821326436404494983875803921684003465855970542931724878457768817162166413967384579329072032251210520838992258491716245608876204830909672245330785235016998427930933850050898878548191256398496024681498083646200326639489612460844
gift = 27203859362379532209762716293585970661584968016465564915669656593570376250661463300469214869975225133883120425672896040102408082124157996563344160198308488970094544684114508100388704667496464400261830996514109943777210955076236899363247079300339008914936852187908757699066223721473477803084358704291887973927
n = 99350851709648177478181442570691890135193362203180628334780894515389735176666242281991349782055218048443285160186921692026870729324336754641181928398906259668775047724023372863155472201773397077316170491389813660679924150036914095032544796724427607899057109320556570067643629947815982002736525967748207154359
temp1 = (s2[1] ** 2 - s1[1] ** 2 - s2[0] ** 3 + s1[0] ** 3)
temp2 = (L[1] ** 2 - s2[1] ** 2 - L[0] ** 3 + s2[0] ** 3)
temp3 = (K[1] ** 2 - L[1] ** 2 - K[0] ** 3 + L[0] ** 3)
k1g = temp1 * (L[0] - s2[0]) - temp2 * (s2[0] - s1[0])
k2g = temp2 * (K[0] - L[0]) - temp3 * (L[0] - s2[0])
k3g = temp1 * (K[0] - L[0]) - temp3 * (s2[0] - s1[0])
g = GCD(k1g, k2g)
g = GCD(g, k3g)
for i in range(2,1000):
while(g % i == 0):
g //= i
a = inverse(s2[0]-s1[0],g)*temp1 % g
b = (s1[1] ** 2 - s1[0]**3-a*s1[0]) % g
E = EllipticCurve(GF(g),[a,b])
L = E(L)
s1 = E(s1)
s2 = E(s2)
base = L
k = 0
for j in range(2, 1000000):
base += L
if (s1 - base) * j == s2:
k = j
break
assert (s1 - k * L) * j == s2
s = s1 - k * L
e = abs(int(s[0] - s[1]))
p = GCD((gift - 1), n)
q = n // p
d = inverse(e, (p-1)*(q-1))
m = pow(enc, d, n)
print(long_to_bytes(int(m)))
#flag{this_1s_a_so_EZ_Ecc_and_RSA_}
math
题目:
1 | from Crypto.Util.number import * |
解题思路:
题目把两个随机数m1,m2表示为:
因为 $p \equiv -1 \pmod{p+1}$
那么m可以表示为:
那么就有 $m + sum = k*p$,所以只需要求一下gcd即可,由于给出的sum//2025,可能会有误差还原的时候还需要进行一下小爆破即可
exp: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#python
from Crypto.Util.number import *
from tqdm import *
m1 = 17322548249387769406385507000191215801044910756841784387283679508067232037647009879640247663005640315645559929483973978388785385751219073137080976227046261663059832428571101292873255962114141666488474602734594597852331665601154571683480014721045567844719377268571343706508041194359642732322649799872642255094259428635455750138217286588825326703937255171250131117864604764478573786940615096044575610751081788573681131616312486987096717266320380202191909867687322859634487150465591581523036586129341984826904474237818210411872793917742756628712320922128969576851582027757934655202892557206052328142121974846460835879379
m2 = 29770749505949559271464509877642735633388289947852331255230201935471628731047838190019590503471311260422939188831886032391799282413808339483805109656799786202448656409753608524222447399741340441803183979217817801933166848028113568228217090419247166878248450792302177597130681740006379413412297487888656975884867850858832779733076818160854085244264177562471933684902341628858046181331683501978826962693104997686104748486850900546849316714934730338449894336151567737740558472664876717516650156395237362632196760323299658988296623556674223583771795447537227301625104687705109034611911834940501083977979641467845119043780
sum1 = -108877560874638575191632670246326227208412819991287356983577291185528002487
sum2 = -47122048431044787786292644180145597499319125719652288525187634667738055282
n = 9020951256034058214321622067945640395058903219618790136239198219605516437223449048642101160150934286238922049363203171871230111420670637737169565825694393
c = 3323425622556846027480153848276857423081641901016156494250966280342935316300495906916254739461788219592704051961044937129981786472345610933524261214506540
e = 65537
for i in trange(2025):
for j in range(2025):
sum1_ = sum1*2025+i
sum2_ = sum2*2025+j
kp = GCD(m1 + sum1_, m2 + sum2_)
if kp > 2 ** 255:
for k in range(1, 10000):
if (kp % k == 0):
p = kp // k - 1
if (isPrime(p) and len(bin(p)[2:]) == 256):
q = n // p
d = inverse(e, (p - 1) * (q - 1))
print(long_to_bytes(pow(c, d, n)))
break
#flag{Reverse_Sum_Mod_p+i_GCD_2025!}
1ZRSA
题目:
1 | from Crypto.Util.number import * |
output.txt太长了就不放出来了,想要的师傅可以去hscctf的靶场下载(虽然可能还没更新)
有空再补