首先分析他的代码吧
def gen_args():
p=getPrime(1024)
q=getPrime(1024)
n=p*q
e=0x10001
d=primefac.modinv(e,(p-1)*(q-1))%((p-1)*(q-1))
return (p,q,e,n,d)
这里相当于随机生成了1024位的p和q,然后给了e,跟RSA的算法一样生成私钥d。继续分析
def proof():
salt=urandom(4)
print salt.encode("base64"),
proof=raw_input("show me your work: ")
if hashlib.md5(salt+proof.decode("base64")).hexdigest().startswith("0000"):
print "checked success"
return 1
return 0
第一段验证的程度,需要我们给一段base64编码的work,然后salt+work的md5的开头要是"0000",直接用代码爆破得到合适的work
salt=p.recvline()
msg = base64.b64decode(salt)
work=""
for i in count():
hashid = md5(msg+str(i)).hexdigest()
if hashid.startswith('0000'):
#print i,hashid
work=base64.b64encode(str(i))
break
继续看
def run():
if not proof():
return
m=int(open("/home/bibi/PycharmProjects/work/whctf/flag","r").read().encode("hex"),16)#flag{*}
(p,q,e,n,d)=gen_args()
c=pow(m,e,n)
print "n:",hex(n)
print "e:",hex(e)
print "c:",hex(c)
t=int(hex(m)[2:][0:8],16) #取hex(m)的前八位 t=1718378855
u=pow(t,e,n)
print "u:",hex(u)
print "===="
x=int(hex(m)[2:][0:8]+raw_input("x: "),16)
print "===="
y=int(raw_input("y: "),16)
if (pow(x,e,n)==y and pow(y,d,n)==t):
print "s:",hex(int(bin(p)[2:][0:568],2))
run()
这里大概意思就是题目会返回给我们n,e,c,u的值,并且我们需要输入x,y使得pow(x,e,n)==y and pow(y,d,n)==t才会返回给我们s,那么仔细来看看,首先n,e,c的意思大家应该明白。看看t=int(hex(m)[2:][0:8],16)这句代码,我在后面写了备注,就是取hex(m)的前八位十六进制即4个字符,而题目给了tips,m是flag{*}形式的。所以t是固定的。然后继续看,需要我们输入一个x0,y0然后x=t+x0,y=y0使得pow(x,e,n)==y and pow(y,d,n)==t
到这里我们可以分析一下数学逻辑,根据RSA的逻辑
c=pow(m,e,n)<===>m=pow(c,d,n)
u=pow(t,e,n)<===>t=pow(u,d,n)
而题目要求t==pow(y,d,n) ==>y=u
y==pow(x,e,n) <==> u==pow(x,e,n) ==>x=t
所以我们可以知道y=u,x=t结合x=t+x0,y=y0可以得出x0=空字符 y0=u, 按要求输入x0,y0就能得到s了,这里放最终代码
#coding=utf-8
from pwn import *
from itertools import count
from hashlib import md5
import base64
p=remote('118.31.18.75',20013)
salt=p.recvline()
msg = base64.b64decode(salt)
work=""
for i in count():
hashid = md5(msg+str(i)).hexdigest()
if hashid.startswith('0000'):
#print i,hashid
work=base64.b64encode(str(i))
break
#print work
t=1718378855
p.recvuntil('work: ')
p.sendline(work)
print p.recvline()
print p.recvline()
print p.recvline()
print p.recvline()
u = int(p.recvline()[5:-2],16) #u
print "u:",hex(u)
print p.recvline()
p.recvuntil('x: ')
#print str(hex(t))
p.sendline("") #x
print p.recvline()
p.recvuntil('y: ') #y
p.sendline(str(hex(u))[2:])
# p_568=int(p.recvline()[5:-2],16)
# print "p_568:",hex(p_568)
print p.recvline()
继续分析得到s,是p的前568位二进制数组成的数,这里有个小坑,直接拿去高位攻击是不行的,因为必须要576位才能高位攻击(不要问我为什么,因为这是FlappyPig wp说的...)所以我们要爆破568到576中的八位二进制数即两位十六进制然后再进行已知高位攻击,直接放sage代码
from sage.all import *
import binascii
n = 0x9d3a1a28ecb1bd245dd86b18dc4c5b729f23778710005118836129f08e31d6516de8ab47db1b3b7f660f50d283b1e9f2c06e7836136e4c0159f5d2b05771861d3ce6aa8715932eadc1cc0f380909a1961018340f7393142f9c177b1187151f97ac8cdc4ad17fa59a0f39d192af555f27de9cc800846eb2ca6ce78f87c0c0fbf47828328392b81771af624389fd779d130d80739bb7a608961125ba3f1800c766440fa70bfd3f834294d47d7ed9cfffd6d14ae18310f6c1d6d8f88b6c5d72a0b45608b4e21bbb8e314220ed7a2d6a8c95454e571c71b50f1d6a823778ca47131f5b889a1ed1957248bee8c4ac66872a5fd58a121560a27bad4958f1c763f2ffddL
cipher = 0x1f2deea59244b14e53c72465febc2064172a35245842fa83ebff313344bed35ee8af8c3f8f61e6f498fa1fd35e63998a573d7717905f72ec01de0b0529eaab10eb0b0c2ca06e9d6e4245e748fd74f4f756a86e379559793389a3ae6c421d51bb78331a487fc3c3e68971e3e26991ab34ce2a2c07ffd5a5a1e215e766b51fb2d6aab63c2dafa3c87d0a5eb79b634740e1fca7a727de997958839bda684e19acad93cae4abfd1c8cc3684419f83696fe4840f3253e7c038adb13a1382667cf7e17ef55c1e950ea474594102e660e36a23bfd3fd830d1c18a434d0b34bed98308399a894dcab909d68bcab7c7ac990974a4f6ed7d612abb7044f6734eaaebcdc0b5L
e2 = 0x10001
pbits = 1024
for i in range(0,127):
p4=0xda5df16f286dbc825cd0c8ee48aa26ac27338a75172c5b92351f14d083216f7e91b9355e27cf930646fbbda6058dec3c4ddf751f36df5556359fbe671f9b947b4c79cadfdbb27b00
p4=p4+int(hex(i),16)
print hex(p4)
kbits = pbits - p4.nbits()
print p4.nbits()
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
#rint roots
if roots:
p = p4+int(roots[0])
print "p: ", hex(int(p))
assert n % p == 0
q = n/int(p)
print "q: ", hex(int(q))
print gcd(p,q)
phin = (p-1)*(q-1)
print gcd(e2,phin)
d = inverse_mod(e2,phin)
flag = pow(cipher,d,n)
flag = hex(int(flag))[2:-1]
print binascii.unhexlify(flag)