2023.10.30ACTF

2023ACTF

2023ACTF 哒!

马上要打ACTF了,来看看之前的ACTF,题目和exp都来自糖醋小鸡块

EasyRSA

EasyRSA

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
78
from secret import flag
from Crypto.Util.number import *


def genKey(nbits, dbits):
bbits = (nbits // 2 - dbits) // 2

while True:
a = getRandomNBitInteger(dbits)
b = getRandomNBitInteger(bbits)
c = getRandomNBitInteger(bbits)
p1 = a * b * c + 1
if isPrime(p1):
# print("p1 =", p1)
break

while True:
d = getRandomNBitInteger(dbits)
p2 = b * c * d + 1
if isPrime(p2):
# print("p2 =", p2)
break

while True:
e = getRandomNBitInteger(bbits)
f = getRandomNBitInteger(bbits)
q1 = e * d * f + 1
p3 = a * e * f + 1
if isPrime(q1) and isPrime(p3):
# print("p3 =", p3)
# print("q1 =", q1)
break

while True:
d_ = getRandomNBitInteger(dbits)
if GCD(a * b * c * d * e * f, d_) != 1:
continue
e_ = inverse(d_, a * b * c * d * e * f)
k1 = (e_ * d_ - 1) // (a * b * c * d * e * f)
assert e_ * d_ == (a * b * c * d * e * f) * k1 + 1
q2 = k1 * e * f + 1
q3 = k1 * b * c + 1
if isPrime(q2) and isPrime(q3):
# print("q2 =", q2)
# print("q3 =", q3)
# print("e =", e_)
# print("d =", d_)
break

n1 = p1 * q1
n2 = p2 * q2
n3 = p3 * q3

assert pow(pow(0xdeadbeef, e_, n1), d_, n1) == 0xdeadbeef
assert pow(pow(0xdeadbeef, e_, n2), d_, n2) == 0xdeadbeef
assert pow(pow(0xdeadbeef, e_, n3), d_, n3) == 0xdeadbeef

return(e_, n1, n2, n3)


nbits = 0x600
dbits = 0x210

m = bytes_to_long(flag)
e, n1, n2, n3 = genKey(nbits, dbits)
c = pow(m, e, n1)

print("c =", c)
print("e =", e)
print("n1 =", n1)
print("n2 =", n2)
print("n3 =", n3)

# c = 63442255298812942222810837512019302954917822996915527697525497640413662503768308023517128481053593562877494934841788054865410798751447333551319775025362132176942795107214528962480350398519459474033659025815248579631003928932688495682277210240277909527931445899728273182691941548330126199931886748296031014210795428593631253184315074234352536885430181103986084755140024577780815130067722355861473639612699372152970688687877075365330095265612016350599320999156644
# e = 272785315258275494478303901715994595013215169713087273945370833673873860340153367010424559026764907254821416435761617347240970711252213646287464416524071944646705551816941437389777294159359383356817408302841561284559712640940354294840597133394851851877857751302209309529938795265777557840238332937938235024502686737802184255165075195042860413556866222562167425361146312096189555572705076252573222261842045286782816083933952875990572937346408235562417656218440227
# n1 = 473173031410877037287927970398347001343136400938581274026578368211539730987889738033351265663756061524526288423355193643110804217683860550767181983527932872361546531994961481442866335447011683462904976896894011884907968495626837219900141842587071512040734664898328709989285205714628355052565784162841441867556282849760230635164284802614010844226671736675222842060257156860013384955769045790763119616939897544697150710631300004180868397245728064351907334273953201
# n2 = 327163771871802208683424470007561712270872666244394076667663345333853591836596054597471607916850284565474732679392694515656845653581599800514388800663813830528483334021178531162556250468743461443904645773493383915711571062775922446922917130005772040139744330987272549252540089872170217864935146429898458644025927741607569303966038195226388964722300472005107075179204987774627759625183739199425329481632596633992804636690274844290983438078815836605603147141262181
# n3 = 442893163857502334109676162774199722362644200933618691728267162172376730137502879609506615568680508257973678725536472848428042122350184530077765734033425406055810373669798840851851090476687785235612051747082232947418290952863499263547598032467577778461061567081620676910480684540883879257518083587862219344609851852177109722186714811329766477552794034774928983660538381764930765795290189612024799300768559485810526074992569676241537503405494203262336327709010421
PYTHON

花里胡哨看n的构造特殊,还在想会不会是什么特别的方法,然后小鸡块共享私钥攻击秒了…
以后多考虑这方面吧
具体原理很简单,可以直接看小鸡块的博客

常数K数量级差不多即可
贴一下小鸡块的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Util.number import *

nbits = 0x600
dbits = 0x210
c = 63442255298812942222810837512019302954917822996915527697525497640413662503768308023517128481053593562877494934841788054865410798751447333551319775025362132176942795107214528962480350398519459474033659025815248579631003928932688495682277210240277909527931445899728273182691941548330126199931886748296031014210795428593631253184315074234352536885430181103986084755140024577780815130067722355861473639612699372152970688687877075365330095265612016350599320999156644
e = 272785315258275494478303901715994595013215169713087273945370833673873860340153367010424559026764907254821416435761617347240970711252213646287464416524071944646705551816941437389777294159359383356817408302841561284559712640940354294840597133394851851877857751302209309529938795265777557840238332937938235024502686737802184255165075195042860413556866222562167425361146312096189555572705076252573222261842045286782816083933952875990572937346408235562417656218440227
n1 = 473173031410877037287927970398347001343136400938581274026578368211539730987889738033351265663756061524526288423355193643110804217683860550767181983527932872361546531994961481442866335447011683462904976896894011884907968495626837219900141842587071512040734664898328709989285205714628355052565784162841441867556282849760230635164284802614010844226671736675222842060257156860013384955769045790763119616939897544697150710631300004180868397245728064351907334273953201
n2 = 327163771871802208683424470007561712270872666244394076667663345333853591836596054597471607916850284565474732679392694515656845653581599800514388800663813830528483334021178531162556250468743461443904645773493383915711571062775922446922917130005772040139744330987272549252540089872170217864935146429898458644025927741607569303966038195226388964722300472005107075179204987774627759625183739199425329481632596633992804636690274844290983438078815836605603147141262181
n3 = 442893163857502334109676162774199722362644200933618691728267162172376730137502879609506615568680508257973678725536472848428042122350184530077765734033425406055810373669798840851851090476687785235612051747082232947418290952863499263547598032467577778461061567081620676910480684540883879257518083587862219344609851852177109722186714811329766477552794034774928983660538381764930765795290189612024799300768559485810526074992569676241537503405494203262336327709010421

K = 2^(nbits//2)
L = matrix(ZZ,4,4)
L[0]=[K,e,e,e]
L[1]=[0,-n1,0,0]
L[2]=[0,0,-n2,0]
L[3]=[0,0,0,-n3]

res=L.LLL()[0]
d = abs(res[0])//K

print(long_to_bytes(int(pow(c,d,n1))))

#ACTF{5FFC427B-F14F-DCA0-C425-675B149890C2}
SAGE

MDH

Malin’s Diffile-Hellman Key Exchange.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from hashlib import sha256
from secret import flag

r = 128
c = 96
p = 308955606868885551120230861462612873078105583047156930179459717798715109629
Fp = GF(p)

def gen():
a1 = random_matrix(Fp, r, c)
a2 = random_matrix(Fp, r, c)
A = a1 * a2.T
return (a1, a2), A

sk_alice, pk_alice = gen()
sk_bob, pk_bob = gen()
shared = (sk_alice[0].T * pk_bob * sk_alice[1]).trace()
ct = int(sha256(str(int(shared)).encode()).hexdigest(), 16) ^^ int.from_bytes(flag, 'big')

with open('output.txt', 'wb') as f:
f.write(str(ct).encode() + b'\n')
f.write(str(list(pk_alice)).encode() + b'\n')
f.write(str(list(pk_bob)).encode() + b'\n')
PYTHON

这题用到了矩阵的迹的性质
shared是alice的2个私钥和bob的公钥的乘积的迹
而alice的公钥是a1 * a2.T
矩阵的迹的性质:行列转置不影响矩阵的迹
也就是说pk_alice.trace()==(sk_alice[0]*sk_alice[1].T)==(sk_alice[0].T*sk_alice[1])
所以shared就很容易求出来了

小鸡块的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from hashlib import sha256
from Crypto.Util.number import *

p = 308955606868885551120230861462612873078105583047156930179459717798715109629
c = 8308943029741424587523612386337754255889681699670071706719724435165094611096603769021839263
A =
B =

A = matrix(GF(p),A)
B = matrix(GF(p),B)
A = A.transpose()

shared = (A*B).trace()
m = c ^^ int(sha256(str(int(shared)).encode()).hexdigest(), 16)
print(long_to_bytes(m))

#ACTF{do_you_know_f0rm2l1n_1s_4w3s0m3!}
SAGE

MidRSA

MidRSA

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
78
79
from secret import flag
from Crypto.Util.number import *


def genKey(nbits, dbits):
bbits = (nbits // 2 - dbits) // 2

while True:
a = getRandomNBitInteger(dbits)
b = getRandomNBitInteger(bbits)
c = getRandomNBitInteger(bbits)
p1 = a * b * c + 1
if isPrime(p1):
# print("p1 =", p1)
break

while True:
d = getRandomNBitInteger(dbits)
p2 = b * c * d + 1
if isPrime(p2):
# print("p2 =", p2)
break

while True:
e = getRandomNBitInteger(bbits)
f = getRandomNBitInteger(bbits)
q1 = e * d * f + 1
p3 = a * e * f + 1
if isPrime(q1) and isPrime(p3):
# print("p3 =", p3)
# print("q1 =", q1)
break

while True:
d_ = getRandomNBitInteger(dbits)
if GCD(a * b * c * d * e * f, d_) != 1:
continue
e_ = inverse(d_, a * b * c * d * e * f)
k1 = (e_ * d_ - 1) // (a * b * c * d * e * f)
assert e_ * d_ == (a * b * c * d * e * f) * k1 + 1
q2 = k1 * e * f + 1
q3 = k1 * b * c + 1
if isPrime(q2) and isPrime(q3):
# print("q2 =", q2)
# print("q3 =", q3)
# print("e =", e_)
print("d =", d_)
break

n1 = p1 * q1
n2 = p2 * q2
n3 = p3 * q3

assert pow(pow(0xdeadbeef, e_, n1), d_, n1) == 0xdeadbeef
assert pow(pow(0xdeadbeef, e_, n2), d_, n2) == 0xdeadbeef
assert pow(pow(0xdeadbeef, e_, n3), d_, n3) == 0xdeadbeef

return(e_, n1, n2, n3)


nbits = 0x600
dbits = 0x240

m = bytes_to_long(flag)
e, n1, n2, n3 = genKey(nbits, dbits)
c = pow(m, e, n1)

print("c =", c)
print("e =", e)
print("n1 =", n1)
print("n2 =", n2)
print("n3 =", n3)


# c = 598823083137858565473505718525815255620672892612784824187302545127574115000325539999824374357957135208478070797113625659118825530731575573239221853507638809719397849963861367352055486212696958923800593172417262351719477530809870735637329898331854130533160020420263724619225174940214193740379571953951059401685115164634005411478583529751890781498407518739069969017597521632392997743956791839564573371955246955738575593780508817401390102856295102225132502636316844
# e = 334726528702628887205076146544909357751287869200972341824248480332256143541098971600873722567713812425364296038771650383962046800505086167635487091757206238206029361844181642521606953049529231154613145553220809927001722518303114599682529196697410089598230645579658906203453435640824934159645602447676974027474924465177723434855318446073578465621382859962701578350462059764095163424218813852195709023435581237538699769359084386399099644884006684995755938605201771
# n1 = 621786427956510577894657745225233425730501124908354697121702414978035232119311662357181409283130180887720760732555757426221953950475736078765267856308595870951635246720750862259255389006679454647170476427262240270915881126875224574474706572728931213060252787326765271752969318854360970801540289807965575654629288558728966771231501959974533484678236051025940684114262451777094234017210230731492336480895879764397821363102224085859281971513276968559080593778873231
# n2 = 335133378611627373902246132362791381335635839627660359611198202073307340179794138179041524058800936207811546752188713855950891460382258433727589232119735602364790267515558352318957355100518427499530387075144776790492766973547088838586041648900788325902589777445641895775357091753360428198189998860317775077739054298868885308909495601041757108114540069950359802851809227248145281594107487276003206931533768902437356652676341735882783415106786497390475670647453821
# n3 = 220290953009399899705676642623181513318918775662713704923101352853965768389363281894663344270979715555659079125651553079702318700200824118622766698792556506368153467944348604006011828780474050012010677204862020009069971864222175380878120025727369117819196954091417740367068284457817961773989542151049465711430065838517386380261817772422927774945414543880659243592749932727798690742051285364898081188510009069286094647222933710799481899960520270189522155672272451
PYTHON

d变大了,目标向量不再是格中的最短向量,或者说目标向量的长度大于高斯启发式的近似值了。
这里记录一下我个人的观点,可能有误:

只要目标向量的长度小于高斯启发式的近似值,那么我们可以认为有很大可能可以规约出目标向量
有些自己构建的格不是那么完美,在保证结果向量中的数量级相近的前提下,无论如何更改格中的常数的值都无法让高斯启发式的近似值大于目标向量,因为高斯启发式中的k是k^(1/n)
计算高斯启发式:

1
2
3
4
5
6
def guass_Heuristic(L):
n = L.nrows()
efficient = (n/(2*math.pi*math.e))**(0.5)
return int(efficient*iroot(abs(L.det()),n)[0])

print(guass_Heuristic(L).bit_length())
SAGE

在这题中需要爆破一下d的低位。

1
2
e*d=1*k*phi(n)
e*(2^s*d_h+d_l)=1*k*phi(n)
MATH

然后借用一下小鸡块的博客:

小鸡块的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
from Crypto.Util.number import *
from tqdm import *

nbits = 0x600
dbits = 0x240

c = 598823083137858565473505718525815255620672892612784824187302545127574115000325539999824374357957135208478070797113625659118825530731575573239221853507638809719397849963861367352055486212696958923800593172417262351719477530809870735637329898331854130533160020420263724619225174940214193740379571953951059401685115164634005411478583529751890781498407518739069969017597521632392997743956791839564573371955246955738575593780508817401390102856295102225132502636316844
e = 334726528702628887205076146544909357751287869200972341824248480332256143541098971600873722567713812425364296038771650383962046800505086167635487091757206238206029361844181642521606953049529231154613145553220809927001722518303114599682529196697410089598230645579658906203453435640824934159645602447676974027474924465177723434855318446073578465621382859962701578350462059764095163424218813852195709023435581237538699769359084386399099644884006684995755938605201771
n1 = 621786427956510577894657745225233425730501124908354697121702414978035232119311662357181409283130180887720760732555757426221953950475736078765267856308595870951635246720750862259255389006679454647170476427262240270915881126875224574474706572728931213060252787326765271752969318854360970801540289807965575654629288558728966771231501959974533484678236051025940684114262451777094234017210230731492336480895879764397821363102224085859281971513276968559080593778873231
n2 = 335133378611627373902246132362791381335635839627660359611198202073307340179794138179041524058800936207811546752188713855950891460382258433727589232119735602364790267515558352318957355100518427499530387075144776790492766973547088838586041648900788325902589777445641895775357091753360428198189998860317775077739054298868885308909495601041757108114540069950359802851809227248145281594107487276003206931533768902437356652676341735882783415106786497390475670647453821
n3 = 220290953009399899705676642623181513318918775662713704923101352853965768389363281894663344270979715555659079125651553079702318700200824118622766698792556506368153467944348604006011828780474050012010677204862020009069971864222175380878120025727369117819196954091417740367068284457817961773989542151049465711430065838517386380261817772422927774945414543880659243592749932727798690742051285364898081188510009069286094647222933710799481899960520270189522155672272451

K = 2^(nbits//2)
L = matrix(ZZ,5,5)
shift = 2^16
for dl in trange(shift):
L[0]=[K*shift,shift*e,shift*e,shift*e,0 ]
L[1]=[0 ,-n1 ,0 ,0 ,0 ]
L[2]=[0 ,0 ,-n2 ,0 ,0 ]
L[3]=[0 ,0 ,0 ,-n3 ,0 ]
L[4]=[0 ,e*dl ,e*dl ,e*dl ,K*(2^dbits)]

res=L.LLL()[0]
if(res[0] > 0):
d = abs(res[0])//K + dl
else:
d = abs(res[0])//K - dl

flag = long_to_bytes(int(pow(c,d,n1)))
if(b"ACTF" in flag):
print(flag)

#ACTF{D16C46D9-77A2-2D96-CA51-4538EFB6AFF7}
SAGE

CRCRC

No desCRCiption

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
from base64 import *

def crc128(data, poly = 0x883ddfe55bba9af41f47bd6e0b0d8f8f):
crc = (1 << 128) - 1
for b in data:
crc ^= b
for _ in range(8):
crc = (crc >> 1) ^ (poly & -(crc & 1))
return crc ^ ((1 << 128) - 1)

with open('./flag.txt','r') as f:
flag = f.readline()

YourInput = input().encode()
YourDecode = b64decode(YourInput, validate=True)

print(len(YourDecode))

assert len(YourDecode) <= 127 and YourDecode.startswith(b'Dear guest, welcome to CRCRC Magic House, If you input ') and YourDecode.endswith(b", you will get 0x9c6a11fbc0e97b1fff5844fa88b1ee2d")

YourCRC = crc128(YourInput)
print(hex(YourCRC))

if(YourCRC) == 0x9c6a11fbc0e97b1fff5844fa88b1ee2d:
print(flag)
PYTHON

小鸡块的wp看不懂…
所以记录一下学到的。
对于4组任意的明文-密文对p1,c1 p2,c2 p3,c3 p4,c4,其中除p1外均已知
如果c1^c2==c3^c4,那么p1^p2==p3^p4
还有就说CRC解密脚本,只能解出一组特解,具体看小鸡块的博客吧,我是看不懂了

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
def crc128(data, poly=0x883ddfe55bba9af41f47bd6e0b0d8f8f):
crc = (1 << 128) - 1
for b in data:
crc ^^= b
for _ in range(8):
crc = (crc >> 1) ^^ (poly & -(crc & 1))
return crc ^^ ((1 << 128) - 1)

def equivalent_affine_crc(crc = crc128, crc_bits = 128, target_bytes = 16):
zero_crc = crc(target_bytes*b"\x00")
target_bits = 8 * target_bytes
v2n = lambda v: int(''.join(map(str, v)), 2)
n2v = lambda n: vector(GF(2), bin(n)[2:].zfill(crc_bits))
# n2v_t = lambda n: vector(GF(2), bin(n)[2:].zfill(target_bits))
Affine_Matrix = []
for i in range(target_bits):
v = vector(GF(2), (j == i for j in range(target_bits)))
value = crc(long_to_bytes(v2n(v),target_bytes)) ^^ zero_crc
Affine_Matrix.append(n2v(value))
# crc affine function: crc_128(x) = M*x+ C
return matrix(GF(2),Affine_Matrix).transpose(), n2v(zero_crc)

def crc_128_reverse(crc_value):
M , C = equivalent_affine_crc()
# crc affine function: crc_128(x) = M*x+ C
v2n = lambda v: int(''.join(map(str, v)), 2)
n2v = lambda n: vector(GF(2), bin(n)[2:].zfill(128))
res = M.solve_right(n2v(crc_value)+C)
return long_to_bytes(v2n(res),16)
SAGE

2023.10.30ACTF
https://bddye.github.io/2025/04/21/2023-10-30ACTF/
作者
蹦跶的鱼儿
发布于
2025年4月21日
许可协议