目录
1.题目
题目据来源:NSSCTF
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
from hashlib import sha256
import random, os, signal, string
def proof_of_work():
random.seed(os.urandom(8))
proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
_hexdigest = sha256(proof.encode()).hexdigest()
print(f"sha256(XXXX+{proof[4:]}) == {_hexdigest}")
print('Give me XXXX: ')
x = input()
if len(x) != 4 or sha256(x.encode()+proof[4:].encode()).hexdigest() != _hexdigest:
print('Wrong PoW')
return False
return True
if not proof_of_work():
exit(1)
signal.alarm(10)
print("Give me a bad RSA keypair.")
try:
p = int(input('p = '))
q = int(input('q = '))
assert p > 0
assert q > 0
assert p != q
assert p.bit_length() == 512
assert q.bit_length() == 512
assert isPrime(p)
assert isPrime(q)
n = p * q
e = 65537
assert p % e != 1
assert q % e != 1
d = inverse(e, (p-1)*(q-1))
except:
print("Invalid params")
exit(2)
try:
key = RSA.construct([n,e,d,p,q])
print("This is not a bad RSA keypair.")
exit(3)
except KeyboardInterrupt:
print("Hacker detected.")
exit(4)
except ValueError:
print("How could this happen?")
from secret import flag
print(flag)
2.分析
分为两个流程,第一步sha256爆破四个字节,第二步是审计源码后进行相应攻击
3.解题
连接远程机:
nc node4.anna.nssctf.cn 28552
连接后有如下信息(每一次都不一样):
sha256(XXXX+EFgCDcZULevC7j4e) == fe78a1e8958f40ebe5e79117b578a7b7bee990ddab502be2b4d4a55065dd18e5
Give me XXXX:
第一步:
sha256爆破
from itertools import product
import hashlib
table = [chr(i) for i in range(48, 127)]
m = b'EFgCDcZULevC7j4e'
proof = 'fe78a1e8958f40ebe5e79117b578a7b7bee990ddab502be2b4d4a55065dd18e5'
print('-------start---------')
for i in product(table, table, table, table):
t = ''.join(i)
t = t.encode()
t = t + m
sh = hashlib.sha256(t)
if(sh.hexdigest() == proof):
print(''.join(i))
break
得到:
AhzE
提交后得到:
sha256(XXXX+EFgCDcZULevC7j4e) == fe78a1e8958f40ebe5e79117b578a7b7bee990ddab502be2b4d4a55065dd18e5
Give me XXXX:
AhzE
Give me a bad RSA keypair.
p =
第二步:
源码审计:
根据一些大佬的分析,有以下几种使得rsa raise ValueError("Invalid RSA condition")的方法:
最终我们看到这一行:
if Integer(n).gcd(d) != 1:
raise ValueError("RSA private exponent is not coprime to modulus")
所以我们尝试在得到p、q的时候产生这样的结果
推理过程:
首先我们设:
因为:
所以:
所以:
在下式中我们整理一下:
化简得到:
注意经验来说,k的范围是在(1, e+1)之间的,我们可以通过爆破得到一组p、q
具体爆破代码:
e = 65537
while True:
p = getPrime(512)
k1 = inverse(e, p - 1)
t = (e * k1 * p - 1) // (p - 1)
for k2 in range(1, e + 1):
if t % k2 == 0:
q = t // k2 + 1
if isPrime(q) and q.bit_length() == 512:
print(p, q)
exit()