前言
这次ROARCTF我打得时间比较短,所以只做了Crypto_System,其余两题都是后来复现的…
Crypto_System
将式子都化简为以g为底的式子,这样可以将这题看起来的离散对数问题化简为简单的求逆元问题。由于可能求不出逆元,所以需要进行判断
(用Linux跑的)
from pwn import *
from libnum import *
from Crypto.Util.number import *
from hashlib import *
from gmpy2 import invert
# These three are constants
p = 12039102490128509125925019010000012423515617235219127649182470182570195018265927223
g = 10729072579307052184848302322451332192456229619044181105063011741516558110216720725
def int2str(data, mode="big"):
if mode == "little":
return sum([ord(data[_]) * 2 ** (8 * _) for _ in range(len(data))])
elif mode == "big":
return sum([ord(data[::-1][_]) * 2 ** (8 * _) for _ in range(len(data))])
def get_parameter(m):
x = int2str(m, 'little')
y = pow(g, x, p)
a = bytes_to_long(sha256(long_to_bytes(y).rjust(128, "\0")).digest())
b = pow(a, a, p - 1)
h = pow(g, b, p)
return y, h, b , x
def sign(m):
y, h, b = get_parameter(m)
r = getStrongPrime(512)
s = (y * pow(h, r, p)) % p
return str(r),str(s)
def verify(m, r, s):
y, h, b ,x= get_parameter(m)
if s == ((y * pow(h, r, p)) % p):
return True
else:
return False
def fuckhash():
xx=sh.recvuntil('XXXX:')
suffix=xx.split('+')[1].split(')')[0].strip(' ')
res=xx.split('==')[1].split('\n')[0].strip(' ')
print(suffix,res)
S = ''
for h in range(48,127):
S += chr(h)
for h in S:
for i in S:
for j in S:
for k in S:
x = sha256((h + i + j + k + suffix).encode()).hexdigest()
if x == res:
sh.sendline(h+i+j+k)
return (h + i + j + k)
def test(r1,r2,s1,s2):
if r1!=r2 and s1==s2 :
return True
else:
return False
def attack(m1,m2,r1):
(y1, h1, b1,x1) = get_parameter(m1)
(y2, h2, b2,x2) = get_parameter(m2)
s1 = (y1 * pow(h1, r1, p)) % p
b2_ = invert(int(b2),int(p-1))
r2 = b2_*(x1 -x2+ b1*r1)%(p-1)
print r2
s2 = (y2 * pow(h2, r2, p)) % p
print verify(m2, r2, s2)
print r2-r1
print test(r1,r2,s1,s2)
print ('r2,s2 = (%s,%s)')%(r2,s2)
sh.recvuntil('Please choice your options:')
sh.sendline('3')
sh.recvuntil("message:")
sh.sendline('('+str(r2)+','+str(s2)+')')
print sh.recvuntil('\n')
def judgee(m1,m2):
try:
(y1, h1, b1,x1) = get_parameter(m1)
(y2, h2, b2,x2) = get_parameter(m2)
b2_ = invert(int(b2),int(p-1))
return True
except:
return False
c=0
while True:
c+=1
print ("round:%s")%(c)
sh=remote('139.129.98.9',30001)
print(fuckhash())
drop = 'options:'
sh.recvuntil('(64 bytes):', drop=False)
m1 = sh.recvuntil('\n', drop=False)[:-1].decode('hex')
sh.recvuntil('(64 bytes):', drop=False)
m2 = sh.recvuntil('\n', drop=False)[:-1].decode('hex')
sh.recvuntil("'r':", drop=False)
r1 = sh.recvuntil('\n', drop=False)
r1=int(r1)
print m1
print m2
print r1
if judgee(m1,m2) == False:
continue
else:
print('right!')
attack(m1,m2,r1)
break
结果截图:
EasyRSA
根据给的tips我们可以得到 2 ∗ x ∗ y ∗ b e t a + x + y 2*x*y*beta + x + y 2∗x∗y∗beta+x+y,
然后又知 p h i ( n ) = 4 ∗ x ∗ y ∗ b e t a phi(n)=4*x*y*beta phi(n)=4∗x∗y∗beta
所以我们可以通过 t i p s / b e t a tips/beta tips/beta再爆破 x ∗ y x*y x∗y求出 p h i phi phi
from Crypto.Util.number import *
from gmpy2 import invert
n=17986052241518124152579698727005505088573670763293762110375836247355612011054569717338676781772224186355540833136105641118789391002684013237464006860953174190278718294774874590936823847040556879723368745745863499521381501281961534965719063185861101706333863256855553691578381034302217163536137697146370869852180388385732050177505306982196493799420954022912860262710497234529008765582379823928557307038782793649826879316617865012433973899266322533955187594070215597700782682186705964842947435512183808651329554499897644733096933800570431036589775974437965028894251544530715336418443795864241340792616415926241778326529055663
e=65537
enc=10760807485718247466823893305767047250503197383143218026814141719093776781403513881079114556890534223832352132446445237573389249010880862460738448945011264928270648357652595432015646424427464523486856294998582949173459779764873664665361437483861277508734208729366952221351049574873831620714889674755106545281174797387906705765430764314845841490492038801926675266705606453163826755694482549401843247482172026764635778484644547733877083368527255145572732954216461334217963127783632702980064435718785556011795841651015143521512315148320334442235923393757396733821710592667519724592789856065414299022191871582955584644441117223
beta=11864389277042761216996641604675717452843530574016671576684180662096506094587545173005905433938758559675517932481818900399893444422743930613073261450555599
tip = (n-1)//(2*beta)
xy1=tip//beta
def attack(xy1):
while True:
try:
xy1=xy1-2
d=invert(e,2*xy1*pow(beta,2))
c=pow(3,e,n)
if pow(c,d,n)==3:
return d
else:
continue
except:
continue
d=attack(xy1)
print long_to_bytes(pow(enc,d,n))
Reverse
参考 https://kt.gy/blog/2015/10/asis-2015-finals-rsasr/
因为p和q是二进制顺序相反的素数,所以p的每一位都和q有关系。所以我们可以尝试遍历p的二进制,通过判断生成的p与q再进行迭代。具体代码如下:
n = 158985980192501034004997692253209315116841431063210516613522548452327355222295231366801286879768949611058043390843949610463241574886852164907094966008463721486557469253652940169060186477803255769516068561042756903927308078335838348784208212701919950712557406983012026654876481867000537670622886437968839524889
def Brute_force(a,b,k):
if k == 256:
if a*b==n:
print (a,b)
return 0
for i in range(2):
for j in range(2):
a1=a+i*(2**(511-k))+j*(2**k)
b1=b+j*(2**(511-k))+i*(2**k)
if a1*b1>n:
continue
if (a1+2**(511-k))*((b1+2**(511-k)))< n:
continue
if (a1*b1)%(2**(k+1)) != n%(2**(k+1)):
continue
Brute_force(a1,b1,k+1)
return 0
Brute_force(0,0,0)
结尾
这三道题统一的地方在于都是使用了爆破这一基本手法。做题的话有时候会纠结于某一个知识点,纠结于某种固定的解法,这样往往会思维封闭。其实我们更应该常驻爆破的思想去解题。结合各种已知解法灵活运用才是更好的做题方法。