想说的一些话:
medium的题,可以说是群魔乱舞,难度波动很大,有个别题我觉得能够放进tough里面的,但整体来说,难度还是中规中矩的,本篇文章包括其中四道,medium我将分为三篇写完,肝肝肝!(
•̀ ω •́ )✧。欢迎师傅们一起来讨论学习。
medium
Derik (73 solves)
附件代码
Derik.py
from Crypto.Util.number import *
from secret import C, e, d, p, q, r, flag
O = [1391526622949983, 2848691279889518, 89200900157319, 31337]
assert isPrime(e) and isPrime(d) and isPrime(p) and isPrime(q) and isPrime(r)
assert C[0] * p - C[1] * q >= 0
assert C[2] * q - C[3] * r >= 0
assert C[4] * r - C[5] * p >= 0
assert (C[0] * p - C[1] * q) ** e + (C[2] * q - C[3] * r) ** e + (C[4] * r - C[5] * p) ** e == d * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * (C[4] * r - C[5] * p)
assert C[6] * e - C[7] * d == O[3]
n = e * d * p * q * r
m = bytes_to_long(flag)
c = pow(m, 65537, n)
print(f'C = {C}')
print(f'c = {c}')
outpu.txt
C = [5960650533801939766973431801711817334521794480800845853788489396583576739362531091881299990317357532712965991685855356736023156123272639095501827949743772, 6521307334196962312588683933194431457121496634106944587943458360009084052009954473233805656430247044180398241991916007097053259167347016989949709567530079, 1974144590530162761749719653512492399674271448426179161347522113979158665904709425021321314572814344781742306475435350045259668002944094011342611452228289, 2613994669316609213059728351496129310385706729636898358367479603483933513667486946164472738443484347294444234222189837370548518512002145671578950835894451, 8127380985210701021743355783483366664759506587061015828343032669060653534242331741280215982865084745259496501567264419306697788067646135512747952351628613, 5610271406291656026350079703507496574797593266125358942992954619413518379131260031910808827754539354830563482514244310277292686031300804846114623378588204, 10543, 4]
c = 80607532565510116966388633842290576008441185412513199071132245517888982730482694498575603226192340250444218146275844981580541820190393565327655055810841864715587561905777565790204415381897361016717820490400344469662479972681922265843907711283466105388820804099348169127917445858990935539611525002789966360469324052731259957798534960845391898385316664884009395500706952606508518095360995300436595374193777531503846662413864377535617876584843281151030183895735511854
我的理解
题目中给出了多个未知数据以及对这些未知数据的多个满足条件,并且从这些数据中生成一个公钥n,对flag进行rsa加密,我们要从这些满足条件中分析出未知数据的特征并且得到这些数,然后从而对flag进行解密。
我的方法
已知条件
assert isPrime(e) and isPrime(d) and isPrime(p) and isPrime(q) and isPrime(r)
assert C[0] * p - C[1] * q >= 0
assert C[2] * q - C[3] * r >= 0
assert C[4] * r - C[5] * p >= 0
assert (C[0] * p - C[1] * q) ** e + (C[2] * q - C[3] * r) ** e + (C[4] * r - C[5] * p) ** e == d * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * (C[4] * r - C[5] * p)
assert C[6] * e - C[7] * d == O[3]
p,q,r满足三个不等式,先对这三个数进行关系整合
q
∗
C
2
C
4
C
3
C
5
>
=
p
>
=
q
∗
C
1
C
0
r
∗
C
4
C
0
C
5
C
1
>
=
q
>
=
r
∗
C
3
C
2
q *\frac{C_2C_4}{C_3C_5}>=p>= q* \frac{C_1}{C_0} \\ r *\frac{C_4C_0}{C_5C_1}>=q>= r* \frac{C_3}{C_2}
q∗C3C5C2C4>=p>=q∗C0C1r∗C5C1C4C0>=q>=r∗C2C3
x1,x2,x3=C[1]/C[0],C[3]/C[2],C[5]/C[4]
print(1/(x2*x3),x1)
print(1/x2,x1*x3)
# 1.0940596663427293 1.0940596663427293
# 0.7552213528600171 0.7552213528600171
这里根据输出结果,我判断
p
=
q
∗
C
1
C
0
p = q* \frac{C_1}{C_0}
p=q∗C0C1
此时我的想法
自然而然的联想到用连分数求出p,q,并且通过isPrime函数 来获得p,q的
c = continued_fraction(x1)
p=[]
for i in tqdm(range(1, 1000)):#适当的对200进行调参
x1=c.numerator(i)
x2=c.denominator(i)
if is_prime(x1),is_prime(x2):
print(x1,x2,sep='\n')
然而跑完了之后发现,到后面的结果是完全一样的,根本跑不出来分子分母都是素数满足这个条件的😭,此时想到前面的,由于python的精度问题(只有小数点后20位),前面判断出来的
p
=
q
∗
C
1
C
0
p = q* \frac{C_1}{C_0}
p=q∗C0C1是错误的,应该是
C
0
p
−
C
1
q
=
x
C_0p-C_1q=x
C0p−C1q=x后续的,(q,r),(r,p)应该也是如此,联想到题目上给出的信息有一个O,O列表还有前面三个数据没有用到,这里将其他三个数据作为x加入限制条件
C
0
p
−
C
1
q
=
O
0
C
2
q
−
C
3
r
=
O
1
C
4
r
−
C
5
p
=
O
2
C_0p-C_1q=O_0 \\C_2q-C_3r=O_1 \\C_4r-C_5p=O_2
C0p−C1q=O0C2q−C3r=O1C4r−C5p=O2
可由z3解出p,q,r
而根据后两个条件
assert (C[0] * p - C[1] * q) ** e + (C[2] * q - C[3] * r) ** e + (C[4] * r - C[5] * p) ** e == d * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * (C[4] * r - C[5] * p)
assert C[6] * e - C[7] * d == O[3](1)
判断e,d
e作为幂次数,e,d为素数,且C[6],C[7]以及O[3]的值都已知,判断e,d的值不会大于100,
若设
(
C
0
p
−
C
1
q
)
b
i
t
=
x
=
>
x
∗
e
≈
d
b
i
t
+
x
∗
3
(C_0p-C_1q)_{bit}=x \\ =>x*e\approx d_{bit}+x*3
(C0p−C1q)bit=x=>x∗e≈dbit+x∗3
由此,可以判断e不会大于5,使得范围限制的更小
进行爆破限制条件求出即可。
我的代码
# !/usr/bin/env python3.10
# -*- coding: utf-8 -*-
# @Time : 2023/7/19 12:50
# @Author : lingfeng
# @File : wp1.py
# !/usr/bin/env python3.10
C = [5960650533801939766973431801711817334521794480800845853788489396583576739362531091881299990317357532712965991685855356736023156123272639095501827949743772, 6521307334196962312588683933194431457121496634106944587943458360009084052009954473233805656430247044180398241991916007097053259167347016989949709567530079, 1974144590530162761749719653512492399674271448426179161347522113979158665904709425021321314572814344781742306475435350045259668002944094011342611452228289, 2613994669316609213059728351496129310385706729636898358367479603483933513667486946164472738443484347294444234222189837370548518512002145671578950835894451, 8127380985210701021743355783483366664759506587061015828343032669060653534242331741280215982865084745259496501567264419306697788067646135512747952351628613, 5610271406291656026350079703507496574797593266125358942992954619413518379131260031910808827754539354830563482514244310277292686031300804846114623378588204, 10543, 4]
O = [1391526622949983, 2848691279889518, 89200900157319, 31337]
#1575463374671586470514676935072270631785513002340974445784539979767592122717041521896781546095608062082673920606747673209912181694260065042597
c = 80607532565510116966388633842290576008441185412513199071132245517888982730482694498575603226192340250444218146275844981580541820190393565327655055810841864715587561905777565790204415381897361016717820490400344469662479972681922265843907711283466105388820804099348169127917445858990935539611525002789966360469324052731259957798534960845391898385316664884009395500706952606508518095360995300436595374193777531503846662413864377535617876584843281151030183895735511854
from tqdm import *
from Crypto.Util.number import *
E=[2,3,5]
D=[(e,(C[6] * e -O[3])//(C[7])) for e in E if (C[6] * e -O[3])%(C[7])==0]
# print(D)#[(3, 73)]
e_,d_=3,73
from z3 import *
p,q,r=Ints('p q r')
s=Solver()
s.add(p>0)
s.add(q>0)
s.add(r>0)
s.add(C[0] * p - C[1] * q == O[0])
s.add(C[2] * q - C[3] * r == O[1])
s.add(C[4] * r - C[5] * p == O[2])
s.add((C[0] * p - C[1] * q) ** e_ + (C[2] * q - C[3] * r) ** e_ + (C[4] * r - C[5] * p) ** e_ == d_ * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * (C[4] * r - C[5] * p))
if s.check()==sat:
m=s.model()
p=m[p].as_long()
q=m[q].as_long()
r=m[r].as_long()
#print(f"p={p}\nq={q}\nr={r}")
d = inverse(65537, (e_ - 1) * (d_ - 1) * (r - 1) * (p - 1) * (q - 1))
m = long_to_bytes(pow(c, d, 3 * 73 * p * q * r))
print(m) # b'CCTF{____Sylvester____tHE0r3m_Of_D3r!va7i0n!}'
Barak (27 solves)
附件代码
barak.sage
#!/usr/bin/env sage
from Crypto.Util.number import *
from flag import flag
def on_barak(P, E):
c, d, p = E
x, y = P
return (x**3 + y**3 + c - d*x*y) % p == 0
def add_barak(P, Q, E):
if P == (0, 0):
return Q
if Q == (0, 0):
return P
assert on_barak(P, E) and on_barak(Q, E)
x1, y1 = P
x2, y2 = Q
if P == Q:
x3 = y1 * (c - x1**3) * inverse(x1**3 - y1**3, p) % p
y3 = x1 * (y1**3 - c) * inverse(x1**3 - y1**3, p) % p
else:
x3 = (y1**2*x2 - y2**2*x1) * inverse(x2*y2 - x1*y1, p) % p
y3 = (x1**2*y2 - x2**2*y1) * inverse(x2*y2 - x1*y1, p) % p
return (x3, y3)
def mul_barak(m, P, E):
if P == (0, 0):
return P
R = (0, 0)
while m != 0:
if m & 1:
R = add_barak(R, P, E)
m = m >> 1
if m != 0:
P = add_barak(P, P, E)
return R
def rand_barak(E):
c, d, p = E
while True:
y = randint(1, p - 1)
K = Zmod(p)
P.<x> = PolynomialRing(K)
f = x**3 - d*x*y + c + y^3
R = f.roots()
try:
r = R[0][0]
return (r, y)
except:
continue
p = 73997272456239171124655017039956026551127725934222347
d = 68212800478915688445169020404812347140341674954375635
c = 1
E = (c, d, p)
P = rand_barak(E)
FLAG = flag.lstrip(b'CCTF{').rstrip(b'}')
m = bytes_to_long(FLAG)
assert m < p
Q = mul_barak(m, P, E)
print(f'P = {P}')
print(f'Q = {Q}')
output.txt
P = (71451574057642615329217496196104648829170714086074852, 69505051165402823276701818777271117086632959198597714)
Q = (40867727924496334272422180051448163594354522440089644, 56052452825146620306694006054673427761687498088402245)
我的理解
题目生成了一个超奇异椭圆曲线
d
x
y
≡
x
3
+
y
3
+
1
dxy\equiv x^3+y^3+1
dxy≡x3+y3+1
并且随机生成了一个点P,然后给出了一个点Q=m*P
ECDLP问题。
我的方法
对于这种特殊曲线,首先将其映射转化为weierstrass方程,使用标准椭圆曲线形式求解。
在谷歌上搜索这种特殊椭圆曲线,可以找到论文
根据论文进行映射即可。
而在和@Mu.Chen的学习中学到一种另外的解法,sagemath自带映射的函数,真是太强了🥰
不用手动映射,可以自动映射,tql!.
Mu.chen师傅的解法
from Crypto.Util.number import *
p = 73997272456239171124655017039956026551127725934222347
d = 68212800478915688445169020404812347140341674954375635
c = 1
P = (71451574057642615329217496196104648829170714086074852, 69505051165402823276701818777271117086632959198597714)
Q = (40867727924496334272422180051448163594354522440089644, 56052452825146620306694006054673427761687498088402245)
R.<xx,yy,zz> = Zmod(p)[]
cubic = xx^3 + yy^3 + c * zz^3 - d * xx * yy * zz
EC = EllipticCurve_from_cubic(cubic, morphism=False)
mf = EllipticCurve_from_cubic(cubic, morphism=True)
PP = mf(P)
QQ = mf(Q)
dd = PP.discrete_log(QQ)
print(EC.order())
print(PP.order())
print(dd)
EC = 73997272456239171124655016995459084401465136460086688
order = 3083219685676632130193959041477461850061047352503612
m = 1780694557271320552511299360138314441283923223949197
#得到的是 flag % order,所以需要枚举。
for i in range(99):
print(long_to_bytes(m + i * order))
b'_hE5S!4n_f0rM_0F_3CC!!'
我的代码
# !/usr/bin/env python3.10
# -*- coding: utf-8 -*-
# @Author : lingfeng
# @File : wp.py
from Crypto.Util.number import *
p = 73997272456239171124655017039956026551127725934222347
d = 68212800478915688445169020404812347140341674954375635
a = 1
P = (71451574057642615329217496196104648829170714086074852, 69505051165402823276701818777271117086632959198597714)
Q = (40867727924496334272422180051448163594354522440089644, 56052452825146620306694006054673427761687498088402245)
A=(d**4+216*d*a)*inverse(48,p)%p
B=(d**6-540*d**3*a-5832*a**2)*inverse(864,p)%p
print(a1,b1,sep='\n')
def twisted_to_weiestrass(x,y):
assert (a*x**3+y**3+1)%p==(d*x*y)%p
x1,x2,x3=(d**3-27*a)*x%p,3*(3+3*y+d*x)%p,d**2*inverse(4,p)%p
y1,y2=(d**3-27*a)*(1-y)%p,2*(3+3*y+d*x)%p
X=(x1*inverse(x2,p)%p-x3)%p
Y=y1*inverse(y2,p)%p
assert (Y**2)%p==(X**3-a1*X+b1)%p
return (X,Y)
P_=twisted_to_weiestrass(P[0],P[1])
Q_=twisted_to_weiestrass(Q[0],Q[1])
E = EllipticCurve(GF(p), [-A, B])
P1=E(P_)
Q1=E(Q_)
factors, exponents = zip(*factor(E.order()))
primes = [factors[i] ^ exponents[i] for i in range(len(factors))]
print(primes)
dlogs = []
for fac in primes:
t = int(int(P1.order()) // int(fac))
dlog = discrete_log(t*Q1,t*P1,operation="+")
dlogs += [dlog]
print("factor: "+str(fac)+", Discrete Log: "+str(dlog)) #calculates discrete logarithm for each prime order
flag=crt(dlogs,primes)
print(long_to_bytes(flag))#b'\x88\x9cd\x97\n\x01\x14\x85@\n\xea\x87V<\xe5\xbf\xc3O$}\x83M'
'''
print后发现并未打印出理想中的flag,猜想可能是因为flag>P1.order(),
因此,对P1.order()进行清算
'''
p1=P1.order()
for i in range(-10,10):
t=flag+i*p1
FLAG=long_to_bytes(int(t))
if len(str(FLAG))<30:
print(B'CCTF{'+FLAG+b'}')#b'CCTF{_hE5S!4n_f0rM_0F_3CC!!}'
break
Risk (35 solves)
附件代码
#!/usr/bin/env python3
from Crypto.Util.number import *
from secret import m, flag
def genPrime(m, nbit):
assert m >= 2
while True:
a = getRandomNBitInteger(nbit // m)
r = getRandomNBitInteger(m ** 2 - m + 2)
p = a ** m + r
if isPrime(p):
return (p, r)
def genkey(m, nbit):
p, r = genPrime(m, nbit // 2)
q, s = genPrime(m, nbit // 2)
n = p * q
e = r * s
return (e, n)
def encrypt(msg, pkey):
e, n = pkey
m = bytes_to_long(msg)
c = pow(m, e, n)
return c
pkey = genkey(m, 2048)
enc = encrypt(flag, pkey)
print(f'pkey = {pkey}')
print(f'enc = {enc}')
output.txt
pkey = (150953688, 373824666550208932851344358703053061405262438259996622188837935528607451817812480600479188884096072016823491996056842120586016323642383543231913508464973502962030059403443181467594283936168384790367731793997013711256520780338341018619858240958105689126133812557401122953030695509876185592917323138313818881164334490044163316692588337720342646339764174333821950301279825316497898035760524780198230860089280791887363472060435443944632303774987556026740232641561706904946900169858650106994947597642013168757868017723456208796677559254390940651802333382820063200360490892131573853635471525711894510477078934343423255983)
enc = 275574424285842306309073814038154403551700455145115884031072340378743712325975683329051874910297915882286569143815715537085387363420246497061870251520240399514896001311724695996978111559476733709139080970977190150345474341853495386364275702356438666152069791355990718058189043717952080875207858163490627801836274404446661613239167700736337269924479349700031535265765885064606399858172168036794462235707003475360358004643720927563261787867952228496769300443415094124132722170498229611285689671203272698693505808912907778910378274197503048226322090611405601517624884408718689404556983397217070272851442351897456769883
我的理解
题目构造了一种公钥生成方式,
p
=
a
m
+
r
,
q
=
b
m
+
s
p=a^m+r,q=b^m+s
p=am+r,q=bm+s
只有这个生成素数的方式是特殊的,其他正常,那就从素数生成入手。
我的方法
首先得到 e b i t e_{bit} ebit,由此判断出m的值
print(e.bit_length())#28
for m in range(10):
print(m**2-m+2)
# 14,m=4
知晓m的值后,就可以知道
p
=
a
4
+
r
,
q
=
b
4
+
s
p=a^4+r,q=b^4+s
p=a4+r,q=b4+s,
并且
r
b
i
t
=
s
b
i
t
=
14
,
a
b
i
t
=
b
b
i
t
=
512
r_{bit}=s_{bit}=14,a_{bit}=b_{bit}=512
rbit=sbit=14,abit=bbit=512。
此时,对e进行分解
sage: factor(150953688)
2^3 * 3^2 * 149 * 14071
而巧合的时
(
14071
)
b
i
t
=
14
(14071)_{bit}=14
(14071)bit=14,正好满足r,s的比特条件,那就真是妙的获得了r,s。
而(a,b)和(r,s)两者的数据差距非常之大,姑且看做
p
≈
a
4
,
q
≈
b
4
p\approx a^4,q\approx b^4
p≈a4,q≈b4
则
n
≈
(
a
b
)
4
=
>
a
b
=
g
m
p
y
2
.
i
r
o
o
t
(
n
,
4
)
n\approx (ab)^4=>a b=gmpy_2.iroot(n,4)
n≈(ab)4=>ab=gmpy2.iroot(n,4)
这时我们就获得了第一个式子
a
∗
b
=
a
b
a*b=ab
a∗b=ab(1)
加上r,s我们已经求出来了,就可以获得第二个式子
(
a
4
+
r
)
(
b
4
+
s
)
=
n
(a^4+r)(b^4+s)=n
(a4+r)(b4+s)=n(2)
两个式子一联立,sagemath解方程轻轻松松。
那这个题就已经解决一大半了,接下来在私钥d的求出中会发现,e和phi不互素。
由于p,q的数比较大,题目并未对flag进行填充,可以试试将p,q单独作为公钥求解,
然后即是常规解法,先把不互素的地方除去,然后剩下的利用p或者q构建多项式环求根。
我的代码
import gmpy2
from Crypto.Util.number import *
e,n = (150953688, 373824666550208932851344358703053061405262438259996622188837935528607451817812480600479188884096072016823491996056842120586016323642383543231913508464973502962030059403443181467594283936168384790367731793997013711256520780338341018619858240958105689126133812557401122953030695509876185592917323138313818881164334490044163316692588337720342646339764174333821950301279825316497898035760524780198230860089280791887363472060435443944632303774987556026740232641561706904946900169858650106994947597642013168757868017723456208796677559254390940651802333382820063200360490892131573853635471525711894510477078934343423255983)
c = 275574424285842306309073814038154403551700455145115884031072340378743712325975683329051874910297915882286569143815715537085387363420246497061870251520240399514896001311724695996978111559476733709139080970977190150345474341853495386364275702356438666152069791355990718058189043717952080875207858163490627801836274404446661613239167700736337269924479349700031535265765885064606399858172168036794462235707003475360358004643720927563261787867952228496769300443415094124132722170498229611285689671203272698693505808912907778910378274197503048226322090611405601517624884408718689404556983397217070272851442351897456769883
#print(e.bit_length())
# for m in range(10):
# print(m**2-m+2)
#14,m=4
r,s=14071,10728
ab=int(gmpy2.iroot(n,4)[0])
# var('a b')
# f1=a*b==ab
# f2=n==(ab**4)+a**4*s+b**4*r+r*s
#solve([f1,f2],[a,b])
a = 62274975615987643692868402753919717915571698965384326918741532757736062456316
b = 70607920723454965609462647852561338394953465815405215597995100849466809965911
p=a**4+r
q=b**4+s
d=inverse(e//72,p-1)
m_72=pow(c,d,n)
e=72
P.<a>=PolynomialRing(Zmod(p),implementation='NTL')
f=a^e-m_72
mps=f.monic().roots()
for i in mps:
flag=long_to_bytes(int(i[0]))
if b'CCTF' in flag:
print(flag)#b'CCTF{S!mP1E_A7t4cK_0n_SpEc1aL-5trucTur3D_RSA_pR1me5!}'
Roldy (55 solves)
题目代码
#!/usr/bin/env python3
from Crypto.Util.number import *
from pyope.ope import OPE as enc
from pyope.ope import ValueRange
import sys
from secret import key, flag
def die(*args):
pr(*args)
quit()
def pr(*args):
s = " ".join(map(str, args))
sys.stdout.write(s + "\n")
sys.stdout.flush()
def sc():
return sys.stdin.buffer.readline()
def encrypt(msg, key, params):
if len(msg) % 16 != 0:
msg += (16 - len(msg) % 16) * b'*'
p, k1, k2 = params
msg = [msg[_*16:_*16 + 16] for _ in range(len(msg) // 16)]
m = [bytes_to_long(_) for _ in msg]
inra = ValueRange(0, 2**128)
oura = ValueRange(k1 + 1, k2 * p + 1)
_enc = enc(key, in_range = inra, out_range = oura)
C = [_enc.encrypt(_) for _ in m]
return C
def main():
border = "|"
pr(border*72)
pr(border, " Welcome to Roldy combat, we implemented an encryption method to ", border)
pr(border, " protect our secret. Please note that there is a flaw in our method ", border)
pr(border, " Can you examine it and get the flag? ", border)
pr(border*72)
pr(border, 'Generating parameters, please wait...')
p, k1, k2 = [getPrime(129)] + [getPrime(64) for _ in '__']
C = encrypt(flag, key, (p, k1, k2))
while True:
pr("| Options: \n|\t[E]ncrypted flag! \n|\t[T]ry encryption \n|\t[Q]uit")
ans = sc().decode().lower().strip()
if ans == 'e':
pr(border, f'encrypt(flag, key, params) = {C}')
elif ans == 't':
pr(border, 'Please send your message to encrypt: ')
msg = sc().rstrip(b'\n')
if len(msg) > 64:
pr(border, 'Your message is too long! Sorry!!')
C = encrypt(msg, key, (p, k1, k2))
pr(border, f'C = {C}')
elif ans == 'q':
die(border, "Quitting ...")
else:
die(border, "Bye ...")
if __name__ == '__main__':
main()
我的理解
服务器提供了两种功能,一是获得加密后的flag,而是可以输入任意字符进入加密,然后服务器返回加密后的数据,就是说服务器提供了一个加密功能。
我的方法
首先查看加密过程是什么,服务器调用了ope库,没见过,查一下
通过搜索后找到学习链接,里面有一个很通俗易懂的讲解
既然如此,这就是ope加密算法,成为保序加密的重要特征了。
而题目中,是一16bytes为一个块进行加密,既然如此,我们可以以每一个块为单位,进行二分查找,将加密后的密文与flag的密文进行对比,然后不断缩小范围,最终找到Flag。
思路大概就是如此,但是在实践中发现,服务器每次交互十几次甚至几次就断开了,而且我们发送给服务器的必须是可打印字符。
对此我的解决方法是,二分查找以可打印字符为单位,上界就为16*’~’,而下界即为16*’!’,因为他们的Ascii分别是可打印中最大的和最小的。(在这里,二分查找时,可能会碰到Flag那一位字符就是!或者就是’~'的,这种时候列出来特殊情况解决就可以)
而服务器交互不定次数后断开,那么应该是以交互时间为限制的,那我们可以设置我们的交互时间不超过断开时间,然后不断重复循环,并且每次循环都会保留之前的进度,然后接着交互,直到获得正确的flag。
我的代码
# !/usr/bin/env python3.10
# -*- coding: utf-8 -*-
# @Time : 2023/7/8 15:30
# @Author : lingfeng
# @File : wp.py
import time
from pwn import *
from tqdm import *
def Binary_lookup(enc,flag,k,low,high):
while low < high-1:
time2=time.time()
if time2-time1 > 17:
return flag,1,low,high
mid=(low+high)//2
r.recvuntil(b'[Q]uit\n')
r.sendline(b'T')
r.recvline()
FLAG=(flag+alpha[mid])+((k+1)*16-1-len(flag))*'~'
r.sendline(FLAG.encode())
r.recvuntil(b'=')
tmp = eval(r.recvline().strip().decode())
if tmp[k]<enc[k]:
low=mid
elif tmp[k]>enc[k]:
high=mid
elif tmp[k]==enc[k]:
return flag+alpha[mid],0,0,la-1
if high==1:
r.recvuntil(b'[Q]uit\n')
r.sendline(b'T')
r.recvline()
FLAG = (flag + alpha[0]) + ((k + 1) * 16 - 1 - len(flag)) * '~'
r.sendline(FLAG.encode())
r.recvuntil(b'=')
tmp = eval(r.recvline().strip().decode())
if tmp[k] > enc[k]:
return flag+alpha[0],0,0,la-1
return flag+alpha[high],0,0,la-1
alpha= sorted(string.ascii_uppercase+string.ascii_lowercase+string.digits+'{}~_!@#$.%^&*+-=')
la,t1,FLAG=len(alpha),0,''
low, high = 0, la - 1
for _ in trange(100):#大概跑个20分钟出
r = remote("06.cr.yp.toc.tf", 31377)
time1=time.time()
r.recvuntil(b'[Q]uit\n')
r.sendline(b'e')
r.recvuntil(b'=')
enc = eval(r.recvline().decode())
k=len(FLAG)//16
FLAG,x,low,high=Binary_lookup(enc,FLAG,k,low,high)
if x==1:
r.close()
continue
print(FLAG) # CCTF{Boldyreva_5ymMe7rIC_0rD3r_pRe5Erv!n9_3nCryp7i0n!_LStfig9TM}
if len(FLAG)>=64:
break
r.close()
medium完成三分之一咧,接下来也在肝了,写的不知道详细不详细,师傅们多多在评论区发表一下意见,我会听取改正的,最后希望师傅们一起参与讨论,提取建议,如果又更好的方法球球来教教弟弟(≧∇≦)ノ🥰
不想认命,就去拼命。我始终相信,付出就会有收获,或大或小,或迟或早,始终不会辜负你的努力。有一种落差是,你总是羡慕别人的成功,自己却不敢开始。