SCTF2024-crypto
因为解出了所有密码,故发一篇wp吗,都是脚本,没讲原理。(还有一题问卷,其他都没做(出来)
(虽然都是简单题,虽然都是能找到脚本的题,虽然我都不会,虽然我不会格,但你就说我解没解没解出来吧)
(感谢鸡块师傅,太崇拜了)
Signin
xyctf中的factor3
(只能说,xyctf的含金量还在提高)
鸡块师傅的博客:2024-XYCTF-wp-crypto | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)
能够得(猜)到如下式子:
合并同类型得到:
最后得到:
令x=k,y=p+q,得到模e下的多项式
"""from sage.all import * from Crypto.Util.number import * from hashlib import md5 class RSA(): def __init__(self, nbits): self.nbits = nbits self.p, self.q = self.getPrimes() self.n = self.p*self.q self.Gift = self.Gift() self.priv, self.pub = self.keyGen() def getPrimes(self): nbits = self.nbits p = random_prime(2^(nbits-1),lbound=2^(nbits-2)) q = random_prime(2^(nbits-1),lbound=2^(nbits-2)) while p == q: q = random_prime(2^(nbits-1),lbound=2^(nbits-2)) return p,q def Gift(self): p,q = self.p, self.q return (p^2 + p + 1)*(q^2 + q + 1) def keyGen(self): nbits = self.nbits while True: d = randint(2^(nbits//4),2^(nbits//2)) if gcd(d,self.Gift) != 1: d = randint(2^(nbits//4),2^(nbits//2)) e = pow(d,-1,self.phi) return (self.p,self.q,self.n,e,d),(self.n,e) RRR = RSA(512) bp = long_to_bytes(int(RRR.p)) FLAG = 'SCTF{'+md5(bp).hexdigest()+'}' print(f'N = {RRR.n}') print(f'e = {RRR.pub[1]}')""" from Crypto.Util.number import * from gmpy2 import * import itertools def small_roots(f, bounds, m=1, d=None): if not d: d = f.degree() R = f.base_ring() N = R.cardinality() f /= f.coefficients().pop(0) f = f.change_ring(ZZ) G = Sequence([], f.parent()) for i in range(m + 1): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g) B, monomials = G.coefficient_matrix() monomials = vector(monomials) factors = [monomial(*bounds) for monomial in monomials] for i, factor in enumerate(factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor in enumerate(factors): B.rescale_col(i, 1 / factor) H = Sequence([], f.parent().change_ring(QQ)) for h in filter(None, B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots return [] n = 32261421478213846055712670966502489204755328170115455046538351164751104619671102517649635534043658087736634695616391757439732095084483689790126957681118278054587893972547230081514687941476504846573346232349396528794022902849402462140720882761797608629678538971832857107919821058604542569600500431547986211951 e = 334450817132213889699916301332076676907807495738301743367532551341259554597455532787632746522806063413194057583998858669641413549469205803510032623432057274574904024415310727712701532706683404590321555542304471243731711502894688623443411522742837178384157350652336133957839779184278283984964616921311020965540513988059163842300284809747927188585982778365798558959611785248767075169464495691092816641600277394649073668575637386621433598176627864284154484501969887686377152288296838258930293614942020655916701799531971307171423974651394156780269830631029915305188230547099840604668445612429756706738202411074392821840 PR.<x,y>=PolynomialRing(Zmod(e)) f = 1 + x*(n^2-n+1 + (n+1)*y + y^2) res = small_roots(f, (2^256,2^512), m=2, d=3) pplusq = int(res[0][1]) pminusq = iroot(pplusq^2-4*n,2)[0] p = (pplusq + pminusq) // 2 q = n // p from hashlib import md5 print('SCTF{'+md5(long_to_bytes(int(p))).hexdigest()+'}') #SCTF{12899cda850fc484de8bce978839620d} print('SCTF{'+md5(long_to_bytes(int(q))).hexdigest()+'}')
不完全阻塞干扰
一部分加密代码
msg = bytes_to_long(FLAG) n = p^5*q^2 phi = p^4*(p-1)*q*(q-1) e = 65537 d = inverse(d,phi) c = pow(m,e,n)
证书分析,拿有效数据解base64转hex,中间一大段A就是d缺失的数据
-----BEGIN RSA PRIVATE KEY----- MIIIFQKCA4AGfwqk6XSmOh/+jVwj5dPEMWU65BzHRvMF9iqfGT8iSGy37xsnVjSB j0bQdSpROeGZGCcfoNfSe8Zg0rckFNCOpSyIN/lJx7rswwKboxcn7zvxINmSbALX QS8YfpjcVt0HuYfSzBka1WFkoUTyiy9woV0QVYik8n+7KJH8UnvWiQpfeVtcSEdq a/nftnt+Hrx7Gwhs0otYxolVv99E7M4R/6zfZUVRsVm3gyBAzCjujr6kj4Zy1T49 6I/Pu1+ydrUDiA3TTVmTM13fjMuWwbTXn1AtchBHZa2cKxhYoXrz1b5E+jy/S47r lCqjlCo4cdLGWscCiRI/wun5sly/y9eEEJYGD6UEw6B7WRSTxkyI0LtFKFqFtffV nbmPqgDCzT+7Y9pZkgXxyrDfUs97QxoO5KfjVpZUbOnQPvWV7O6S0hQskul9J0ST lwNFW0xw3sJ8Mh7GuDwCliLoOp4NVdCyWNldTmEpGGXdp23GGfzpV3mQQpxud+nU B4HjsvRJcBuD6LDGxm6zgPlkc+XUIu/uiysOiLcWsAp5ydUUyjrZ0t7lJmCf+VQX MqQZjRG52/uy5Vwk2A6lItB4bjNV8jYGpdOKct5O78i2v8SCJIooYstp2ODj0xZZ fanYCCi+hQVPrxX8NpyqyvuBXGlzwXGUBoPVahoZZ7Cbf/o/vlsuCGmXWdhNcWA/ UWRHaWuycyKmnzn2yiU+ANyVVdX5cygHDEZ/NmPMSJqtEw8oxC81v4jFcZIKuSrL j3XQPjWnUQPFvZbwYclr0Cr24dGRsN0WS8chN3AD7b9dPvZaXpBGOFNWtSFiO+43 8WSFCgp6+w7U5+i9mv4SmPfVMrya2UGBLTMq7OddHMyx/2n9QrMfJIrledng1qFL BUbnhLqUDjK9AcOV34/0WEBARitUefoHM21QPcMy5w/AbZRjKX/AQrYj1W+H76pS WptYDjFNkNEhGJPtQHomUI3qoKE8nujJArnhw6Av6aUUUsAu573MhcDv9jiR4kcD vSZdnJ2/RW4q+UCVOLzg/sx+urICZqqrBsdmw+ps2py5ul4dAkt9w9c+dvajMxl7 rYfE+zTVZaABSqxygl5Brc/q2tyHrO9ArYS3xVaRq61WG+BVDqCpiEcMQnQyrLj+ srnS0lmPsgibuRu9nLGZ6JLTYWTYvz7NVFdqlxNAR6EtqEIHSFu05QIDAQABAoID gAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoGBAIBj0KIYduXOHiEB wgAVUpBm7Zl2iC0QAqKe/g8v38wnQ/yaS1tlHMlxCGmeyi+x89kxdbrjQ+fJLkpB xy0F5XAZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoGBAOTw/kn5rhSSwJegqYj6cYdmJf5PzgWw IE8f30PsZLTaxpnSjhZu/fx1YtGeWMNJPZEANlzyhAtGwPbujZZIBxcP8sE8TrgB LsqzeGKjkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAA 30 82 0815 n 02 82 0380 067f0aa4e974a63a1ffe8d5c23e5d3c431653ae41cc746f305f62a9f193f22486cb7ef1b275634818f46d0752a5139e19918271fa0d7d27bc660d2b72414d08ea52c8837f949c7baecc3029ba31727ef3bf120d9926c02d7412f187e98dc56dd07b987d2cc191ad56164a144f28b2f70a15d105588a4f27fbb2891fc527bd6890a5f795b5c48476a6bf9dfb67b7e1ebc7b1b086cd28b58c68955bfdf44ecce11ffacdf654551b159b7832040cc28ee8ebea48f8672d53e3de88fcfbb5fb276b503880dd34d5993335ddf8ccb96c1b4d79f502d72104765ad9c2b1858a17af3d5be44fa3cbf4b8eeb942aa3942a3871d2c65ac70289123fc2e9f9b25cbfcbd7841096060fa504c3a07b591493c64c88d0bb45285a85b5f7d59db98faa00c2cd3fbb63da599205f1cab0df52cf7b431a0ee4a7e35696546ce9d03ef595ecee92d2142c92e97d2744939703455b4c70dec27c321ec6b83c029622e83a9e0d55d0b258d95d4e61291865dda76dc619fce9577990429c6e77e9d40781e3b2f449701b83e8b0c6c66eb380f96473e5d422efee8b2b0e88b716b00a79c9d514ca3ad9d2dee526609ff9541732a4198d11b9dbfbb2e55c24d80ea522d0786e3355f23606a5d38a72de4eefc8b6bfc482248a2862cb69d8e0e3d316597da9d80828be85054faf15fc369caacafb815c6973c171940683d56a1a1967b09b7ffa3fbe5b2e08699759d84d71603f516447696bb27322a69f39f6ca253e00dc9555d5f97328070c467f3663cc489aad130f28c42f35bf88c571920ab92acb8f75d03e35a75103c5bd96f061c96bd02af6e1d191b0dd164bc721377003edbf5d3ef65a5e9046385356b521623bee37f164850a0a7afb0ed4e7e8bd9afe1298f7d532bc9ad941812d332aece75d1cccb1ff69fd42b31f248ae579d9e0d6a14b0546e784ba940e32bd01c395df8ff4584040462b5479fa07336d503dc332e70fc06d9463297fc042b623d56f87efaa525a9b580e314d90d1211893ed407a26508deaa0a13c9ee8c902b9e1c3a02fe9a51452c02ee7bdcc85c0eff63891e24703bd265d9c9dbf456e2af9409538bce0fecc7ebab20266aaab06c766c3ea6cda9cb9ba5e1d024b7dc3d73e76f6a333197bad87c4fb34d565a0014aac72825e41adcfeadadc87acef40ad84b7c55691abad561be0550ea0a988470c427432acb8feb2b9d2d2598fb2089bb91bbd9cb199e892d36164d8bf3ecd54576a97134047a12da84207485bb4e5 e 02 03 010001 d.... p AoGBAIBj0KIYduXOHiEBwgAVUpBm7Zl2iC0QAqKe/g8v38wnQ/yaS1tlHMlxCGmeyi+x89kxdbrjQ+fJLkpBxy0F5XAZQ 02 8181 008063d0a21876e5ce1e2101c20015529066ed9976882d1002a29efe0f2fdfcc2743fc9a4b5b651cc97108699eca2fb1f3d93175bae343e7c92e4a41c72d05e57019 q AoGBAOTw/kn5rhSSwJegqYj6cYdmJf5PzgWwIE8f30PsZLTaxpnSjhZu/fx1YtGeWMNJPZEANlzyhAtGwPbujZZIBxcP8sE8TrgBLsqzeGKjk 02 8181 00e4f0fe49f9ae1492c097a0a988fa71876625fe4fce05b0204f1fdf43ec64b4dac699d28e166efdfc7562d19e58c3493d9100365cf2840b46c0f6ee8d964807170ff2c13c4eb8012ecab37862a3
分析出来之后就是p高位和q高位,二元copper就行了
from Crypto.Util.number import * from gmpy2 import * import itertools def small_roots(f, bounds, m=1, d=None): if not d: d = f.degree() R = f.base_ring() N = R.cardinality() f /= f.coefficients().pop(0) f = f.change_ring(ZZ) G = Sequence([], f.parent()) for i in range(m + 1): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g) B, monomials = G.coefficient_matrix() monomials = vector(monomials) factors = [monomial(*bounds) for monomial in monomials] for i, factor in enumerate(factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor in enumerate(factors): B.rescale_col(i, 1 / factor) H = Sequence([], f.parent().change_ring(QQ)) for h in filter(None, B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots return [] n=0x067f0aa4e974a63a1ffe8d5c23e5d3c431653ae41cc746f305f62a9f193f22486cb7ef1b275634818f46d0752a5139e19918271fa0d7d27bc660d2b72414d08ea52c8837f949c7baecc3029ba31727ef3bf120d9926c02d7412f187e98dc56dd07b987d2cc191ad56164a144f28b2f70a15d105588a4f27fbb2891fc527bd6890a5f795b5c48476a6bf9dfb67b7e1ebc7b1b086cd28b58c68955bfdf44ecce11ffacdf654551b159b7832040cc28ee8ebea48f8672d53e3de88fcfbb5fb276b503880dd34d5993335ddf8ccb96c1b4d79f502d72104765ad9c2b1858a17af3d5be44fa3cbf4b8eeb942aa3942a3871d2c65ac70289123fc2e9f9b25cbfcbd7841096060fa504c3a07b591493c64c88d0bb45285a85b5f7d59db98faa00c2cd3fbb63da599205f1cab0df52cf7b431a0ee4a7e35696546ce9d03ef595ecee92d2142c92e97d2744939703455b4c70dec27c321ec6b83c029622e83a9e0d55d0b258d95d4e61291865dda76dc619fce9577990429c6e77e9d40781e3b2f449701b83e8b0c6c66eb380f96473e5d422efee8b2b0e88b716b00a79c9d514ca3ad9d2dee526609ff9541732a4198d11b9dbfbb2e55c24d80ea522d0786e3355f23606a5d38a72de4eefc8b6bfc482248a2862cb69d8e0e3d316597da9d80828be85054faf15fc369caacafb815c6973c171940683d56a1a1967b09b7ffa3fbe5b2e08699759d84d71603f516447696bb27322a69f39f6ca253e00dc9555d5f97328070c467f3663cc489aad130f28c42f35bf88c571920ab92acb8f75d03e35a75103c5bd96f061c96bd02af6e1d191b0dd164bc721377003edbf5d3ef65a5e9046385356b521623bee37f164850a0a7afb0ed4e7e8bd9afe1298f7d532bc9ad941812d332aece75d1cccb1ff69fd42b31f248ae579d9e0d6a14b0546e784ba940e32bd01c395df8ff4584040462b5479fa07336d503dc332e70fc06d9463297fc042b623d56f87efaa525a9b580e314d90d1211893ed407a26508deaa0a13c9ee8c902b9e1c3a02fe9a51452c02ee7bdcc85c0eff63891e24703bd265d9c9dbf456e2af9409538bce0fecc7ebab20266aaab06c766c3ea6cda9cb9ba5e1d024b7dc3d73e76f6a333197bad87c4fb34d565a0014aac72825e41adcfeadadc87acef40ad84b7c55691abad561be0550ea0a988470c427432acb8feb2b9d2d2598fb2089bb91bbd9cb199e892d36164d8bf3ecd54576a97134047a12da84207485bb4e5 e=0x10001 c=145554802564989933772666853449758467748433820771006616874558211691441588216921262672588167631397770260815821197485462873358280668164496459053150659240485200305314288108259163251006446515109018138298662011636423264380170119025895000021651886702521266669653335874489612060473962259596489445807308673497717101487224092493721535129391781431853820808463529747944795809850314965769365750993208968116864575686200409653590102945619744853690854644813177444995458528447525184291487005845375945194236352007426925987404637468097524735905540030962884807790630389799495153548300450435815577962308635103143187386444035094151992129110267595908492217520416633466787688326809639286703608138336958958449724993250735997663382433125872982238289419769011271925043792124263306262445811864346081207309546599603914842331643196984128658943528999381048833301951569809038023921101787071345517702911344900151843968213911899353962451480195808768038035044446206153179737023140055693141790385662942050774439391111437140968754546526191031278186881116757268998843581015398070043778631790328583529667194481319953424389090869226474999123124532354330671462280959215310810005231660418399403337476289138527331553267291013945347058144254374287422377547369897793812634181778309679601143245890494670013019155942690562552431527149178906855998534415120428884098317318129659099377634006938812654262148522236268027388683027513663867042278407716812565374141362015467076472409873946275500942547114202939578755575249750674734066843408758067001891408572444119999801055605577737379889503505649865554353749621313679734666376467890526136184241450593948838055612677564667946098308716892133196862716086041690426537245252116765796203427832657608512488619438752378624483485364908432609100523022628791451171084583484294929190998796485805496852608557456380717623462846198636093701726099310737244471075079541022111303662778829695340275795782631315412134758717966727565043332335558077486037869874106819581519353856396937832498623662166446395755447101393825864584024239951058366713573567250863658531585064635727070458886746791722270803893438211751165831616861912569513431821959562450032831904268205845224077709362068478 hp=0x008063d0a21876e5ce1e2101c20015529066ed9976882d1002a29efe0f2fdfcc2743fc9a4b5b651cc97108699eca2fb1f3d93175bae343e7c92e4a41c72d05e57019 hq=0x00e4f0fe49f9ae1492c097a0a988fa71876625fe4fce05b0204f1fdf43ec64b4dac699d28e166efdfc7562d19e58c3493d9100365cf2840b46c0f6ee8d964807170ff2c13c4eb8012ecab37862a3 hp=hp<<504 hq=hq<<408 PR.<x,y>=PolynomialRing(Zmod(n)) f = (hp+x)^5*(hq+y)^2-n res = small_roots(f, (2^504,2^408), m=2, d=3) p=int(hp+res[0][0]) q=int(hq+res[0][1]) print(long_to_bytes(int(pow(c,invert(e,p^4*(p-1)*q*(q-1)),n)))) #SCTF{0ne_4rgum3nt_1s_r0tt3n_0r4ng3s,_th3_wh0le_cert1fic4t3_1s_r0tt3n_0r4ng3s:XD}
Whisper
cert1.pem
-----BEGIN PUBLIC KEY-----
MIIBHjANBgkqhkiG9w0BAQEFAAOCAQsAMIIBBgKBgBtdT+CqZ4LiddTOEqbVdWLv
u+fbb1J3JVuJFym/oqGNPttJhD15iaN7lRa+LfjKk5BY5l9ktfsgcb6k9fjROSiV
syvwN32Z9PeZeRJeXbAc21CAocLWZcmsMbWCMCVJnJUTJ3uuXnqEbNJxxDluK6IZ
Ag5YqQVcsYoo02oAv3F7AoGAB59czGZXZ7SiV+XB/1bpgD3y5WUDAtqtQgEF/mck
R3Q70/C+ocRqSYeTLpqIbKh6ev13lqvx5WKcSYb+TyLonNznq7BmJEZRRqLitsqa
sxls6rdGeXTB3EVgiiAEEbKR/a+Z99gNzk2zVm9Kni5XTGIkzQfYBjjSj3ggvPS0
kUM=
-----END PUBLIC KEY-----
cert2.pem
-----BEGIN PUBLIC KEY-----
MIIBHjANBgkqhkiG9w0BAQEFAAOCAQsAMIIBBgKBgAccMk6HaUkxh8FfctXMaVcp
tISI7j+9AdsA1cR48Ix88yCTumF0UFHT6dFpUjqpFDgYH0dnmv9e3SKVD3Sh6xRD
MgqqXZf1wegbXvmj5pumaavExsS0BfUIimA6dPm874iCO0UjV0EUyBBgCDhygZb4
5eDUru7qt53YaDpy88AXAoGAB59czGZXZ7SiV+XB/1bpgD3y5WUDAtqtQgEF/mck
R3Q70/C+ocRqSYeTLpqIbKh6ev13lqvx5WKcSYb+TyLonNznq7BmJEZRRqLitsqa
sxls6rdGeXTB3EVgiiAEEbKR/a+Z99gNzk2zVm9Kni5XTGIkzQfYBjjSj3ggvPS0
kUM=
-----END PUBLIC KEY-----
题目描述
Two public key certificates were monitored. And Mr. Dual intercepted a ciphertext. Just when he was in the rough, a Careless Whisper told that the length of a key parameter is carelessly set to 345 bits.
密文的16进制数据
15aadf434f05fc47e06f6997a554c1de7cecdad1faf40a74bc7c6d7c4c5fa533fe2c605bcde6acaa0ee3576f607be6503831b33d54928eaad1f8d64187cff8f4f1a67ff6d846715bfc4795b22e216ec7ec92106db6a1fdeb9d649968a81cbb10a3e5c828167af2fd0e81534f11198b63caad0ed8e9f844db8403027ba3eb1a56
是dual rsa,我没见过的东西,所以搜索引擎启动。
我自己能想到连分数处理的,但是写不出来,找了一篇博客https://hasegawaazusa.github.io/dual-rsa-note.html,但也解不出来,然后就开始,找脚本啊找脚本,找到一个好脚本。
参数什么的没动,n1,n2,e可以手工读公钥文件提取(因为我n2无法直接读)
(贴给gpt让它将py2转成py3就行了)
from sage.all import * import math from Crypto.Util.number import * # display matrix picture with 0 and X def matrix_overview(BB): for ii in range(BB.dimensions()[0]): a = '{:02d} '.format(ii) for jj in range(BB.dimensions()[1]): a += ' ' if BB[ii, jj] == 0 else 'X' if BB.dimensions()[0] < 60: a += ' ' print(a) def dual_rsa_liqiang_et_al(e, n1, n2, delta, mm, tt): N = (n1 + n2) // 2 A = ZZ(math.floor(N**0.5)) _XX = ZZ(math.floor(N**delta)) _YY = ZZ(math.floor(N**0.5)) _ZZ = ZZ(math.floor(N**(delta - 1./4))) _UU = _XX * _YY + 1 M = Matrix(ZZ, [[A, e], [0, n1]]) B = M.LLL() l11, l12 = B[0] l21, l22 = B[1] l_11 = ZZ(l11 / A) l_21 = ZZ(l21 / A) modulo = e * l_21 F = Zmod(modulo) PR = PolynomialRing(F, 'u, x, y, z') u, x, y, z = PR.gens() PK = PolynomialRing(ZZ, 'uk, xk, yk, zk') uk, xk, yk, zk = PK.gens() PQ = PK.quo(xk * yk + 1 - uk) f = PK(x * (n2 + y) - e * l_11 * z + 1) fbar = PQ(f).lift() gijk = {} for k in range(mm + 1): for i in range(mm - k + 1): for j in range(mm - k - i + 1): gijk[i, j, k] = PQ(xk**i * zk**j * PK(fbar)**k * modulo**(mm - k)).lift() hjkl = {} for j in range(1, tt + 1): for k in range(math.floor(mm / tt) * j, mm + 1): for l in range(k + 1): hjkl[j, k, l] = PQ(yk**j * zk**(k - l) * PK(fbar)**l * modulo**(mm - l)).lift() monomials = [] for k in gijk.keys(): monomials += gijk[k].monomials() for k in hjkl.keys(): monomials += hjkl[k].monomials() monomials = sorted(set(monomials), reverse=True) assert len(monomials) == len(gijk) + len(hjkl) dim = len(monomials) M = Matrix(ZZ, dim) row = 0 for k in gijk.keys(): for i, monomial in enumerate(monomials): M[row, i] = gijk[k].monomial_coefficient(monomial) * monomial.subs(uk=_UU, xk=_XX, yk=_YY, zk=_ZZ) row += 1 for k in hjkl.keys(): for i, monomial in enumerate(monomials): M[row, i] = hjkl[k].monomial_coefficient(monomial) * monomial.subs(uk=_UU, xk=_XX, yk=_YY, zk=_ZZ) row += 1 matrix_overview(M) print('=' * 128) B = M.LLL() matrix_overview(B) H = [(i, 0) for i in range(dim)] H = dict(H) for j in range(dim): for i in range(dim): H[i] += PK((monomials[j] * B[i, j]) / monomials[j].subs(uk=_UU, xk=_XX, yk=_YY, zk=_ZZ)) H = list(H.values()) PQ = PolynomialRing(QQ, 'uq, xq, yq, zq') uq, xq, yq, zq = PQ.gens() for i in range(dim): H[i] = PQ(H[i].subs(uk=xk * yk + 1)) I = Ideal(*H[1:20]) g = I.groebner_basis('giac')[::-1] mon = [t.monomials() for t in g] PX = PolynomialRing(ZZ, 'xs') xs = PX.gen() x_pol = y_pol = z_pol = None for i in range(len(g)): if mon[i] == [xq, 1]: print(g[i] / g[i].lc()) x_pol = g[i] / g[i].lc() elif mon[i] == [yq, 1]: print(g[i] / g[i].lc()) y_pol = g[i] / g[i].lc() elif mon[i] == [zq, 1]: print(g[i] / g[i].lc()) z_pol = g[i] / g[i].lc() if x_pol is None or y_pol is None or z_pol is None: print('[-] Failed: we cannot get a solution...') return x0 = x_pol.subs(xq=xs).roots()[0][0] y0 = y_pol.subs(yq=xs).roots()[0][0] z0 = z_pol.subs(zq=xs).roots()[0][0] assert f(x0 * y0 + 1, x0, y0, z0) % modulo == 0 a0 = z0 a1 = (x0 * (n2 + y0) + 1 - e * l_11 * z0) / (e * l_21) d = a0 * l_11 + a1 * l_21 return d if __name__ == '__main__': delta = 0.334 mm = 4 tt = 2 n1=0x1b5d4fe0aa6782e275d4ce12a6d57562efbbe7db6f5277255b891729bfa2a18d3edb49843d7989a37b9516be2df8ca939058e65f64b5fb2071bea4f5f8d1392895b32bf0377d99f4f79979125e5db01cdb5080a1c2d665c9ac31b5823025499c9513277bae5e7a846cd271c4396e2ba219020e58a9055cb18a28d36a00bf717b n2=0x071c324e8769493187c15f72d5cc695729b48488ee3fbd01db00d5c478f08c7cf32093ba61745051d3e9d169523aa91438181f47679aff5edd22950f74a1eb1443320aaa5d97f5c1e81b5ef9a3e69ba669abc4c6c4b405f5088a603a74f9bcef88823b4523574114c810600838728196f8e5e0d4aeeeeab79dd8683a72f3c017 e=0x079f5ccc665767b4a257e5c1ff56e9803df2e5650302daad420105fe672447743bd3f0bea1c46a4987932e9a886ca87a7afd7796abf1e5629c4986fe4f22e89cdce7abb06624465146a2e2b6ca9ab3196ceab7467974c1dc45608a200411b291fdaf99f7d80dce4db3566f4a9e2e574c6224cd07d80638d28f7820bcf4b49143 d1 = dual_rsa_liqiang_et_al(e, n1, n2, delta, mm, tt) c=open('ciphertext.txt','rb').read() c=bytes_to_long(c) flag=long_to_bytes(int(pow(c,int(d1),n1))) if b"SCTF" in flag: print(flag) # https://elliptic-shiho.github.io/ctf-writeups/#!ctf/2017/0CTF%20Finals/cr1000-AuthenticationSecrecy/README.md # b'SCTF{Ju5t_3njoy_th3_Du4l_4nd_Copper5m1th_m3thod_w1th_Ur_0wn_1mplem3nt4t10n}'
LinearARTs
from random import choices import json from sage.all import * from Crypto.Util.number import * from sage.groups.perm_gps.permgroup_named import SymmetricGroup def Young(FLAG): f = int.from_bytes(FLAG, "big") q = 65537 s = [] while f: s.append(f % q) f //= q s = vector(GF(q), s) n, m = len(s), len(s) ** 2 A = Matrix(GF(q), m, n, lambda i, j: randint(0, q - 1)) e = vector(choices(range(2^8), k=m), GF(q))*Matrix(ZZ,PermutationGroupElement(SymmetricGroup(m).random_element()).matrix()) b = (A*s) + e return A,b def Old(m, nbits): Sn = SymmetricGroup(m) p = [getPrime(360) for i in range(m)] N = sorted([getRandomNBitInteger(nbits) for _ in range(m)]) S = [] for i in range(m): r = [N[_] % p[i] for _ in range(m)] r = vector(ZZ,r) Per = Sn.random_element() P = PermutationGroupElement(Per) Pm = Matrix(ZZ,P.matrix()) r *= Pm S.append(r) S = matrix(ZZ,S) with open('Old.matrix','w') as f: json.dump({"S": str(list(S)),"p": str(p)}, f) return N def chall(nn): # The challenge lasted nn rounds # Young_level * virtue >= Old_level , where virtue = nn + 1 h = [] HP = [] MP = [] Old_level = 625*2*2 Young_level = 25*5*5*2 M = getPrime(Old_level) XP = getRandomRange(1,M) for _ in range(nn): a = getRandomRange(1,M) b = a*XP % M HP.append(a) MP.append(b) delta_level = Old_level - Young_level h.append(b >> delta_level << delta_level) return XP,M,HP,MP,h mm = 16 nn = 9 nbits = 3840 A,b = Young(FLAG) N = Old(mm, nbits) XP,M,HP,MP,h = chall(nn) # MP is useful ,I can use him to cast five lightning spells D = diagonal_matrix(GF(0x10001),N+MP) Sn = SymmetricGroup(5*5) Per = Sn.random_element() P = PermutationGroupElement(Per) PM = Matrix(GF(0x10001),P.matrix()) AA = A*D*PM with open('D.matrix','w') as f: json.dump({"D": str(list(D))}, f) # OK! Find your martial arts, and then you can get the flag. with open("output.txt", "w") as f: json.dump({"AA": str(list(AA)), "b": str(b)}, f) print(f'My SymmetricGroup is {Sn}, and my element is {Per}') print(f'M = {M}') print(f'h = {h}') print(f'HP = {HP}') ''' My SymmetricGroup is Symmetric group of order 25! as a permutation group, and my element is (1,23,2,13,3,16,15,6,22,18,14,4,25,11,20,24,21,9,5,17,7,19,10,12,8) '''
只需要用到如下数据,其他数据都没用。
关键点在于
PM可以自己测试一下就可以自己生成了,D也直接给了,AA也有了
那A就可以直接算出来了,其他数据都是杂鱼。
之后看Young中就是一个lwe问题,我不会,所有搜索引擎再次启动。
再次感谢鸡块师傅,最后又是找他的脚本出了
https://tangcuxiaojikuai.xyz/post/758dd33a.html
import json from Crypto.Util.number import * with open('D.matrix', 'r') as file: data = json.load(file) D=eval(data['D']) D=Matrix(GF(0x10001),D) with open('output.txt', 'r') as file: data = json.load(file) AA=eval(data['AA']) AA=Matrix(GF(65537),AA) b=list(eval(data['b'])) ##### test if 0: Sn = SymmetricGroup(5*5) Per = Sn.random_element() P = PermutationGroupElement(Per) PM = Matrix(GF(0x10001),P.matrix()) print(Per) print(P) print(PM) #My SymmetricGroup is Symmetric group of order 25! as a permutation group, and my element is (1,23,2,13,3,16,15,6,22,18,14,4,25,11,20,24,21,9,5,17,7,19,10,12,8) P=(1,23,2,13,3,16,15,6,22,18,14,4,25,11,20,24,21,9,5,17,7,19,10,12,8) PM=[] for i in range(len(P)): PM.append([0]*25) for i in range(len(P)): PM[P[i]-1][P[(i+1)%len(P)]-1]=1 PM=Matrix(GF(0x10001),PM) AD=PM.solve_left(AA) A=D.solve_left(AD) # https://tangcuxiaojikuai.xyz/post/758dd33a.html def primal_attack2(A,b,m,n,p,esz): L = block_matrix( [ [matrix(Zmod(p), A).T.echelon_form().change_ring(ZZ), 0], [matrix.zero(m - n, n).augment(matrix.identity(m - n) * p), 0], [matrix(ZZ, b), 1], ] ) #print(L.dimensions()) Q = diagonal_matrix([1]*m + [esz]) L *= Q L = L.LLL() L /= Q res = L[0] if(res[-1] == 1): e = vector(GF(p), res[:m]) elif(res[-1] == -1): e = -vector(GF(p), res[:m]) s = matrix(Zmod(p), A).solve_right((vector(Zmod(p), b)-e)) return s f=primal_attack2(A,b,625,25,65537,2^8) print(f) m=0 for i in range(len(f)): m=m+65537^i*int(f[i]) print(long_to_bytes(int(m))) #b'SCTF{HunYu4n_TaiChi-5tyl3_P3rmut4t10nProup_m4st3r}'
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理