强网杯2019 Copperstudy
做之前很爽,做之后更爽
前提说明:百度的wp没看到第0题以为没wp然后饱受摧残做到最后,特写此文纪念下
惨遭社会毒打的我
打开题目:
nc ip port
我做的时候直接用的复现,也就是那个GitHub链接(关键坑比的地方就在这里,等碰到的时候再说
第0题
[+]proof: skr=os.urandom(8)
[+]hashlib.sha256(skr).hexdigest()=9987a7715e30a05b29c1fae9c8647fb2a1046589e8fe9b684e75754f86d26c79
[+]skr[0:5].encode('hex')=2127654d44
[-]skr.encode('hex')=
好家伙,第一题直接一波劝退,我当时看到人傻了,先看下代码
import os
os.urandom(i) #基于系统生成长度为i随机byte字节的数据
他给出了m的0-5的数据
[+]skr[0:5].encode('hex')=f708e349be
直接解密,传统艺能导入
from Crypto.Util.number import *
m = long_to_bytes(0xf708e349be)
print(m) #b'\xf7\x08\xe3I\xbe'
一看这怎么不像5长度的样子,开始进入蒙蔽状态,测试
>>>a = os.random(8)#b'\x00p\xaf\xbf\xf6\xc1\x10\xe9'
>>>a[0]
\x00
>>>a[1]
p
>>>a[2]
\xbf
...
测了半天,发现他os.urandom出来的数据就是0-255的chr值,可见字符他就转换,不可见他就变成\xXY的形式,其中XY的范围是00-ff。
发现这个规律之后我立马来了思路,这不就是穷举法嘛,已经给出了5个长度的数据,也就是说剩下的3个数据的组合最多有256^3种可能性,虽然感觉数据量大,但对于现代计算机这点复杂度更本不算什么
然后我这样做了,然后我没做出来…
后来想想这是第0题啊,太丢脸了,然后又莽上去了
测试了下长度为3的数据
from Crypto.Util.number import *
import os
test = []
for i in range(1000):
test.append(bytes_to_long(os.urandom(3)))
print(max(test))
print(min(test))
结果
一看觉得可能会有区间可循,因为想到本来他这个随机性很强,不如试试long_to_bytes的爆破,我出于小心,选择最低1w,最高2000w的区间,并且十分相信我的电脑
from Crypto.Util.number import *
import hashlib
for i in range(10000,20000000):
tar = 0x48dac257f3
payload = long_to_bytes(i)
payload = long_to_bytes(tar) + payload
if hashlib.sha256(payload).hexdigest() == '0b8debba71632360431d3c0a35395686c0ddfe4142ae4e068b5ec6d36b8dcfd1' :
print(i)
break
还真打出来了
这里跑到511w只花了1分多钟,时间还算合理的趴
然后只要把跑出来的数据hex拼接到前面给出的5个数据后面前面加个0x就行了
注意:每次系统的urandom值不同,每次刷新都要重跑
第1题
总算到了第一题,拿到题目[+]Generating challenge 1
[+]n=13112061820685643239663831166928327119579425830632458568801544406506769461279590962772340249183569437559394200635526183698604582385769381159563710823689417274479549627596095398621182995891454516953722025068926293512505383125227579169778946631369961753587856344582257683672313230378603324005337788913902434023431887061454368566100747618582590270385918204656156089053519709536001906964008635708510672550219546894006091483520355436091053866312718431318498783637712773878423777467316605865516248176248780637132615807886272029843770186833425792049108187487338237850806203728217374848799250419859646871057096297020670904211
[+]e=3
[+]m=random.getrandbits(512)
[+]c=pow(m,e,n)=15987554724003100295326076036413163634398600947695096857803937998969441763014731720375196104010794555868069024393647966040593258267888463732184495020709457560043050577198988363754703741636088089472488971050324654162166657678376557110492703712286306868843728466224887550827162442026262163340935333721705267432790268517
[+]((m>>72)<<72)=2519188594271759205757864486097605540135407501571078627238849443561219057751843170540261842677239681908736
拿到题目我先努力保持冷静
好,开始看题
先测个位数,好家伙,一看2047位,e=3,这波问题很大,m是512位的random数据,测下
懂得都懂,老懂哥了
from Crypto.Util.number import *
import gmpy2
c=15987554724003100295326076036413163634398600947695096857803937998969441763014731720375196104010794555868069024393647966040593258267888463732184495020709457560043050577198988363754703741636088089472488971050324654162166657678376557110492703712286306868843728466224887550827162442026262163340935333721705267432790268517
m = gmpy2.iroot(c,3)[0]
print(long_to_bytes(m))
唯一疑惑的就是最后的m给了不知道一个啥玩意,反正做出来就不管了
第2题
[+]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')=
第一眼进来就看了e, 65537 …
继续看,n,e,c,还有一个p,看样子是本题的突破口了
有一说一,确实是这样的
((p>>128)<<128)=97522826022187678545924975588711975512906538181361325096919121233043973599759518562689050415761485716705615149641768982838255403594331293651224395590747133152128042950062103156564440155088882592644046069208405360324372057140890317518802130081198060093576841538008960560391380395697098964411821716664506908672
也只能来看看这是什么jb玩意,我拿了几个数据测试了一下,发现自己原来进制运算还不是很熟,这里的运算时<< >>位移运算,也就是p右移128位再左移128位,右移直接吞左移不足位补零
也就是说这里给出p的最后128位去除补0并转换为10进制的值
明白的人已经在百度了
已知p的高位攻击,payload:
//sage
//p4已知高位
p4 = 286593827663265980875510954967316219073448170030900062579915534986706486906458307884391633081975974889868808093084141196610789229262338742207816117361927894904776552676541036673244090334164798443162932914355966770450894047111793505063044583029134192122352988382684883337
n = 12784625729032789592766625203074018101354917751492952685083808825504221816847310910447532133616954262271205877651255598995305639194329607493047941212754523879402744065076183778452640602625242851184095546100200565113016690161053808950384458996881574266573992526357954507491397978278604102524731393059303476350167738237822647246425836482533150025923051544431330502522043833872580483142594571802189321599016725741260254170793393777293145010525686561904427613648184843619301241414264343057368192416551134404100386155751297424616254697041043851852081071306219462991969849123668248321130382231769250865190227630009181759219
//全位数
pbits = 1024
缺省位数
kbits = pbits - p4.nbits()
print (p4.nbits())
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
x0 = f.small_roots(X=2^kbits, beta=0.4)[0]
print ("x:" ,hex(int(x0)))
p = p4+x0
print ("p: ", hex(int(p)))
assert n % p == 0
q = n/int(p)
print ("q: ", hex(int(q)))
注意:payload里的p是去过位数的值,也就是上面的p要>>128放入payload中
解出来p,q 然后有手就行,就不写了
第3题
[+]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)