免责声明:下列wp除我本人出的题外,其他题目wp不具备官方性质,仅作为参考。

然后我简单说两句啊()
今年的密码,我个人感觉不算很难,都是老套路套到了新题上,很多都是常见的解题思路。同时也有一些创新,但是也没有跳出固定的框架(毕竟密码学又不是misc,谁天天脑洞(乐))
总之,这次我还是尽力给大家带来全套证明了。希望大家看的愉快。

蓝鲨的费马

在这里插入图片描述

题目:

import libnum
import gmpy2
from Crypto.Util.number import *

flag=b'ISCTF{********}'
m=bytes_to_long(flag)

p=libnum.generate_prime(1024)
q=libnum.generate_prime(1024)
n=p*q
e=0x10001
c=pow(m,e,n)
d=inverse(e,(p-1)*(q-1))
leak = (d+(pow(p,q,n)+pow(q,p,n)))%n

print("c=", c)
print("n=", n)
print("leak=", leak)

"""
c= 8989289659072309605793417141528767265266446236550650613514493589798432446586991233583435051268377555448062724563967695425657559568596372723980081067589103919296476501677424322525079257328042851349095575718347302884996529329066703597604694781627113384086536158793653551546025090807063130353950841148535682974762381044510423210397947080397718080033363000599995100765708244828566873128882878164321817156170983773105693537799111546309755235573342169431295776881832991533489235535981382958295960435126843833532716436804949502318851112378495533302256759494573250596802016112398817816155228378089079806308296705261876583997
n= 13424018200035368603483071894166480724482952594135293395398366121467209427078817227870501294732149372214083432516059795712917132804111155585926502759533393295089100965059106772393520277313184519450478832376508528256865861027444446718552169503579478134286009893965458507369983396982525906466073384013443851551139147777507283791250268462136554061959016630318688169168797939873600493494258467352326974238472394214986505312411729432927489878418792288365594455065912126527908319239444514857325441614280498882524432151918146061570116187524918358453036228204087993064505391742062288050068745930452767100091519798860487150247
leak= 9192002086528025412361053058922669469031188193149143635074798633855112230489479254740324032262690315813650428270911079121913869290893574897752990491429582640499542165616254566396564016734157323265631446079744216458719690853526969359930225042993006404843355356540487296896949431969541367144841985153231095140361069256753593550199420993461786814074270171257117410848796614931926182811404655619662690700351986753661502438299236428991412206196135090756862851230228396476709412020941670878645924203989895008014836619321109848938770269989596541278600166088022166386213646074764712810133558692545401032391239330088256431881
"""

根据费马小定理,有

q = p q ( m o d n ) q = p^q \pmod{n} q=pq(modn)
p = q p ( m o d n ) p = q^p \pmod{n} p=qp(modn)

然后我们化简式子。
l e a k = ( d + p + q ) ( m o d n ) leak = (d + p + q) \pmod{n} leak=(d+p+q)(modn)
l e a k = d + p + q + k n , k ∈ Z leak= d + p+q + kn, k \in Z leak=d+p+q+kn,kZ
e ∗ l e a k = e d + e ( p + q ) + k e n , k ∈ Z e*leak = ed + e(p+q) + ken,k \in Z eleak=ed+e(p+q)+ken,kZ
k 1 = e ∗ k , k 1 ∈ Z k_1 = e*k,k_1 \in Z k1=ek,k1Z
e ∗ l e a k = e d + e ( p + q ) + k 1 n , k 1 ∈ Z e*leak = ed + e(p+q) + k_1n,k_1 \in Z eleak=ed+e(p+q)+k1n,k1Z
因为 e d ≡ 1 ( m o d φ ( n ) ) ed \equiv 1 \pmod{\varphi(n)} ed1(modφ(n))
e d = 1 + t ∗ φ ( n ) , t ∈ Z ed = 1+t*\varphi(n),t \in Z ed=1+tφ(n),tZ
代入上式
e ∗ l e a k = 1 + t φ ( n ) + e ( p + q ) + k 1 n , k 1 ∈ Z , t ∈ Z e*leak = 1+t\varphi(n) + e(p+q) + k_1n,k_1 \in Z,t \in Z eleak=1+(n)+e(p+q)+k1n,k1Z,tZ
φ ( n ) = ( p − 1 ) ( q − 1 ) = p q − ( p + q ) + 1 = n − ( p + q ) + 1 \varphi(n) = (p-1)(q-1) = pq-(p+q)+1 = n-(p+q)+1 φ(n)=(p1)(q1)=pq(p+q)+1=n(p+q)+1
代入
e ∗ l e a k = 1 + t ( n − ( p + q ) + 1 ) + e ( p + q ) + k 1 n , k 1 ∈ Z , t ∈ Z e*leak = 1+t(n-(p+q)+1) + e(p+q) + k_1n,k_1 \in Z,t \in Z eleak=1+t(n(p+q)+1)+e(p+q)+k1n,k1Z,tZ
整理化简
e ∗ l e a k = 1 + t n − t ( p + q ) + t + e ( p + q ) + k 1 n , k 1 ∈ Z , t ∈ Z e*leak = 1+tn -t(p+q)+t+ e(p+q) + k_1n,k_1 \in Z,t \in Z eleak=1+tnt(p+q)+t+e(p+q)+k1n,k1Z,tZ
e ∗ l e a k = 1 + t + ( e − t ) ( p + q ) + ( k 1 − t ) n , k 1 ∈ Z , t ∈ Z e*leak = 1+t+ (e-t)(p+q) + (k_1-t)n,k_1 \in Z,t \in Z eleak=1+t+(et)(p+q)+(k1t)n,k1Z,tZ
等式两边对n取模
e ∗ l e a k ≡ ( e − t ) ( p + q ) + t + 1 ( m o d n ) , t ∈ Z e*leak \equiv (e-t)(p+q)+t+1 \pmod{n},t \in Z eleak(et)(p+q)+t+1(modn),tZ
l ≡ e ∗ l e a k ( m o d n ) l \equiv e*leak \pmod{n} leleak(modn)
l − t − 1 ≡ ( e − t ) ( p + q ) ( m o d n ) , t ∈ Z l-t-1 \equiv (e-t)(p+q) \pmod{n},t \in Z lt1(et)(p+q)(modn),tZ
分析
p+q大于0
l − t − 1 l-t-1 lt1的正负号仅由 e − t e-t et决定
t > e t >e t>e,则 t > l − 1 t>l-1 t>l1
而 l 是1024位以上的数,若t>e,则t几乎不可爆破
而若可以爆破,则 t < e t <e t<e
e = 0x10001
尝试爆破

l = e*leak % n

for t in range(0x10001):
	if (l - 1 - t) % (e - t)  == 0:
		p_plus_q = (l - 1 - t) // (e - t)
		delta = p_plus_q * p_plus_q - 4 * n
		if delta <= 0 :
			continue
		squre_delta = iroot(delta,2)
		if squre_delta[1]:
			p = (p_plus_q + squre_delta[0])//2
			q = (p_plus_q - squre_delta[0])//2
			print(f"{t=}")
			break

得到p和q之后就正常求解RSA 即可。

小蓝鲨的数学题

在这里插入图片描述

在这里插入图片描述

题目:

# Base和Ciphertext
m = 5321153468370294351697008906248782883193902636120413346203705810525086437271585682015110123362488732193020749380395419994982400888011862076022065339666193
c = 7383779796712259466884236308066760158536557371789388054326630574611014773044467468610300619865230550443643660647968413988480055366698747395046400909922513

离散对数求解问题
直接求解即可。

m = 5321153468370294351697008906248782883193902636120413346203705810525086437271585682015110123362488732193020749380395419994982400888011862076022065339666193
a=7383779796712259466884236308066760158536557371789388054326630574611014773044467468610300619865230550443643660647968413988480055366698747395046400909922513
G=Zmod(2**512) 
m1=G(m) 
c1=G(a) 
print(ZZ(discrete_log(c1,m1)))

小蓝鲨的方程

在这里插入图片描述

题目:

from Cryptodome.Util.number import *
from random import *
from gmpy2 import *
import uuid
flag1='ISCTF{'+str(uuid.uuid4())+'}'

m1=bytes_to_long(flag1.encode())
def get_p():
    BITS = 256
    bits = 777
    oder = 4
    a = randint(1 << bits, 1 << bits + 1)
    p=getPrime(BITS)
    p1 = p**oder+a
    return p,p1
p,p1=get_p()
s=getPrime(1024)
q=getPrime(512)
n=p*q**4
e=65537
c1=pow(s,e,n)
c=pow(s**3+1,m1,s**5)
print("c1=",c1)
print("c =",c)
print("n =",n)
print("p1 =",p1)

'''
c1= 671390498592586008552998377599101093977542184109077889081448730480869018650843045119891777468161631085086340705902115332025675787789530562679603254577287153918966364523848382506106179394235772395029788721306186952016420794804145631124905952103136061076643266886961178241381892015555099638200222249447194504082451341122502519637821695210573997670753981061458264118355417889153180841281073262935937836447460470926729282834006229571453935760593644658459098721652426154970766417292435960463905367868753821950303919781798234432998272038029063155193184039985018137026245365188171178677898869374676546799536208952198558258306460302868688355653022725288744014143221560882404431652751343944983442109327
c = 8641190030376811670503537177719719233418166235794962118828671236836174132083208517733734760455990850156371205118391537919769888760384574011411232571257192285256730733174399297826587479261381970232162702657952399683882650083181048279650913795429823628186888540572704055008102853692060360140858142686334722286525699998854566609078547487420929457446776757558492454916447188774943818970599916514467335772992690805247630814156710861067503956707301402347944233660194395192354000788262111000900574820275786269075882923600474781645848712157460135387134196156906258218217831988828360827613420801773911833194097791649069743116686685667300622630909231822986237104627385544169938138006242341269672868611269202418482629393372933567053272565557137741441902377611003983050084491513897727856173625922194300103448148829004025229567101761111396110940066254801762424343522707712480796358754008120503317686600144600226149617189681233392693738216138797012278242152852923361635415564580582002132107424154426980566696622448291815571736676562214017436
n = 1076246859437269645898003764327104347852443049519429833372038915264009774423737482018987571807662568251485615769880354898666799006772572239466617428164721157850526408878346223839884319846641438292436373441749602341461361190584638190903978829024853974880636148520803145113551453821058269641304504880310836801494499720662704717315748614372503735165114899680682056477494953525794354656896362929510309669119173103242509398650608116835276076364248473952717811633756784397347121601006659623317417388283638159905288128181587304367489096254611610975352096229116491567502061775862811850081040850421151385474249060884479729988512713640536139010928836126719149031115182144744359297169350288886555784650111
p1 = 145356063641618996012874664536921616978986640263438210169671010403677822239343590475177543891188656103067696467174379510912427160232486984044862545338401652910975162942038201716552753723984593267892098222213049269335313670049037479410635628460505327693176152061750827570561482918795206276991967169087371403553
'''

题目给了p1和n
我们先来求出来p

p 1 = p 4 + a p_1 = p^4+a p1=p4+a
p = p 1 − a 4 < p 1 4 p = \sqrt[4]{p_1 - a} < \sqrt[4]{p_1} p=4p1a <4p1
写成等式,有
p + γ = p 1 4 p + \gamma = \sqrt[4]{p_1} p+γ=4p1
那么我们爆破这个伽马就行

def crack(n, p1):
	for i in trange(10000):
		test = iroot(p1, 4)[0] - i
		if not is_prime(test):
			continue
		else:
			q = iroot(n // test, 4)
			if q[1]:
				q = q[0]
				print()
				print("found!")
				return test,q

这样就有p和q了
然后计算 φ ( n ) \varphi(n) φ(n)也很简单
直接套欧拉函数就行
φ ( n ) = φ ( p q 4 ) = φ ( p ) ∗ φ ( q 4 ) = ( p − 1 ) ∗ ( q 4 − q 3 ) \varphi(n) = \varphi(pq^4) = \varphi(p)*\varphi(q^4) = (p-1)*(q^4 - q^3) φ(n)=φ(pq4)=φ(p)φ(q4)=(p1)(q4q3)
然后就可以正常求解RSA得到s了
有s之后,要求m1
我们已经知道
c ≡ ( s 3 + 1 ) m 1 ( m o d s 5 ) c\equiv(s^3 + 1)^{m_1} \pmod{s^5} c(s3+1)m1(mods5)
将式子写成等式
c + k s 5 = ( s 3 + 1 ) m 1 , k ∈ Z c+ ks^5 = (s^3 + 1)^{m_1},k\in Z c+ks5=(s3+1)m1,kZ
我们将等式右边二项式展开
( s 3 + 1 ) m 1 = C m 1 0 s 3 m 1 1 0 + C m 1 1 s 3 ( m 1 − 1 ) 1 1 + ⋯ + C m 1 m 1 − 1 s 3 1 m 1 − 1 + C m 1 m 1 s 0 1 m 1 (s^3 + 1)^{m_1} = C_{m_1}^{0}s^{3m_1}1^0 + C_{m_1}^{1}s^{3(m_1 - 1)}1^1 + \cdots + C_{m_1}^{m_1-1}s^{3}1^{m_1-1} + C^{m_1}_{m_1}s^01^{m_1} (s3+1)m1=Cm10s3m110+Cm11s3(m11)11++Cm1m11s31m11+Cm1m1s01m1
我们把1全部化简掉,并且把前面几项和后边几项的排列组合式子展开
( s 3 + 1 ) m 1 = s 3 m 1 + m 1 s 3 ( m 1 − 1 ) + ⋯ + m 1 s 3 + 1 (s^3 + 1)^{m_1} = s^{3m_1}+m_1s^{3(m_1-1)} + \cdots + m_1s^3 + 1 (s3+1)m1=s3m1+m1s3(m11)++m1s3+1
显然,m1 远大于2

因此前边所有s的指数,都大于s的5次方
因此在模s的5次方的时候,可以被约去
因此式子化简为
c ≡ m 1 s 3 + 1 ( m o d s 5 ) c \equiv m_1s^3 + 1 \pmod{s^5} cm1s3+1(mods5)
从上式我们可以发现
只要 m 1 < s 2 m_1 < s^2 m1<s2,那么恒等号可以化为等号
而s是1024位数,则m只要小于2048位即可
m的信息量显然小于256字节
毕竟flag也才长几十字节。
因此 m = c − 1 s 3 m = \frac{c-1}{s^3} m=s3c1

from libnum import n2s,s2n
from gmpy2 import *
from tqdm import trange


def crack(n, p1):
	for i in trange(10000):
		test = iroot(p1, 4)[0] - i
		if not is_prime(test):
			continue
		else:
			q = iroot(n // test, 4)
			if q[1]:
				q = q[0]
				print()
				print("found!")
				return test,q

n = 1076246859437269645898003764327104347852443049519429833372038915264009774423737482018987571807662568251485615769880354898666799006772572239466617428164721157850526408878346223839884319846641438292436373441749602341461361190584638190903978829024853974880636148520803145113551453821058269641304504880310836801494499720662704717315748614372503735165114899680682056477494953525794354656896362929510309669119173103242509398650608116835276076364248473952717811633756784397347121601006659623317417388283638159905288128181587304367489096254611610975352096229116491567502061775862811850081040850421151385474249060884479729988512713640536139010928836126719149031115182144744359297169350288886555784650111
p1 = 145356063641618996012874664536921616978986640263438210169671010403677822239343590475177543891188656103067696467174379510912427160232486984044862545338401652910975162942038201716552753723984593267892098222213049269335313670049037479410635628460505327693176152061750827570561482918795206276991967169087371403553
c1 = 671390498592586008552998377599101093977542184109077889081448730480869018650843045119891777468161631085086340705902115332025675787789530562679603254577287153918966364523848382506106179394235772395029788721306186952016420794804145631124905952103136061076643266886961178241381892015555099638200222249447194504082451341122502519637821695210573997670753981061458264118355417889153180841281073262935937836447460470926729282834006229571453935760593644658459098721652426154970766417292435960463905367868753821950303919781798234432998272038029063155193184039985018137026245365188171178677898869374676546799536208952198558258306460302868688355653022725288744014143221560882404431652751343944983442109327
c = 8641190030376811670503537177719719233418166235794962118828671236836174132083208517733734760455990850156371205118391537919769888760384574011411232571257192285256730733174399297826587479261381970232162702657952399683882650083181048279650913795429823628186888540572704055008102853692060360140858142686334722286525699998854566609078547487420929457446776757558492454916447188774943818970599916514467335772992690805247630814156710861067503956707301402347944233660194395192354000788262111000900574820275786269075882923600474781645848712157460135387134196156906258218217831988828360827613420801773911833194097791649069743116686685667300622630909231822986237104627385544169938138006242341269672868611269202418482629393372933567053272565557137741441902377611003983050084491513897727856173625922194300103448148829004025229567101761111396110940066254801762424343522707712480796358754008120503317686600144600226149617189681233392693738216138797012278242152852923361635415564580582002132107424154426980566696622448291815571736676562214017436
e = 0x10001

p,q = crack(n, p1)
print(p, q)
phi = (p-1)*(q**4 - q**3)
d = invert(e, phi)
s = pow(c1, d, n)

m = (c - 1) // (s**3)
print(m)

print(n2s(int(m)))

蓝鲨的RSA

在这里插入图片描述

这题的考点在去年亦有所记载(ISCTF2023 密码 1zRSA,baby group)

题目:

from secret import flag
import gmpy2
import decimal
from Crypto.Util.number import *

def gethint(h,p):
    decimal.getcontext().prec = 1024
    H = decimal.Decimal(int(h))
    P = decimal.Decimal(int(p))
    leak = decimal.Decimal((8*H*P - 1) / (16*P*P))
    return leak
p = getPrime(512)
q = getPrime(512)
f = getPrime(512)
g = getPrime(128)
h = gmpy2.invert(f, p) * g % p

n = f*q
e = 65537
m = bytes_to_long(flag)

c = pow(m,e,n)
print('c =', c)
print('hint =', gethint(h,p))
print('n =',n)

#c = 587245179027322480379581200283415189810421958968516831191660631552695197401940961725169763339428980298128692606951200581483431566182271569207988054537414289564013883171160614196522169980339024564884190765084419167938640701193928669
#hint = 0.2427542737153618793334900104191212626446625872340179613972610728976081994921862517310186626304527115125924716035632505287111236596234811779375148657365336957626454491865164520834975233144235103885081268955448330597818844340656652982593545877449810282619387305007246499089258519062093814083383071737897364213169497762760797899310673216754376885295598952272100016962368762532805864796748393317534908268379601445004775495237901072144236328105526403608646831124542336002540011176406194984370372589752234640498423911217119220030242197564695880261480071310815379681250975672935544404797155655708441222387631967447088319826137200280810029390387418159394276760100487636516708987579464183208860911063948902432948269805493252899815187044807603000344378890835564906163242023600624338694473573763088471321731611077227112205396909637906507673367598721218000123789690455125909411309668615810240938664264212370815385282488986625554704015828254539339719586211726300858711328516487805251366293457402531199532556110786048074755505680210260049
#n = 839799159583571337450826982895478997157381520448790705455708438948150905361244823725400304016136863419723271227616684280477524669207590477657886623628732394537008838314015048569652202355464477680540884654473950183135276735347866051

首先先看gethint

给入p和h,给出一个leak
l e a k = 8 h p − 1 16 p 2 leak = \frac{8hp-1}{16p^2} leak=16p28hp1
化简一下,有
l e a k = h 2 p − 1 16 p 2 leak = \frac{h}{2p} - \frac{1}{16p^2} leak=2ph16p21
等式两边同乘以8
8 l e a k = 4 h p − 1 2 p 2 8leak = \frac{4h}{p} - \frac{1}{2p^2} 8leak=p4h2p21
移项变化一下
4 h p − 8 l e a k = 1 2 p 2 \frac{4h}{p} - 8leak = \frac{1}{2p^2} p4h8leak=2p21

加一个绝对值
∣ 4 ( 2 l e a k − h p ) ∣ = 1 2 p 2 |4(2leak - \frac{h}{p})| = \frac{1}{2p^2} ∣4(2leakph)=2p21
放缩一下
∣ 2 l e a k − h p ∣ < ∣ 4 ( 2 l e a k − h p ) ∣ = 1 2 p 2 |2leak - \frac{h}{p}| < |4(2leak - \frac{h}{p})| = \frac{1}{2p^2} ∣2leakph<∣4(2leakph)=2p21
∣ 2 l e a k − h p ∣ < 1 2 p 2 |2leak - \frac{h}{p}| < \frac{1}{2p^2} ∣2leakph<2p21
我们有引理:
legendre Continued fraction
若有 ∣ ξ − a b ∣ < 1 2 b 2 \left | \xi - \frac{a}{b} \right | < \frac{1}{2b^2} ξba <2b21
那么 a b \frac{a}{b} ba ξ \xi ξ的连分数展开的某一项渐进分数
具体不证,可以去这儿仔细研究推导

https://math.stackexchange.com/questions/531736/legendres-proof-continued-fractions-from-hardys-book

关于连分数相关内容,鉴于去年已经详细说明,如果有不会的可以去翻翻我关于ISCTF2023 1zRSA 相关内容。

总之,我们可以在渐进分数中找到h

我们去年用的原生python来计算连分数,我们今年也可以通过sagemath进行求解。

这里解释几个下列代码出现的sagemath函数

continued_fraction用来计算a的连分数,后边的参数是如果a是个无穷连分数,则展开1024项。

c = continued_fraction(a, 1024)

同时,你可以对他计算渐进分数,如我们上边把结果给到了c,那么我们可以通过c.convergents()方法计算c的渐进分数。给出的结果是个形式表示,即用分子和分母进行表示,而非给出分子和分母或者计算出具体的数。因此我们可以通过字符串处理得到其每一项渐进分数的分子和分母。

同时,我们又知道p是个512位长的质数

因此我们直接求2*hint 的渐近展开就行。
这里我们唯一需要注意的就是,由于python的精度问题,直接给进去貌似是不太可行的,或许有sagemath函数可以保留精度,但是我们这里选择用小数点后的数除以10的1024次方来表示。

当然,别忘了乘上2。

def crack():
	hint = 2*2427542737153618793334900104191212626446625872340179613972610728976081994921862517310186626304527115125924716035632505287111236596234811779375148657365336957626454491865164520834975233144235103885081268955448330597818844340656652982593545877449810282619387305007246499089258519062093814083383071737897364213169497762760797899310673216754376885295598952272100016962368762532805864796748393317534908268379601445004775495237901072144236328105526403608646831124542336002540011176406194984370372589752234640498423911217119220030242197564695880261480071310815379681250975672935544404797155655708441222387631967447088319826137200280810029390387418159394276760100487636516708987579464183208860911063948902432948269805493252899815187044807603000344378890835564906163242023600624338694473573763088471321731611077227112205396909637906507673367598721218000123789690455125909411309668615810240938664264212370815385282488986625554704015828254539339719586211726300858711328516487805251366293457402531199532556110786048074755505680210260049
	l = hint/10**1024
	c=continued_fraction(l, 1024)
	result = [tuple([int(j) for j in str(i).split("/")]) for i in c.convergents()]
	
	for i in result[2:]:
	    h,p = i
	    if len(bin(p)[2:]) == 512 and is_prime(p):
	        print(h,p)
	        return h, p


这样我们就得到h和p了

然后后边的问题是一个格密码学问题

简单写一下
我们已经知道两个值,一个h一个p
并且有
h = gmpy2.invert(f, p) * g % p

h ≡ f − 1 g ( m o d p ) h \equiv f^{-1}g \pmod p hf1g(modp)
我们的目的是求出来f

我们先对式子进行恒等变换,首先左右各乘上一个 f f f
f h ≡ g ( m o d p ) (1) fh \equiv g \pmod p \tag{1} fhg(modp)(1)
考虑1式,有 k ∈ Z k \in Z kZ满足 f h = g + k p fh = g + kp fh=g+kp
我们不妨构造两个向量 a 1 = ( 1 , h ) , a 2 = ( 0 , p ) a_1=(1,h),a_2=(0,p) a1=(1,h),a2=(0,p)
那么考虑向量 ( f , g ) (f,g) (f,g)可以表示为
( f , g ) = f a 1 − k a 2 (f,g) = fa_1 - ka_2 (f,g)=fa1ka2
我们已知h和p
若我们能求出来f和g,那么我们显然可以直接进行解密

那么上述都是数学变换,怎么进行求解呢?
我们这里不进行具体证明,有兴趣可以自行验证

二维格上的高斯启发式:
v m i n = d e t L π e v_{min = }\sqrt{\frac{detL}{\pi e}} vmin=πedetL
其中v为二维格上的最小向量(注:上式为估计值)
那么我们不妨将a1,a2设为一个二阶格系统,
则detL为由a1,a2组成的矩阵的行列式
∣ a 1 , a 2 ∣ = 1 ∗ p − 0 ∗ h = p |a_1,a_2| = 1*p - 0*h = p a1,a2=1p0h=p
即最小向量在p附近
同时由题目可得, ∣ ( f , g ) ∣ ≤ p |(f,g)| \leq p (f,g)p
不加证明的猜测(f,g)为最小向量

因此,我们只需要求以a1,a2为基向量的格上最短向量。

这个工作本应可以用二维的高斯格基规约来求得。但是我不清楚为什么这里没有求出来。我们直接用LLL算法了。

def crack():
	hint = 2*2427542737153618793334900104191212626446625872340179613972610728976081994921862517310186626304527115125924716035632505287111236596234811779375148657365336957626454491865164520834975233144235103885081268955448330597818844340656652982593545877449810282619387305007246499089258519062093814083383071737897364213169497762760797899310673216754376885295598952272100016962368762532805864796748393317534908268379601445004775495237901072144236328105526403608646831124542336002540011176406194984370372589752234640498423911217119220030242197564695880261480071310815379681250975672935544404797155655708441222387631967447088319826137200280810029390387418159394276760100487636516708987579464183208860911063948902432948269805493252899815187044807603000344378890835564906163242023600624338694473573763088471321731611077227112205396909637906507673367598721218000123789690455125909411309668615810240938664264212370815385282488986625554704015828254539339719586211726300858711328516487805251366293457402531199532556110786048074755505680210260049
	l = hint/10**1024
	c=continued_fraction(l, 1024)
	result = [tuple([int(j) for j in str(i).split("/")]) for i in c.convergents()]
	
	for i in result[2:]:
	    h,p = i
	    if len(bin(p)[2:]) == 512 and is_prime(p):
	        print(h,p)
	        return h, p

h,p = crack()
t = matrix([[1,h],[0,p]])
data = t.LLL()
f, g = data[0][0], data[0][1]
print(f, g)

这样我们就求出来f和g了
有f了自然就可以按照正常思路去求解RSA了

因此这里不过多赘述了。

直接给出全部代码

from gmpy2 import *
from libnum import n2s,s2n


def crack():
	hint = 2*2427542737153618793334900104191212626446625872340179613972610728976081994921862517310186626304527115125924716035632505287111236596234811779375148657365336957626454491865164520834975233144235103885081268955448330597818844340656652982593545877449810282619387305007246499089258519062093814083383071737897364213169497762760797899310673216754376885295598952272100016962368762532805864796748393317534908268379601445004775495237901072144236328105526403608646831124542336002540011176406194984370372589752234640498423911217119220030242197564695880261480071310815379681250975672935544404797155655708441222387631967447088319826137200280810029390387418159394276760100487636516708987579464183208860911063948902432948269805493252899815187044807603000344378890835564906163242023600624338694473573763088471321731611077227112205396909637906507673367598721218000123789690455125909411309668615810240938664264212370815385282488986625554704015828254539339719586211726300858711328516487805251366293457402531199532556110786048074755505680210260049
	l = hint/10**1024
	c=continued_fraction(l, 1024)
	result = [tuple([int(j) for j in str(i).split("/")]) for i in c.convergents()]
	
	for i in result[2:]:
	    h,p = i
	    if len(bin(p)[2:]) == 512 and is_prime(p):
	        print(h,p)
	        return h, p


h,p = crack()
t = matrix([[1,h],[0,p]])
data = t.LLL()
f, g = data[0][0], data[0][1]
n = 839799159583571337450826982895478997157381520448790705455708438948150905361244823725400304016136863419723271227616684280477524669207590477657886623628732394537008838314015048569652202355464477680540884654473950183135276735347866051
e = 0x10001
c = 587245179027322480379581200283415189810421958968516831191660631552695197401940961725169763339428980298128692606951200581483431566182271569207988054537414289564013883171160614196522169980339024564884190765084419167938640701193928669

q = n // f
assert f*q == n

phi = (f-1)*(q-1)
d = invert(e,phi)
m = pow(c,d,n)
print(n2s(int(m)))

我和小蓝鲨的秘密

在这里插入图片描述

GPT牛逼(
n分解一下,yafu或者factordb都能分解
除了我自己分解了一下p和q
然后算了算n
剩下的都是GPT干的

from gmpy2 import *
from PIL import Image
from libnum import n2s,s2n
import numpy as np


p = 160216064374859
q = 186431677583461
e = 0x10001

n = p*q
phi = (p-1)*(q-1)
d = invert(e,phi)

# 加载加密的图像数据
encrypted_array = np.load("encrypted_image.npy", allow_pickle = True)
h, w, _ = encrypted_array.shape

# 初始化解密后的图像数组
decrypted_array = np.zeros((h, w, 3), dtype=np.uint8)

for i in range(h):
	for j in range(w):
		r_enc, g_enc, b_enc = encrypted_array[i, j]

		# RSA 解密
		r = pow(r_enc, d, n)
		g = pow(g_enc, d, n)
		b = pow(b_enc, d, n)

		decrypted_array[i, j] = [r, g, b]

decrypted_img = Image.fromarray(decrypted_array, "RGB")
decrypted_img.save("decrypted_flag.jpg")
ISCTF{success!_bluesharkinfo_gogogo!}

ChaCha20-Poly1305

在这里插入图片描述

题目:

from Crypto.Cipher import ChaCha20_Poly1305
import os

key = os.urandom(32)
nonce = os.urandom(12)

with open('flag.txt', 'rb') as f:
    plaintext = f.read()

cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)

ct, tag = cipher.encrypt_and_digest(plaintext)

print(f"Encrypted Flag: {ct.hex()}")
print(f"Tag: {tag.hex()}")
print(f"Nonce: {nonce.hex()}")

with open('key.txt', 'w') as key_file:
    key_file.write(key.hex())

key = '3=t#sMX3?9GHSPdi4i^gk!3*(cH8S8XT2y&?Tv4!?AGG=R]ZDy/PVVa+DqiXAH*}DS&Nn*a+@<H,=!L'

'''
Encrypted Flag: 20408b9fc498063ad53a4abb53633a6a15df0ddaf173012d620fa33001794dbb8c038920273464e13170e26d08923aeb
Tag: 70ffcc508bf4519e7616f602123c307b
Nonce: d8ebeedec812a6d71240cc50
'''

这题也很简单,唯一的难点就是看出来key是个base92
剩下的就交给ChatGPT写就行了

这个key用basecrack跑一下就行

在这里插入图片描述

然后交给GPT或者自己写都OK

from libnum import n2s,s2n
from Crypto.Cipher import ChaCha20_Poly1305


key = n2s(0x173974535637a5ef30a116b03d00bd2fe751951ca3eaa62daec2b8f5ca5b6135)
tag = n2s(0x70ffcc508bf4519e7616f602123c307b)
nonce = n2s(0xd8ebeedec812a6d71240cc50)
ciphertext = n2s(0x20408b9fc498063ad53a4abb53633a6a15df0ddaf173012d620fa33001794dbb8c038920273464e13170e26d08923aeb)

cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
print(plaintext.decode())

小蓝鲨的密码

在这里插入图片描述

好吧我承认这题是我想复杂了(乐

跟今年ISCC一样,也有个路在脚下(是今年吧?)

实际上就是文件名

rar压缩包的密码是bluesharkinfo
得到密码本

想爆破也行,这个其实能看出来

因为里边有个blueshark和isctf2024
试一下发现是isctf2024
免去写脚本的烦恼了

用在线网站解密即可

https://tool.oschina.net/encrypt/

在这里插入图片描述

ezmath

在这里插入图片描述

修复代码

在这里插入图片描述

这两个函数一个是求和,一个是求极限,用到了非常简单的装饰器的用法。

先传入进去参数,然后在传入进去极限的值,也就是start之类的,也就是前n-1个在计算时是常数,最后一个是变量。对这个变量积分或者求极限。这个求极限的pos就是求左极限还是右极限,当然对于默认的无穷来说,左极限显然等于右极限。

def sumFunc(func):
	def wapper(*args,start = 1,end=INF):
		sums = 0
		for i in trange(start, 0xffff * end):
			sums += function(*args,j/0xf) * (1/0xf)
		return sums
	return wapper

def limitFunc(func):
	def wapper(*args, approch = bigINF, pos = "+"):
		o = 1/bigINF
		return function(args, eval(f"{approch} {pos} {o}"))
	return wapper

首先是第一个的错误

1、for循环应该是range而不是trange(请先忘掉tqdm)(line 4)

2、循环变量应该是i而不是j(line 5)

然后是第二个的错误

1、传入进来的是func,而不是function(line 12)

2、args应该解引用(line 12)

修复后的代码

def sumFunc(func):
	def wapper(*args,start = 1,end=INF):
		sums = 0
		for i in range(start, 0xffff * end):
			sums += func(*args,i/0xf) * (1/0xf)
		return sums
	return wapper

def limitFunc(func):
	def wapper(*args, approch = bigINF, pos = "+"):
		o = 1/bigINF
		return func(*args, eval(f"{approch} {pos} {o}"))
	return wapper

其实修不修影响并不大,毕竟如果修了程序直接跑出flag岂不是成签到了)

修只是为了能跑)

接下来其实就是高数)

首先这个magicNumber其实就是自然常数e

而limitFunc的默认是趋向于正无穷的,也就是

lim ⁡ t → + ∞ ( 1 + 1 t ) t = e \lim_{t \to +\infty}(1+\frac{1}{t})^t = e t+lim(1+t1)t=e

就是个重要极限

第二个可能比较难以看出来,我们先写出来

f ( x ) = ∫ 0 + ∞ t x − 1 e − t d t f(x) = \int^{+\infty}_{0}t^{x-1}e^{-t} dt f(x)=0+tx1etdt

如果你注意力惊人的话,是可以注意到这玩意儿其实就是阶乘函数的解析延拓,什么是解析延拓,简单来说就是将定义域拓宽,本身的阶乘只能是整数,现在我们可以让他取实数了。(注意力不惊人的话,可以去找attention is all you need的,那个注意力比较惊人(人话:GPT))

因此,这个函数有以下性质

f ( x + 1 ) = x f ( x ) f(x+1) = xf(x) f(x+1)=xf(x)

f ( 1 − x ) f ( x ) = π s i n π x , x ∈ ( 0 , 1 ) f(1-x)f(x)=\frac{\pi}{sin\pi x},x \in (0,1) f(1x)f(x)=sinπxπ,x(0,1)

因此,可以让x=0.5
f ( 1 2 ) = π f(\frac{1}{2}) = \sqrt{\pi} f(21)=π

那我们题中的(这个符号就是大写的gamma(伽马),用来替代了上面的f罢了)

Γ ( 5 2 ) = 3 2 Γ ( 3 2 ) = 3 4 Γ ( 1 2 ) = 3 4 π \Gamma(\frac{5}{2}) = \frac{3}{2}\Gamma(\frac{3}{2}) = \frac{3}{4}\Gamma(\frac{1}{2})=\frac{3}{4}\sqrt{\pi} Γ(25)=23Γ(23)=43Γ(21)=43π
Γ ( 3 2 ) = 1 2 Γ ( 1 2 ) = π 2 \Gamma(\frac{3}{2})=\frac{1}{2}\Gamma(\frac{1}{2}) = \frac{\sqrt{\pi}}{2} Γ(23)=21Γ(21)=2π
然后就是common了

这个其实也很常见,写出来就知道了
∫ 0 + ∞ e − t 2 d t \int_{0}^{+\infty}e^{-t^2}dt 0+et2dt
包是高斯积分的。

这个证法真的太多太多了,总之,我们有他的反常积分

∫ − ∞ + ∞ e t 2 d t = π \int_{-\infty}^{+\infty}e^{t^2}dt = \sqrt{\pi} +et2dt=π

被积函数是个偶函数,因此有

∫ 0 + ∞ e − t 2 d t = π 2 \int_{0}^{+\infty}e^{-t^2}dt = \frac{\sqrt{\pi}}{2} 0+et2dt=2π

正好是gamma(3/2)的值

验证了我们几个函数的正确性。

那么只要计算gamma(5/2)就行了,前边我们已经计算过他的值了。

from math import sqrt,pi
from hashlib import md5
import random

key = int(str(3*sqrt(pi)/4)[2:])
print(key)
random.seed(key)
print(md5(str(random.getrandbits(256)).encode('utf-8')).hexdigest())

在这里插入图片描述

逃跑的HIM

在这里插入图片描述

先放出来本章灵感来源,事实上也就是完全照着这个就能复现出来。。。

https://github.com/spawnmason/randar-explanation

简单说一下思路,不用代码审计了就(其实ai审计也能找到答案,乐)

我自己实现了一套java的那堆随机数(包括命名也是java的那一套,Random随机数则是我直接翻java的源代码照抄的,乐)

主要的main里边就是HIM会设置两个在-23440 到23440的随机数,分别为X,Z

我们的目标就是恢复这两个随机数

恢复5次即可。

主要是考察了代码审计,格基规约,线性同余发生器破解相关的内容。(当然硬说来点pwntools也确实有)

本来想套层二维码给X,Z,然后还要读二维码,一方面时间不足,另一方面也没必要硬套了感觉,就没上。

其实大部分文章都有讲,这里就主要是代码审计之后找到漏洞然后恢复就行了。逻辑还是比较明显的,就看会不会破解了(乐

如果复现有问题联系我(建议先仔细读读上边那个文章)

大致就这样。。。

需要给sagemath装上pwntools然后就能跑了


from pwn import *


sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
rl = lambda : p.recvline()
it = lambda : p.interactive()

ip = ''
port = 0

p = remote(ip , port)
# p = remote("127.0.0.1", 8888)
sla("请输入用户名: ",b"guoql")
sla("=>请选择:",b"start")
for _ in range(5):
        sla("输入yes投币开始:",b"yes")
        sla("请选择:","2")
        sla("请输入想要挖掘的方块坐标(例: (1,1,1) ):",b"(1,1,1)")
        data = rl().decode('utf-8')
        blockX,blockY,blockZ = tuple([float("0." + i.split(".")[1]) for i in data.split("Block drop in ")[1][:-1][1:-1].split(", ")])
        print(data,blockX,blockY,blockZ)
        randX = round(2 * 2**24 * (blockX - 0.25))
        randY = round(2 * 2**24 * (blockY - 0.25))
        randZ = round(2 * 2**24 * (blockZ - 0.25))
        # 获取低24位数据
        print(f"{randX},{randY},{randZ}")
        # 格基规约得到原始seed
        def crack(a0,b0,c0):
            a=25214903917
            b=11
            c=281474976710656
            a1 = a0 * 2**24 + 2**23
            b1 = b0 * 2**24 + 2**23
            c1 = c0 * 2**24 + 2**23
            v = vector([a1,b1 - b,c1 - b - a*b])

            matex = matrix.zero(3)
            matex[0] = [1,a,a*a]
            matex[1] = [0,c,0]
            matex[2] = [0,0,c]
            lattice = matex.LLL()
            base = lattice.transpose().inverse()
            result = base*v

            final = vector([round(RDF(i)) for i in result])

            solved = lattice.transpose() * final
            return solved

        seed = int(crack(randX, randY, randZ)[0])
        # LCG线性同余求解出来上一个seed
        old_seed = ((seed - 11 ) * 246154705703781) % 2**48
        # sagemath的异或是^^而不是^
        HIM_seed = old_seed ^^ 0x5DEECE66D
        print(old_seed,HIM_seed)
        world_seed = 14617218721232814696
        # input()
        # 寻找x,z需要满足在-23440 到 23400 的范围内
        for x in range(-23440, 23441):
                z = ((HIM_seed - world_seed - 10387319 - x * 341873128712 ) * 211541297333629 ) % 2**48
                if z >= 2**48 + -23440 :
                        z = z - 2**48
                        print(f"x,z found:{x},{z}")
                        break
                if z <= 23440:
                        print(f"x,z found:{x},{z}")
                        break
                

        sla("请选择:", b"1")
        sla("请输入HIM所在区块的坐标(例: (10,-25) ):", f"({x},{z})".encode('utf-8'))
        print(rl().decode('utf-8'))
print(rl().decode('utf-8'))

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐