强网杯2019 Copperstudy
靶机:node4.buuoj.cn:29678
第一次见靶机的题,找题目找了半天😊
打开VMware中的浏览器,输入靶机地址,得到:
[+]proof: skr=os.urandom(8)
[+]hashlib.sha256(skr).hexdigest()=67fbc84508c4087471605c92639387450c6d41fa97936c8a64405408403b0f72
[+]skr[0:5].encode('hex')=32f574e3af
[-]skr.encode('hex')=
bye~
os.urandom()函数:获取一个指定长度的随机bytes对象
hashlib.sha256(x).hecdigest():使用sha256算法计算x的散列并返回十六进制的值。
爆破得到skr
from Crypto.Util.number import *
import hashlib
for i in range(10000,20000000):
tar = 0x32f574e3af
payload = long_to_bytes(i)
payload = long_to_bytes(tar) + payload
if hashlib.sha256(payload).hexdigest() == '67fbc84508c4087471605c92639387450c6d41fa97936c8a64405408403b0f72' :
print(i)
break
运行得到:15740973
转为十六进制为f0302d
加上前面的为32f574e3aff0302d
然后呢,,,,,把它输到哪啊啊啊😶
在菜菜的不懈努力下终于下载好了nc(并且删完了所以由于下载而附带的一系列软件🤬)
然后发现在虚拟机上早就有安装好的nc😓
但是,有了nc之后呢,,,,
咳咳咳,打开虚拟机终端,输入:nc node4.buuoj.cn 27362
得到:
开始题目
[+]proof: skr=os.urandom(8)
[+]hashlib.sha256(skr).hexdigest()=c8753a2c2e65194731a5c821803c197b018b157d3b43920dbc0e632ad108e835
[+]skr[0:5].encode('hex')=4f2d16389b
[-]skr.encode('hex')=
终于不直接出bye~了
(靶机题目数据每次打开是不同的)
按照前面程序,求得:4f2d16389b9d3681
输入后得到:
第一题
proof completed
[+]Generating challenge 1
[+]n=13112061820685643239663831166928327119579425830632458568801544406506769461279590962772340249183569437559394200635526183698604582385769381159563710823689417274479549627596095398621182995891454516953722025068926293512505383125227579169778946631369961753587856344582257683672313230378603324005337788913902434023431887061454368566100747618582590270385918204656156089053519709536001906964008635708510672550219546894006091483520355436091053866312718431318498783637712773878423777467316605865516248176248780637132615807886272029843770186833425792049108187487338237850806203728217374848799250419859646871057096297020670904211
[+]e=3
[+]m=random.getrandbits(512)
[+]c=pow(m,e,n)=15987554724003100295326076036413163634398600947695096857803937998969441763014731720375196104010794555868069024393647966040593258267888463732184495020709457560043050577198988363754703741636088089472488971050324654162166657678376557110492703712286306868843728466224887550827162442026262163340935333721705267432790268517
[+]((m>>72)<<72)=2519188594271759205757864486097605540135407501571078627238849443561219057751843170540261842677239681908736
[-]long_to_bytes(m).encode('hex')=
很明显的RSA,已知n、e、c,而且e=3,用小明文攻击
import gmpy2
from Crypto.Util.number import long_to_bytes
c =15987554724003100295326076036413163634398600947695096857803937998969441763014731720375196104010794555868069024393647966040593258267888463732184495020709457560043050577198988363754703741636088089472488971050324654162166657678376557110492703712286306868843728466224887550827162442026262163340935333721705267432790268517
m = gmpy2.iroot(c,3)[0]
print(long_to_bytes(m))
运行得到:b'FLAG{2^8rsa7589693fc689c77c5f5262d654272427}'
然后在用在线hex加密,或者
print(binascii.hexlify(long_to_bytes(m)))
得到:b'464c41477b325e3872736137353839363933666336383963373763356635323632643635343237323432377d'
输入(记得不要把b’'输入上去)得到:
第二题
challenge1 completed
[+]Generating challenge 2
[+]n=12784625729032789592766625203074018101354917751492952685083808825504221816847310910447532133616954262271205877651255598995305639194329607493047941212754523879402744065076183778452640602625242851184095546100200565113016690161053808950384458996881574266573992526357954507491397978278604102524731393059303476350167738237822647246425836482533150025923051544431330502522043833872580483142594571802189321599016725741260254170793393777293145010525686561904427613648184843619301241414264343057368192416551134404100386155751297424616254697041043851852081071306219462991969849123668248321130382231769250865190227630009181759219
[+]e=65537
[+]m=random.getrandbits(512)
[+]c=pow(m,e,n)=627824086157119245056478875800598959553774250161670787506083253960788230737588761787385686125828765665617567887904228030839535317987589608761534500003128247164233774794784231518212804270056404565710426613938264302998015421153393879729263551292024543756422702956470022959537221269172084619081368498693930550456153543628170306324206266216348386707008661128717431426237486511309767286175518238620230507201952867261283880986868752676549613958785288914989429224582849218395471672295410036858881836363364885164276983237312235831591858044908369376855484127614933545955544787160352042318378588039587911741028067576722790778
[+]((p>>128)<<128)=97522826022187678545924975588711975512906538181361325096919121233043973599759518562689050415761485716705615149641768982838255403594331293651224395590747133152128042950062103156564440155088882592644046069208405360324372057140890317518802130081198060093576841538008960560391380395697098964411821716664506908672
[-]long_to_bytes(m).encode('hex')=
依旧是RSA,已知n、e、c
分解n然后按基础解法就可
import gmpy2
import binascii
from Crypto.Util.number import long_to_bytes
e = 65537
n = 12784625729032789592766625203074018101354917751492952685083808825504221816847310910447532133616954262271205877651255598995305639194329607493047941212754523879402744065076183778452640602625242851184095546100200565113016690161053808950384458996881574266573992526357954507491397978278604102524731393059303476350167738237822647246425836482533150025923051544431330502522043833872580483142594571802189321599016725741260254170793393777293145010525686561904427613648184843619301241414264343057368192416551134404100386155751297424616254697041043851852081071306219462991969849123668248321130382231769250865190227630009181759219
c = 627824086157119245056478875800598959553774250161670787506083253960788230737588761787385686125828765665617567887904228030839535317987589608761534500003128247164233774794784231518212804270056404565710426613938264302998015421153393879729263551292024543756422702956470022959537221269172084619081368498693930550456153543628170306324206266216348386707008661128717431426237486511309767286175518238620230507201952867261283880986868752676549613958785288914989429224582849218395471672295410036858881836363364885164276983237312235831591858044908369376855484127614933545955544787160352042318378588039587911741028067576722790778
p = 97522826022187678545924975588711975512906538181361325096919121233043973599759518562689050415761485716705615149641768982838255403594331293651224395590747133152128042950062103156564440155088882592644046069208405360324372057140890317518802130081198060093576841538008960560661715295741651653499691458486798196487
q = 131093675711613661161476275473445206682597559447006571385482255727609238786596952165801814021602699749876712682307789568113374768689632642728986573211776526473651771104432443501294668372441525987174391472994271054873305324343666279426741897612827889525440428582592216151586138881806196331920758968403508531637
phi = (q-1) * (p-1)
d = gmpy2.invert(e,phi)
m = gmpy2.powmod(c,d,n)
print(long_to_bytes(m))
print(binascii.hexlify(long_to_bytes(m)))
运行得到:b'464c41477b325e3872736136653237376633353564626536646133656464366633353664326462366436667d'
输入得到:
第三题
challenge2 completed
[+]Generating challenge 3
[+]n=92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
[+]e=3
[+]m=random.getrandbits(512)
[+]c=pow(m,e,n)=56164378185049402404287763972280630295410174183649054805947329504892979921131852321281317326306506444145699012788547718091371389698969718830761120076359634262880912417797038049510647237337251037070369278596191506725812511682495575589039521646062521091457438869068866365907962691742604895495670783101319608530
[+]d&((1<<512)-1)=787673996295376297668171075170955852109814939442242049800811601753001897317556022653997651874897208487913321031340711138331360350633965420642045383644955
[-]long_to_bytes(m).encode('hex')=
看起来跟前面第二题一样,但是用相同代码运行出来的是:1b5b7fc18b0db820211ba55ceeb56dcbbf1e181447f65f3b40dd8119dab89864ac15a28db8495fb0aa0692
输入显示bye~,很显然错了,又要重来一次
还有个事:
运算时<< >>位移运算,也就是p右移128位再左移128位,右移直接吞左移不足位补零
例如:
然后这道题是已知d的低位
能力不够百度来凑
def partial_p(p0, kbits, n):
PR.<x> = PolynomialRing(Zmod(n))
nbits = n.nbits()
f = 2^kbits*x + p0
f = f.monic()
roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3) # find root < 2^(nbits//2-kbits) with factor >= n^0.3
if roots:
x0 = roots[0]
p = gcd(2^kbits*x0 + p0, n)
return ZZ(p)
def find_p(d0, kbits, e, n):
X = var('X')
for k in range(1, e+1):
results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits)
for x in results:
p0 = ZZ(x[0])
p = partial_p(p0, kbits, n)
if p:
return p
if __name__ == '__main__':
n = 92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
e = 3
d = 787673996295376297668171075170955852109814939442242049800811601753001897317556022653997651874897208487913321031340711138331360350633965420642045383644955
nbits = n.nbits()
kbits = d.nbits()
print ("lower %d bits (of %d bits) is given" % (kbits, nbits))
p = find_p(d, kbits, e, n)
q = n//p
print ("d0 = %d" % d)
print ("d = %d" % inverse_mod(e, (p-1)*(q-1)))
回来了,这次懂已知部分位数的coppersmith攻击了
def getFullP(low_p, n):
R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
p = x*2^512 + low_p
root = (p-n).monic().small_roots(X = 2^128, beta = 0.4)
if root:
return p(root[0])
return None
def phase4(low_d, n, c,e):
maybe_p = []
for k in range(1, 4):
p = var('p')
p0 = solve_mod([e*p*low_d == p + k*(n*p - p^2 - n + p)], 2^512)
maybe_p += [int(x[0]) for x in p0]
# print(maybe_p)
for x in maybe_p:
P = getFullP(x, n)
if P: break
P = int(P)
Q = n // P
assert P*Q == n
d = inverse_mod(e, (P-1)*(Q-1))
print(hex(power_mod(c, d, n))[2:])
n=92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
e=3
low_d = 787673996295376297668171075170955852109814939442242049800811601753001897317556022653997651874897208487913321031340711138331360350633965420642045383644955
phase4(low_d, n, c,e)
得到:464c41477b325e3872736135616230383637343566366563373435363139613862363566653465633536307d
然后继续
第四题
challenge3 completed
[+]Generating challenge 4
[+]e=3
[+]m=random.getrandbits(512)
[+]n1=78642188663937191491235684351005990853149481644703243255021321296087539054265733392095095639539412823093600710316645130404423641473150336492175402885270861906530337207734106926328737198871118125840680572148601743121884788919989184318198417654263598170932154428514561079675550090698019678767738203477097731989
[+]c1=pow(m,e,n1)=23419685303892339080979695469481275906709035609088426118328601771163101123641599051556995351678670765521269546319724616458499631461037359417701720430452076029312714313804716888119910334476982840024696320503747736428099717113471541651211596481005191146454458591558743268791485623924245960696651150688621664860
[+]n2==98174485544103863705821086588292917749386955237408645745685476234349659452606822650329076955303471252833860010724515777826660887118742978051231030080666542833950748806944312437614585352818344599399156268450521239843157288915059003487783576003027303399985723834248634230998110618288843582573006048070816520647
[+]c2=pow(m,e,n2)=72080679612442543693944655041130370753964497034378634203383617624269927191363529233872659451561571441107920350406295389613006330637565645758727103723546610079332161151567096389071050158035757745766399510575237344950873632114050632573903701015749830874081198250578516967517980592506626547273178363503100507676
[+]n3=91638855323231795590642755267985988356764327384001022396221901964430032527111968159623063760057482761918901490239790230176524505469897183382928646349163030620342744192731246392941227433195249399795012672172947919435254998997253131826888070173526892674308708289629739522194864912899817994807268945141349669311
[+]c3=pow(m,e,n3)=22149989692509889061584875630258740744292355239822482581889060656197919681655781672277545701325284646570773490123892626601106871432216449814891757715588851851459306683123591338089745675044763551335899599807235257516935037356212345033087798267959242561085752109746935300735969972249665700075907145744305255616
[-]long_to_bytes(m).encode('hex')=
三个n三个c,很明显用中国剩余定理
from gmpy2 import *
from Crypto.Util.number import *
from functools import reduce
import random
e=3
m=random.getrandbits(512)
n1=78642188663937191491235684351005990853149481644703243255021321296087539054265733392095095639539412823093600710316645130404423641473150336492175402885270861906530337207734106926328737198871118125840680572148601743121884788919989184318198417654263598170932154428514561079675550090698019678767738203477097731989
c1=23419685303892339080979695469481275906709035609088426118328601771163101123641599051556995351678670765521269546319724616458499631461037359417701720430452076029312714313804716888119910334476982840024696320503747736428099717113471541651211596481005191146454458591558743268791485623924245960696651150688621664860
n2=98174485544103863705821086588292917749386955237408645745685476234349659452606822650329076955303471252833860010724515777826660887118742978051231030080666542833950748806944312437614585352818344599399156268450521239843157288915059003487783576003027303399985723834248634230998110618288843582573006048070816520647
c2=72080679612442543693944655041130370753964497034378634203383617624269927191363529233872659451561571441107920350406295389613006330637565645758727103723546610079332161151567096389071050158035757745766399510575237344950873632114050632573903701015749830874081198250578516967517980592506626547273178363503100507676
n3=91638855323231795590642755267985988356764327384001022396221901964430032527111968159623063760057482761918901490239790230176524505469897183382928646349163030620342744192731246392941227433195249399795012672172947919435254998997253131826888070173526892674308708289629739522194864912899817994807268945141349669311
c3=22149989692509889061584875630258740744292355239822482581889060656197919681655781672277545701325284646570773490123892626601106871432216449814891757715588851851459306683123591338089745675044763551335899599807235257516935037356212345033087798267959242561085752109746935300735969972249665700075907145744305255616
#long_to_bytes(m).encode('hex')=
N = [n1,n2,n3]
c = [c1,c2,c3]
def chinese_remainder(modulus, remainders):
Sum = 0
prod = reduce(lambda a, b: a*b, modulus)
for m_i, r_i in zip(modulus, remainders):
p = prod // m_i
Sum += r_i * (inverse(p,m_i)*p)
return Sum % prod
e = 3
pow_m_e = chinese_remainder(N,c)
m = iroot(pow_m_e,3)[0]
print(long_to_bytes(m))
运行得到: b'FLAG{2^8rsa8c5f3cff4bc095349fec65fc2263e878}'
换成十六进制464c41477b325e3872736138633566336366663462633039353334396665633635666332323633653837387d
下一步
第五题
challenge4 completed
[+]Generating challenge 5
[+]n= 113604829563460357756722229849309932731534576966155520277171862442445354404910882358287832757024693652075211204635679309777620586814014894544893424988818766425089667672311645586528776360047956843961901352792631908859388801090108188344342619580661377758180391734771694803991493164412644148805229529911069578061
[+]e=7
[+]m=random.getrandbits(512)
[+]c=pow(m,e,n)=112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021533447981943498594790549326550460216939216988828130624120379925895123186121819609415184887470233938291227816332249857236198616538782622327476603338806349004620909717360739157545735826670038169284252348037995399308
[+]x=pow(m+1,e,n)=112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021552486915464025361447529153776277710423467951041523831865232164370127602772602643378592695459331174613894578701940837730590029577336924367384969935652616989527416027725713616493815764725131271563545176286794438175
[-]long_to_bytes(m).encode('hex')=
重点在:
c
=
p
o
w
(
m
,
e
,
n
)
c=pow(m,e,n)
c=pow(m,e,n)
x
=
p
o
w
(
m
+
1
,
e
,
n
)
x=pow(m+1,e,n)
x=pow(m+1,e,n)
看起来是Coppersmith短填充攻击
import binascii
def attack(c1, c2, n, e):
PR.<x>=PolynomialRing(Zmod(n))
g1 = x^e - c1
g2 = (x+1)^e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
n= 113604829563460357756722229849309932731534576966155520277171862442445354404910882358287832757024693652075211204635679309777620586814014894544893424988818766425089667672311645586528776360047956843961901352792631908859388801090108188344342619580661377758180391734771694803991493164412644148805229529911069578061
e=7
c1=112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021533447981943498594790549326550460216939216988828130624120379925895123186121819609415184887470233938291227816332249857236198616538782622327476603338806349004620909717360739157545735826670038169284252348037995399308
c2=112992730284209629010217336632593897028023711212853788739137950706145189880318698604512926758021552486915464025361447529153776277710423467951041523831865232164370127602772602643378592695459331174613894578701940837730590029577336924367384969935652616989527416027725713616493815764725131271563545176286794438175
m1 = attack(c1, c2, n, e)
print(m1)
print(binascii.unhexlify("%x" % int(m1)))
但是运行结果是
b"\xa1\xc7Un\x89_\x82h\xb7\xa8\x1c\\\xae=\x13w\xf2E\xce\xb8K\x86\x87\x89\x82\xc9\x86\x9e\xd9\xa0\x0f\xd1\xec\x11\xa4b\x83\x1b\x81-\x7f\x97:8Z\x1c\xda\xe9F\\x\x08^\xf1\xd2\x8f\xa5-\x8b\x15\x16\t\xc77\xe7\x88\xc3\xae\x98H\xc3\x9c\xc2\xd6,\x8cs\xb7e\x9d\x19\xe4\x93\x01\x17\x1e]\xf0\xd9\xebk\xd0\xea\x0c\x0f-d#Sr\xc0O\x88\xe6@/ '\x83C-*<\xcaMr\x90\xe5\x9eA\xaf\xbe\x1c d\x95\x13L"
试了下m1
113604829563460357756722229849309932731534576966155520277171862442445354404910882358287832757024693652075211204635679309777620586814014894544893424988818766425089667672311645586528776360047956843961901352792631908859388801090108188344342619580661377758180391734771694803991493164412644148805229529911069578060
意料之中的不对
搜了其他大佬们的解题
发现其实
c = 16404985139084147094704300764850430964980485772400565266054075398380588297033201409914512724255440373095027298869259036450071617770755361938461322132693877590521575670718076480353565935028734363256919872879837455527948173237810119579078252909879868459848240229599708133153841801633280283847680255816123323196
x = 92463268823628386526871956385934776043432833035349654252757452728405540022093349560058649691620353528569690982904353035470935543182784600771655097406007508218346417446808306197613168219068573563402315939576563452451487014381380516422829248470476887447827532913133023890886210295009811931573875721299817276803
还是上面的代码,得到
2519188594271759205757864485636246725747814635521266738394314968508953885010717495394569603836620104361341
b'FLAG{2^8rsa398cf8df7c26661bb7cb65b2b9fae25e}'
将flag转换为十六进制'0x464c41477b325e3872736133393863663864663763323636363162623763623635623262396661653235657d'
然后继续
第六题
challenge5 completed
[+]Generating challenge 6
[+]n=0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27L
[+]d=random.getrandbits(1024*0.270)
[+]e=invmod(d,phin)
[+]hex(e)=0x11722b54dd6f3ad9ce81da6f6ecb0acaf2cbc3885841d08b32abc0672d1a7293f9856db8f9407dc05f6f373a2d9246752a7cc7b1b6923f1827adfaeefc811e6e5989cce9f00897cfc1fc57987cce4862b5343bc8e91ddf2bd9e23aea9316a69f28f407cfe324d546a7dde13eb0bd052f694aefe8ec0f5298800277dbab4a33bbL
[+]m=random.getrandbits(512)
[+]c=pow(m,e,n)=0xe3505f41ec936cf6bd8ae344bfec85746dc7d87a5943b3a7136482dd7b980f68f52c887585d1c7ca099310c4da2f70d4d5345d3641428797030177da6cc0d41e7b28d0abce694157c611697df8d0add3d900c00f778ac3428f341f47ecc4d868c6c5de0724b0c3403296d84f26736aa66f7905d498fa1862ca59e97f8f866cL
[-]long_to_bytes(m).encode('hex')=
可以看出e非常大,尝试维纳攻击
搜了其他大佬的代码
用的是
import time
############################################
# Config
##########################################
"""
Setting debug to true will display more informations
about the lattice, the bounds, the vectors...
"""
debug = True
"""
Setting strict to true will stop the algorithm (and
return (-1, -1)) if we don't have a correct
upperbound on the determinant. Note that this
doesn't necesseraly mean that no solutions
will be found since the theoretical upperbound is
usualy far away from actual results. That is why
you should probably use `strict = False`
"""
strict = False
"""
This is experimental, but has provided remarkable results
so far. It tries to reduce the lattice as much as it can
while keeping its efficiency. I see no reason not to use
this option, but if things don't work, you should try
disabling it
"""
helpful_only = True
dimension_min = 7 # stop removing if lattice reaches that dimension
############################################
# Functions
##########################################
# display stats on helpful vectors
def helpful_vectors(BB, modulus):
nothelpful = 0
for ii in range(BB.dimensions()[0]):
if BB[ii,ii] >= modulus:
nothelpful += 1
print( nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
# display matrix picture with 0 and X
def matrix_overview(BB, bound):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
a += '0' if BB[ii,jj] == 0 else 'X'
if BB.dimensions()[0] < 60:
a += ' '
if BB[ii, ii] >= bound:
a += '~'
print( a)
# tries to remove unhelpful vectors
# we start at current = n-1 (last vector)
def remove_unhelpful(BB, monomials, bound, current):
# end of our recursive function
if current == -1 or BB.dimensions()[0] <= dimension_min:
return BB
# we start by checking from the end
for ii in range(current, -1, -1):
# if it is unhelpful:
if BB[ii, ii] >= bound:
affected_vectors = 0
affected_vector_index = 0
# let's check if it affects other vectors
for jj in range(ii + 1, BB.dimensions()[0]):
# if another vector is affected:
# we increase the count
if BB[jj, ii] != 0:
affected_vectors += 1
affected_vector_index = jj
# level:0
# if no other vectors end up affected
# we remove it
if affected_vectors == 0:
print( "* removing unhelpful vector", ii)
BB = BB.delete_columns([ii])
BB = BB.delete_rows([ii])
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
# level:1
# if just one was affected we check
# if it is affecting someone else
elif affected_vectors == 1:
affected_deeper = True
for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
# if it is affecting even one vector
# we give up on this one
if BB[kk, affected_vector_index] != 0:
affected_deeper = False
# remove both it if no other vector was affected and
# this helpful vector is not helpful enough
# compared to our unhelpful one
if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
print( "* removing unhelpful vectors", ii, "and", affected_vector_index)
BB = BB.delete_columns([affected_vector_index, ii])
BB = BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
# nothing happened
return BB
"""
Returns:
* 0,0 if it fails
* -1,-1 if `strict=true`, and determinant doesn't bound
* x0,y0 the solutions of `pol`
"""
def boneh_durfee(pol, modulus, mm, tt, XX, YY):
"""
Boneh and Durfee revisited by Herrmann and May
finds a solution if:
* d < N^delta
* |x| < e^delta
* |y| < e^0.5
whenever delta < 1 - sqrt(2)/2 ~ 0.292
"""
# substitution (Herrman and May)
PR.<u, x, y> = PolynomialRing(ZZ)
Q = PR.quotient(x*y + 1 - u) # u = xy + 1
polZ = Q(pol).lift()
UU = XX*YY + 1
# x-shifts
gg = []
for kk in range(mm + 1):
for ii in range(mm - kk + 1):
xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
gg.append(xshift)
gg.sort()
# x-shifts list of monomials
monomials = []
for polynomial in gg:
for monomial in polynomial.monomials():
if monomial not in monomials:
monomials.append(monomial)
monomials.sort()
# y-shifts (selected by Herrman and May)
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
yshift = Q(yshift).lift()
gg.append(yshift) # substitution
# y-shifts list of monomials
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
monomials.append(u^kk * y^jj)
# construct lattice B
nn = len(monomials)
BB = Matrix(ZZ, nn)
for ii in range(nn):
BB[ii, 0] = gg[ii](0, 0, 0)
for jj in range(1, ii + 1):
if monomials[jj] in gg[ii].monomials():
BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
# Prototype to reduce the lattice
if helpful_only:
# automatically remove
BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
# reset dimension
nn = BB.dimensions()[0]
if nn == 0:
print( "failure")
return 0,0
# check if vectors are helpful
if debug:
helpful_vectors(BB, modulus^mm)
# check if determinant is correctly bounded
det = BB.det()
bound = modulus^(mm*nn)
if det >= bound:
print( "We do not have det < bound. Solutions might not be found.")
print( "Try with highers m and t.")
if debug:
diff = (log(det) - log(bound)) / log(2)
print( "size det(L) - size e^(m*n) = ", floor(diff))
if strict:
return -1, -1
else:
print( "det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
# display the lattice basis
if debug:
matrix_overview(BB, modulus^mm)
# LLL
if debug:
print( "optimizing basis of the lattice via LLL, this can take a long time")
BB = BB.LLL()
if debug:
print( "LLL is done!")
# transform vector i & j -> polynomials 1 & 2
if debug:
print( "looking for independent vectors in the lattice")
found_polynomials = False
for pol1_idx in range(nn - 1):
for pol2_idx in range(pol1_idx + 1, nn):
# for i and j, create the two polynomials
PR.<w,z> = PolynomialRing(ZZ)
pol1 = pol2 = 0
for jj in range(nn):
pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
# resultant
PR.<q> = PolynomialRing(ZZ)
rr = pol1.resultant(pol2)
# are these good polynomials?
if rr.is_zero() or rr.monomials() == [1]:
continue
else:
print( "found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials = True
break
if found_polynomials:
break
if not found_polynomials:
print( "no independant vectors could be found. This should very rarely happen...")
return 0, 0
rr = rr(q, q)
# solutions
soly = rr.roots()
if len(soly) == 0:
print( "Your prediction (delta) is too small")
return 0, 0
soly = soly[0][0]
ss = pol1(q, soly)
solx = ss.roots()[0][0]
#
return solx, soly
def example():
############################################
# How To Use This Script
##########################################
#
# The problem to solve (edit the following values)
#
# the modulus
N = 0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27
# the public exponent
e = 0x11722b54dd6f3ad9ce81da6f6ecb0acaf2cbc3885841d08b32abc0672d1a7293f9856db8f9407dc05f6f373a2d9246752a7cc7b1b6923f1827adfaeefc811e6e5989cce9f00897cfc1fc57987cce4862b5343bc8e91ddf2bd9e23aea9316a69f28f407cfe324d546a7dde13eb0bd052f694aefe8ec0f5298800277dbab4a33bb
# the cipher
c = 0xe3505f41ec936cf6bd8ae344bfec85746dc7d87a5943b3a7136482dd7b980f68f52c887585d1c7ca099310c4da2f70d4d5345d3641428797030177da6cc0d41e7b28d0abce694157c611697df8d0add3d900c00f778ac3428f341f47ecc4d868c6c5de0724b0c3403296d84f26736aa66f7905d498fa1862ca59e97f8f866c
# the hypothesis on the private exponent (the theoretical maximum is 0.292)
delta = .28 # this means that d < N^delta
#
# Lattice (tweak those values)
#
# you should tweak this (after a first run), (e.g. increment it until a solution is found)
m = 4 # size of the lattice (bigger the better/slower)
# you need to be a lattice master to tweak these
t = int((1-2*delta) * m) # optimization from Herrmann and May
X = 2*floor(N^delta) # this _might_ be too much
Y = floor(N^(1/2)) # correct if p, q are ~ same size
#
# Don't touch anything below
#
# Problem put in equation
P.<x,y> = PolynomialRing(ZZ)
A = int((N+1)/2)
pol = 1 + x * (A + y)
#
# Find the solutions!
#
# Checking bounds
if debug:
print( "=== checking values ===")
print( "* delta:", delta)
print( "* delta < 0.292", delta < 0.292)
print( "* size of e:", int(log(e)/log(2)))
print( "* size of N:", int(log(N)/log(2)))
print( "* m:", m, ", t:", t)
# boneh_durfee
if debug:
print( "=== running algorithm ===")
start_time = time.time()
solx, soly = boneh_durfee(pol, e, m, t, X, Y)
# found a solution?
if solx > 0:
print( "=== solution found ===")
if False:
print( "x:", solx)
print( "y:", soly)
d = int(pol(solx, soly) / e)
m = pow(c,d,N)
print( '[-]d is ' + str(d))
print( '[-]m is: ' + str(m))
print( '[-]hex(m) is: ' + '{:x}'.format(int(m)))
else:
print( "[!]no solution was found!")
print( '[!]All Done!')
if debug:
print(("[!]Timer: %s s" % (time.time() - start_time)))
print( '[!]All Done!')
if __name__ == "__main__":
example()
用sage运行得到
'\nSetting debug to true will display more informations\nabout the lattice, the bounds, the vectors...\n'
"\nSetting strict to true will stop the algorithm (and\nreturn (-1, -1)) if we don't have a correct \nupperbound on the determinant. Note that this \ndoesn't necesseraly mean that no solutions \nwill be found since the theoretical upperbound is\nusualy far away from actual results. That is why\nyou should probably use `strict = False`\n"
"\nThis is experimental, but has provided remarkable results\nso far. It tries to reduce the lattice as much as it can\nwhile keeping its efficiency. I see no reason not to use\nthis option, but if things don't work, you should try\ndisabling it\n"
" \nReturns:\n* 0,0 if it fails\n* -1,-1 if `strict=true`, and determinant doesn't bound\n* x0,y0 the solutions of `pol`\n"
=== checking values ===
* delta: 0.280000000000000
* delta < 0.292 True
* size of e: 1020
* size of N: 1023
* m: 4 , t: 1
=== running algorithm ===
* removing unhelpful vectors 4 and 5
* removing unhelpful vector 3
* removing unhelpful vectors 1 and 2
* removing unhelpful vector 0
5 / 10 vectors are not helpful
We do not have det < bound. Solutions might not be found.
Try with highers m and t.
size det(L) - size e^(m*n) = 698
00 X 0 0 0 0 0 0 0 0 0 ~
01 X X 0 0 0 0 0 0 0 0 ~
02 X X X 0 0 0 0 0 0 0
03 X X X X 0 0 0 0 0 0
04 0 0 0 0 X 0 0 0 0 0 ~
05 0 0 0 0 X X 0 0 0 0 ~
06 0 0 0 0 X X X 0 0 0 ~
07 0 0 0 0 X X X X 0 0
08 0 0 0 0 X X X X X 0
09 X X X X 0 X X X X X
optimizing basis of the lattice via LLL, this can take a long time
LLL is done!
looking for independent vectors in the lattice
found them, using vectors 0 and 1
=== solution found ===
[-]d is 776765455081795377117377680209510234887230129318575063382634593357724998207571
[-]m is: 5616256644474643777324927156425296308201436356404797635226215853608752109375728559177663257634746748367999648544612395127292284761610833552163188225026856
[-]hex(m) is: 6b3bb0cdc72a7f2ce89902e19db0fb2c0514c76874b2ca4113b86e6dc128d44cc859283db4ca8b0b5d9ee35032aec8cc8bb96e8c11547915fc9ef05aa2d72b28
[!]Timer: 0.20359492301940918 s
[!]All Done!
将十六进制m输入
得到
challenge6 completed
flag{e9b59814-1f96-4636-a338-dc616f2793de}
终于