概述
YAML是来自于HTB(hackthebox.com)的一个中级密码学挑战,完成该挑战所需要掌握的知识点在于RSA算法。
题目分析
相关的任务文件包括server.py源代码和一个在线环境。
server.py内容节选如下
class YALM:
def __init__(self):
self.e = 3
self.n = N
def get_secret(self):
message = f'Hey! This is my secret... it is secure because RSA is extremely strong and very hard to break... Here you go: {FLAG}'
m = int(message.encode().hex(), 16)
c = pow(m, self.e, self.n)
return hex(c)
def test_encryption(self):
plaintext = input('Plaintext: ').strip()
m = int(plaintext, 16)
cs = []
while m:
c = pow(m, self.e, self.n)
cs.append(c)
m //= self.n
if len(cs) > 1:
return 'Too many messages!'
return 'Thanks for the message!'
def main():
yalm = YALM()
while True:
print(MENU)
option = int(input('Option: '))
if option == 1:
print(f'Ciphertext: {yalm.get_secret()}')
elif option == 2:
print(yalm.test_encryption())
else:
break
以上代码实现了一个基本的RSA加密算法,已知数据包括e和密文,未知的则是n。 在线环境提供两个输入选项,选项1给出密文, 选项2允许输入一个明文,其输出的结果可以用于判断明文与n的大小关系。
解题过程
首先使用选项2使用二分查找法获取n。
from pwn import remote
conn = remote('134.122.103.40', 31566, level = 'info')
conn.recvuntil("Option: ")
conn.sendline("1")
output = conn.recvline()
print("output =", output)
low = 0
high = pow(2, 2048)
mid = 0
test_count = 0
while low <= high:
mid = (high + low) // 2
conn.recvuntil("Option: ")
conn.sendline("2")
conn.recvuntil("Plaintext: ")
conn.sendline(hex(mid))
line = conn.recvline()
if b"Too many messages!" in line:
high = mid - 1
print("change high to ", hex(high))
else:
low = mid + 1
print("change low to ", hex(low))
print("Search finised with low = ", hex(low))
n = low
得到n之后,进行解密,因为明文前面的一大部分已知,因此我们可以使用Stereotyped Message Attack, 由于FLAG的长度未知,因此使用一个循环进行遍历。
from Crypto.Util.number import bytes_to_long, long_to_bytes
e = 3
c = 0x8ce7a727c4a70470aa3d6b872f82ef26c8ff5c7820d5790aa53e9dbd1d9f328c8847b268813c9c1bca54c3a892c9a848e95f37bb3c467971af3a29a2ea706dde662caa595728ff094b6c3c66bdddc6733f428c5b80ef81c0dbfa7f4419f08cc6ce7cde30df2004ff8037baf3647cf1813c577ca1303fb92f319418e3ed4f36dc49d33e7d92471a53ae2c029cdfa2b9034a6cb8f3b468f9154a6755aff13d923bd7e6d49d2e8db3b34b6135675d1a11236e7c8641716c54fe91dc26677200232baae8a9d5293109d73336f239d9a8905c7a1b81aec57d3df55f3302c0cddbcd742ea302c1157fa7b1138b36acd82cd73142b4fbf26099153616cd0d244dea2e1c
for flag_length in range(16, 64):
message = b"Hey! This is my secret... it is secure because RSA is extremely strong and very hard to break... Here you go: " + b'\x00' * flag_length
m = bytes_to_long(message)
P.<x> = PolynomialRing(Zmod(N), implementation='NTL')
pol = (m + x)^e - c
roots = pol.small_roots(epsilon=1/30)
if (len(roots) > 0):
print("Potential solutions:")
for root in roots:
print("message =", long_to_bytes(m + int(root)))