第三届黄河流域公安院校网络安全技能挑战赛复现

sandwich

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from Crypto.Util.number import *
import gmpy2
flag = b'flag{fake_flag}'
assert len(flag) == 39
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x3
pad1 = b'easy_problem'
pad2 = b'How_to_solve_it'
c = pow(bytes_to_long(pad1 + flag + pad2),e,n)
print(f'n = {n}')
print(f'c = {c}')

'''
n = 130210658110511504736422597261591182174531847806532340762131145212035478695205314931974421838392310731226415266775095601890938846830080329061111533796518633011922277343217149648494987341818402753017296362015915834670450122261511337212801488239810623226740266516836721952886027130703886460578247562781194524199
c = 58274335440051115211211273605191310114692293785750437685473044454042062899661976407492451518086227780147882738264722645944582899451063113444881286175099872016956825274378613983870549046907444680021237171113596116147511706486372974792692071549068969896395366667516390709069131700584308236332248449116109156503
'''

部分已知信息打copper flag的长度为39,开头的‘flag{’为5字节已知,结尾‘}’1字节已知,中间33字节未知,并且pad1填充了12位,pad2填充了15位,实际上是在66位长度下打33位未知m的copper攻击

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

n = 130210658110511504736422597261591182174531847806532340762131145212035478695205314931974421838392310731226415266775095601890938846830080329061111533796518633011922277343217149648494987341818402753017296362015915834670450122261511337212801488239810623226740266516836721952886027130703886460578247562781194524199
c = 58274335440051115211211273605191310114692293785750437685473044454042062899661976407492451518086227780147882738264722645944582899451063113444881286175099872016956825274378613983870549046907444680021237171113596116147511706486372974792692071549068969896395366667516390709069131700584308236332248449116109156503
pad1 = b'easy_problem'
pad2 = b'How_to_solve_it'
m_high = bytes_to_long(pad1 + b'flag{' + b'\x00'*33 + b'}' + pad2)

R.<x> = PolynomialRing(Zmod(n))
#末尾的1为flag的结尾填充'}'
f = (m_high + x * 256^(len(pad2) + 1))^3 - c
f = f.monic()
res = f.small_roots(X=256**33,beta=0.49,epsilon=0.01)

print(b'flag{'+long_to_bytes(int(res[0]))+b'}')
# flag{A_C0pper5mi1tH_4Ues7iOn_SplIt_Pad}

因式分解

题目

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
from Crypto.Util.number import *
from Crypto.Util.number import *
from gmpy2 import*
from secret import flag,a,b,c

m = bytes_to_long(flag)
p = getPrime(256)
q = getPrime(256)
n = p * q
e = 65537
_q = int(bin(q)[2:][::-1] , 2)
c = pow(m,e,n)

print('n =',n)
print('c =',c)

'''
n = 7688109450918412752403544831281002390909833419780604228031807748258766149305710928557842935597759373483911172486806200079137977020089610947423466744079981
c = 6470273779347221033316093386019083111753019159457126878637258794718443144439812725263309232245307744208957171971247518708231996986359926490571921925899978
'''

assert a**3+b**3+c**3 == 3*a*b*c
gift = secert**3 - 9*secert + 8
print(gift)

assert 3*(p ^ _q) == a + b + c

#16174454302590604301534105361719250538317088773024913985896374029052621214070408075926265229111851489902642328975085914458074453963086159246933939207642987161923181946601656883349077418380372857072224674380642689142603970810010050
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import string

from secret import hint
from secret import encrypt

import random

dicts = string.ascii_lowercase +"{=}"

key = (''.join([random.choice(dicts) for i in range(4)])) * 8

assert(len(hint) == 32)

assert(len(key) == 32)


cipher = encrypt(hint, key) #Vigenere

print(cipher)

# cp=wmaunapgimjfpopeblvup=aywqygb
先把hint解出来,维吉尼亚爆破,但是是多了’{,=,}’并且key和hint的长度均为32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import string
import itertools

dicts = string.ascii_lowercase + "{=}"

enc = 'cp=wmaunapgimjfpopeblvup=aywqygb'

for k in itertools.product(dicts, repeat=4):
key = ''.join(k)
key=key*8
print(key)
numenc = [dicts.index(i) for i in enc]
numkey = [dicts.index(i) for i in key]
flag = ''
for i in range(len(enc)):
# assert len(numenc) == len(numkey)
ans = (numenc[i] - numkey[i % 4]) % 29
flag += dicts[ans]

if 'secret' in flag:
print(flag)
break
#tellasecret{a=secert}keepsilentt
第二段
1
2
3
assert a**3+b**3+c**3 == 3*a*b*c
gift = secert**3 - 9*secert + 8
print(gift)
直接用sagemath解这个方程
1
2
3
4
5
6
7
8
9
10
11
12
gift = 16174454302590604301534105361719250538317088773024913985896374029052621214070408075926265229111851489902642328975085914458074453963086159246933939207642987161923181946601656883349077418380372857072224674380642689142603970810010050
var('t')
f = a^3 - 9*a + 8 - gift
res = solve([f],[t])
print(res)
'''
[
t == -I*sqrt(479675667122028192327307598929249450109555498652389081855962114336125186835432726261488440976511535706065147589710878075747126062261808231937972111506698) - 12644836457648476210643410284347264244894171176836870123994247554995746446663,
t == I*sqrt(479675667122028192327307598929249450109555498652389081855962114336125186835432726261488440976511535706065147589710878075747126062261808231937972111506698) - 12644836457648476210643410284347264244894171176836870123994247554995746446663,
t == 25289672915296952421286820568694528489788342353673740247988495109991492893326
]
'''
然后变形式子 a3 + b3 + c3 = 3abc 变形后得到 (a + b + c)(a² + b² + c² − ab − ac − bc) = 0 因为 (a+b+c) 不为0,所以我们有 (a² + b² + c² − ab − ac − bc) = 0 再次变形 因此我们可以得到a=b=c 所以 (pxorq) =  = a 然后就是首尾剪枝
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
from Crypto.Util.number import *
import sys
sys.setrecursionlimit(1500)

pxorq = 25289672915296952421286820568694528489788342353673740247988495109991492893326
n = 7688109450918412752403544831281002390909833419780604228031807748258766149305710928557842935597759373483911172486806200079137977020089610947423466744079981
c = 6470273779347221033316093386019083111753019159457126878637258794718443144439812725263309232245307744208957171971247518708231996986359926490571921925899978
e = 65537
leak_bits = 256
pxorq = str(bin(pxorq)[2:]).zfill(leak_bits)

def find(ph,qh,pl,ql):
l = len(ph)
tmp0 = ph + (leak_bits-2*l)*"0" + pl
tmp1 = ph + (leak_bits-2*l)*"1" + pl
tmq0 = qh + (leak_bits-2*l)*"0" + ql
tmq1 = qh + (leak_bits-2*l)*"1" + ql
if(int(tmp0,2)*int(tmq0,2) > n):
return
if(int(tmp1,2)*int(tmq1,2) < n):
return
if(int(pl,2)*int(ql,2) % (2**(l-1)) != n % (2**(l-1))):
return

if(l == 128):
pp0 = int(tmp0,2)
if(n % pp0 == 0):
pf = pp0
qf = n//pp0
phi = (pf-1)*(qf-1)
d = inverse(e,phi)
m1 = pow(c,d,n)
print(long_to_bytes(m1))
exit()

else:
if(pxorq[l] == "1" and pxorq[255-l] == "1"):
find(ph+"1",qh+"0","1"+pl,"0"+ql)
find(ph+"0",qh+"0","1"+pl,"1"+ql)
find(ph+"1",qh+"1","0"+pl,"0"+ql)
find(ph+"0",qh+"1","0"+pl,"1"+ql)
elif(pxorq[l] == "1" and pxorq[255-l] == "0"):
find(ph+"1",qh+"0","0"+pl,"0"+ql)
find(ph+"0",qh+"0","0"+pl,"1"+ql)
find(ph+"1",qh+"1","1"+pl,"0"+ql)
find(ph+"0",qh+"1","1"+pl,"1"+ql)
elif(pxorq[l] == "0" and pxorq[255-l] == "1"):
find(ph+"0",qh+"0","1"+pl,"0"+ql)
find(ph+"0",qh+"1","0"+pl,"0"+ql)
find(ph+"1",qh+"0","1"+pl,"1"+ql)
find(ph+"1",qh+"1","0"+pl,"1"+ql)
elif(pxorq[l] == "0" and pxorq[255-l] == "0"):
find(ph+"0",qh+"0","0"+pl,"0"+ql)
find(ph+"1",qh+"0","0"+pl,"1"+ql)
find(ph+"0",qh+"1","1"+pl,"0"+ql)
find(ph+"1",qh+"1","1"+pl,"1"+ql)

find("1","1","1","1")
#b'flag{80a59062-9bbf-99a3-6af0-a24e94032163}'