2023 CryptoCTF wp by lingfeng (medium分类——1)

想说的一些话:

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} qC3C5C2C4>=p>=qC0C1rC5C1C4C0>=q>=rC2C3

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=qC0C1
此时我的想法
自然而然的联想到用连分数求出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=qC0C1是错误的,应该是 C 0 p − C 1 q = x C_0p-C_1q=x C0pC1q=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 C0pC1q=O0C2qC3r=O1C4rC5p=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 (C0pC1q)bit=x=>xedbit+x3
由此,可以判断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 dxyx3+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 pa4,qb4
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 ab=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完成三分之一咧,接下来也在肝了,写的不知道详细不详细,师傅们多多在评论区发表一下意见,我会听取改正的,最后希望师傅们一起参与讨论,提取建议,如果又更好的方法球球来教教弟弟(≧∇≦)ノ🥰

不想认命,就去拼命。我始终相信,付出就会有收获,或大或小,或迟或早,始终不会辜负你的努力。有一种落差是,你总是羡慕别人的成功,自己却不敢开始

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在SpringBoot中,常用的参数的绑定方式包括路径参数、查询参数、请求体参数以及表单数据参数。路径参数是通过在URL路径中定义占位符来传递参数,可以使用@PathVariable注解进行绑定。查询参数是通过URL中的查询字符串传递参数,可以使用@RequestParam注解进行绑定。请求体参数是通过请求体中的数据传递参数,可以使用@RequestBody注解进行绑定。表单数据参数是通过表单提交的数据传递参数,可以使用@RequestParam注解或者MultipartFile类型进行绑定。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [SpringBoot前后端参数传递方式总结](https://blog.csdn.net/liuerchong/article/details/112425692)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [教你4招优雅实现Spring Boot 异步线程间的数据传递](https://blog.csdn.net/Java_LingFeng/article/details/128543461)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值