hackthebox challenge刷题系列1

BabyEncryption

题目脚本如下,并且提供了msg.enc:

import string
from secret import MSG

def encryption(msg):
ct = []
for char in msg:
ct.append((123 * char + 18) % 256)
return bytes(ct)

ct = encryption(MSG)
f = open('./msg.enc','w')
f.write(ct.hex())
f.close()

求123关于256的逆元,解密脚本如下:

import gmpy2
secret = gmpy2.invert(123, 256)

def decode(msg):
flag = []
for char in msg:
char = (secret * (char - 18)) % 256
flag.append(char)
return bytes(flag)

with open('msg.enc') as f:
c = bytes.fromhex(f.read())

flag = decode(c)
print(flag)
$ python exp.py
b'Th3 nucl34r w1ll 4rr1v3 0n fr1d4y.\nHTB{l00k_47_y0u_r3v3rs1ng_3qu4710n5_c0ngr475}'

Baby Time Capsule

题目提供了server.py,脚本如下:

from Crypto.Util.number import bytes_to_long, getPrime
import socketserver
import json

FLAG = b'HTB{--REDACTED--}'


class TimeCapsule():

def __init__(self, msg):
self.msg = msg
self.bit_size = 1024
self.e = 5

def _get_new_pubkey(self):
while True:
p = getPrime(self.bit_size // 2)
q = getPrime(self.bit_size // 2)
n = p * q
phi = (p - 1) * (q - 1)
try:
pow(self.e, -1, phi)
break
except ValueError:
pass

return n, self.e

def get_new_time_capsule(self):
n, e = self._get_new_pubkey()
m = bytes_to_long(self.msg)
m = pow(m, e, n)

return {"time_capsule": f"{m:X}", "pubkey": [f"{n:X}", f"{e:X}"]}


def challenge(req):
time_capsule = TimeCapsule(FLAG)
while True:
try:
req.sendall(
b'Welcome to Qubit Enterprises. Would you like your own time capsule? (Y/n) '
)
msg = req.recv(4096).decode().strip().upper()
if msg == 'Y' or msg == 'YES':
capsule = time_capsule.get_new_time_capsule()
req.sendall(json.dumps(capsule).encode() + b'\n')
elif msg == 'N' or msg == "NO":
req.sendall(b'Thank you, take care\n')
break
else:
req.sendall(b'I\'m sorry I don\'t understand\n')
except:
# Socket closed, bail
return


class MyTCPRequestHandler(socketserver.BaseRequestHandler):

def handle(self):
req = self.request
challenge(req)


class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass


def main():
socketserver.TCPServer.allow_reuse_address = True
server = ThreadingTCPServer(("0.0.0.0", 1337), MyTCPRequestHandler)
server.serve_forever()


if __name__ == '__main__':
main()

TimeCapsule这个类的构造函数中设置了msg和素数比特大小以及指数e的值,然后_get_new_pubkey用来生成公钥,要求指数e在模phi下存在逆,最后返回n和e作为公钥。get_new_time_capsule函数获取公钥后,将msg转为长整数,加密后得到密文。其实TimeCapsule就是实现了RSA加密,密文内容就是flag。

每次连接服务器的时候,获取到的n都不同,但是e一样,这就形成了一组同余方程组,可以使用中国剩余定理求解:

设:$n = n_1 \cdot n_2 \cdot \ldots \cdot n_n$

$N_i = \frac{n}{n_i}$,然后找到 $N_i$ 对应的模数的乘法逆元素,记为 $x_i$,满足 $N_i \cdot x_i \equiv 1 \pmod{n_i}$

然后计算:$m_i = N_i \cdot x_i \pmod{n_i}$

得到解:$ m^e \equiv \left(\sum_{i=1}^{n} (c_i \cdot m_i)\right) \pmod{n} $

exp如下:

from pwn import *
import json
from sympy.ntheory.modular import crt
from sympy.simplify.simplify import nthroot
from Crypto.Util.number import long_to_bytes

io = remote('94.237.53.58', 52665)

c = []
pub = []
e = 5
for i in range(3):
io.sendlineafter('Welcome to Qubit Enterprises. Would you like your own time capsule? (Y/n)', 'Y')
data = io.recvline()
data = json.loads(data)
cipher = int(data['time_capsule'], 16)
n = int(data['pubkey'][0], 16)
c.append(cipher)
pub.append(n)


flag = crt(pub, c, check=True)
flag = long_to_bytes(nthroot(flag[0], e))
print(flag)

io.close()
$ python exp.py
[+] Opening connection to 94.237.53.58 on port 52665: Done
HTB{t3h_FuTUr3_15_bR1ghT_1_H0p3_y0uR3_W34r1nG_5h4d35!}

The Last Dance

题目描述:

To be accepted into the upper class of the Berford Empire, you had to attend the annual Cha-Cha Ball at the High Court. Little did you know that among the many aristocrats invited, you would find a burned enemy spy. Your goal quickly became to capture him, which you succeeded in doing after putting something in his drink. Many hours passed in your agency’s interrogation room, and you eventually learned important information about the enemy agency’s secret communications. Can you use what you learned to decrypt the rest of the messages?

题目中的source.py内容如下:

from Crypto.Cipher import ChaCha20
from secret import FLAG
import os


def encryptMessage(message, key, nonce):
cipher = ChaCha20.new(key=key, nonce=iv)
ciphertext = cipher.encrypt(message)
return ciphertext


def writeData(data):
with open("out.txt", "w") as f:
f.write(data)


if __name__ == "__main__":
message = b"Our counter agencies have intercepted your messages and a lot "
message += b"of your agent's identities have been exposed. In a matter of "
message += b"days all of them will be captured"

key, iv = os.urandom(32), os.urandom(12)

encrypted_message = encryptMessage(message, key, iv)
encrypted_flag = encryptMessage(FLAG, key, iv)

data = iv.hex() + "\n" + encrypted_message.hex() + "\n" + encrypted_flag.hex()
writeData(data)

out.txt内容如下:

c4a66edfe80227b4fa24d431
7aa34395a258f5893e3db1822139b8c1f04cfab9d757b9b9cca57e1df33d093f07c7f06e06bb6293676f9060a838ea138b6bc9f20b08afeb73120506e2ce7b9b9dcd9e4a421584cfaba2481132dfbdf4216e98e3facec9ba199ca3a97641e9ca9782868d0222a1d7c0d3119b867edaf2e72e2a6f7d344df39a14edc39cb6f960944ddac2aaef324827c36cba67dcb76b22119b43881a3f1262752990
7d8273ceb459e4d4386df4e32e1aecc1aa7aaafda50cb982f6c62623cf6b29693d86b15457aa76ac7e2eef6cf814ae3a8d39c7

用了ChaCha20流密码对消息进行了加密,但是可以发现的是对message加密的密钥和iv,与对flag加密的密钥和iv是相同的,并且题目中还提供了iv的值。

ChaCha20的核心加密逻辑是将明文与一个生成的数据进行异或,得到密文数据;解密时将密文数据再次与这个数据进行异或便能恢复明文。

根据题目脚本可以得到:

将上述两个式子异或,得到:

从而:

exp如下:

def xor(message, p1, p2):
p1_bytes = bytes.fromhex(p1)
p2_bytes = bytes.fromhex(p2)
xor1 = bytes(a ^ b for a,b in zip(message, p1_bytes))
xor2 = bytes(a ^ b for a,b in zip(xor1, p2_bytes))
return xor2

message = b"Our counter agencies have intercepted your messages and a lot "
message += b"of your agent's identities have been exposed. In a matter of "
message += b"days all of them will be captured"

c1 = "7aa34395a258f5893e3db1822139b8c1f04cfab9d757b9b9cca57e1df33d093f07c7f06e06bb6293676f9060a838ea138b6bc9f20b08afeb73120506e2ce7b9b9dcd9e4a421584cfaba2481132dfbdf4216e98e3facec9ba199ca3a97641e9ca9782868d0222a1d7c0d3119b867edaf2e72e2a6f7d344df39a14edc39cb6f960944ddac2aaef324827c36cba67dcb76b22119b43881a3f1262752990"
c2 = "7d8273ceb459e4d4386df4e32e1aecc1aa7aaafda50cb982f6c62623cf6b29693d86b15457aa76ac7e2eef6cf814ae3a8d39c7"

flag = xor(message, c1, c2)
print(flag)
$ python exp.py
b'HTB{und3r57AnD1n9_57R3aM_C1PH3R5_15_51mPl3_a5_7Ha7}'

Lost Modulus

题目描述:

I encrypted a secret message with RSA but I lost the modulus. Can you help me recover it?

challenge.py内容如下:

#!/usr/bin/python3
from Crypto.Util.number import getPrime, long_to_bytes, inverse
flag = open('flag.txt', 'r').read().strip().encode()

class RSA:
def __init__(self):
self.p = getPrime(512)
self.q = getPrime(512)
self.e = 3
self.n = self.p * self.q
self.d = inverse(self.e, (self.p-1)*(self.q-1))
def encrypt(self, data: bytes) -> bytes:
pt = int(data.hex(), 16)
ct = pow(pt, self.e, self.n)
return long_to_bytes(ct)
def decrypt(self, data: bytes) -> bytes:
ct = int(data.hex(), 16)
pt = pow(ct, self.d, self.n)
return long_to_bytes(pt)

def main():
crypto = RSA()
print ('Flag:', crypto.encrypt(flag).hex())

if __name__ == '__main__':
main()

output.txt内容如下:

Flag: 05c61636499a82088bf4388203a93e67bf046f8c49f62857681ec9aaaa40b4772933e0abc83e938c84ff8e67e5ad85bd6eca167585b0cc03eb1333b1b1462d9d7c25f44e53bcb568f0f05219c0147f7dc3cbad45dec2f34f03bcadcbba866dd0c566035c8122d68255ada7d18954ad604965

可以发现脚本中的e为3,由于:

则有:

即:

爆破k即可,如果m的三次方小于N,则k=0。

解题脚本如下:

from sympy.simplify.simplify import nthroot
from Crypto.Util.number import long_to_bytes

flag = "05c61636499a82088bf4388203a93e67bf046f8c49f62857681ec9aaaa40b4772933e0abc83e938c84ff8e67e5ad85bd6eca167585b0cc03eb1333b1b1462d9d7c25f44e53bcb568f0f05219c0147f7dc3cbad45dec2f34f03bcadcbba866dd0c566035c8122d68255ada7d18954ad604965"
flag = int(flag, 16)

flag = long_to_bytes(nthroot(flag, 3))
print(flag)
$ python exp.py
b'HTB{n3v3r_us3_sm4ll_3xp0n3n7s_f0r_rs4}'
文章作者: Alex
文章链接: http://example.com/2024/02/13/hackthebox-challenge-Crypto1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Alex's blog~