Código#
Tenemos el archivo del servidor al cual podemos acceder con la IP y el puerto dado por hack the box:
from Crypto.Util.number import isPrime, long_to_bytes, getPrime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from random import randint
from hashlib import sha256
from secret import FLAG
class DH:
def __init__(self):
self.gen_params()
def gen_params(self):
self.r = getPrime(512)
while True:
self.q = getPrime(42)
self.p = (2 * self.q * self.r) + 1
if isPrime(self.p):
break
while True:
self.h = getPrime(42)
self.g = pow(self.h, 2 * self.r, self.p)
if self.g != 1:
break
self.a = randint(2, self.p - 2)
self.b = randint(2, self.p - 2)
self.A, self.B = pow(self.g, self.a, self.p), pow(self.g, self.b, self.p)
self.ss = pow(self.A, self.b, self.p)
def encrypt(self, flag_part):
key = sha256(long_to_bytes(self.ss)).digest()[:16]
cipher = AES.new(key, AES.MODE_ECB)
ct = cipher.encrypt(pad(flag_part, 16)).hex()
return f"encrypted = {ct}"
def get_params(self):
return f"p = {self.p}\ng = {self.g}\nA = {self.A}\nB = {self.B}"
def menu():
print("\nChoose as you please\n")
print("1. Get parameters")
print("2. Reset parameters!! This can take some time")
print("3. Get Flag")
option = input("\n> ")
return option
def main():
dh = DH()
while True:
choice = int(menu())
if choice == 1:
print(dh.get_params())
elif choice == 2:
dh.gen_params()
elif choice == 3:
print(dh.encrypt(FLAG))
else:
print('See you later.')
exit(1)
if __name__ == "__main__":
main()
Reto#
Del servidor podemos obtener los siguientes datos:
- p
- g
- A
- B
- Y el mensaje o la flag cifrada
Además tenemos que la flag se cifra usando AES en el modo ECB por lo que no utiliza IV y siempre que cifre con la misma clave y mensaje cifrara lo mismo por lo que si tenemos la clave podremos recuperar la flag.
Según el código tenemos que la clave es ss que es generado usando la siguiente formula:
$$ ss = A ^ b \ %\ p $$
Para resolverlo tenemos que conseguir b ya que los otros datos ya los tenemos, buscando un poco encontré que se trata de un problema llamado logaritmo discreto, en python tenemos una librería para resolver este tipo de problemas:
(function) def discrete_log(
n: Any,
a: Any,
b: Any,
order: ... = None,
prime_order: ... = None
) -> int
Compute the discrete logarithm of a to the base b modulo n.
Solución#
from sympy import factorint
from sympy.ntheory.residue_ntheory import discrete_log
from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import unpad
from Crypto.Util.number import long_to_bytes
from hashlib import sha256
p = 59702555363140365331221654367749202594684333032653445501600946953015480391016276040925683077716904592873209440311716988833274523783610980994223127214220800208471343487
g = 28607077544811228815959291844142045756225848738120397478772468003446598863446354933589570289508591077174331427234175726954660251792899436433628822273951414414283265286
A = 40128858578334550784152606754547996995101433425312177936319008861285712829228083206324801229162121952523492000002546147948532844880866252831360023464564459187935260314
B = 36869696607134213037764766496699729672230301311065576696978853896383514877746237126437066067741173150436635504714236708512081363150395196544387116017253252746350804843
b = discrete_log(p, B, g)
ss = pow(A, b, p)
print(f"key = {ss}")
key = sha256(long_to_bytes(ss)).digest()[:16]
ciphertext_bytes = bytes.fromhex("c409c9789e3ef6c74893c0a21b771f37e0b4e2cb73248445574bb4c7379789d492682ec789ff8c1fe3b3cae6ab236ead")
cipher = AES.new(key, AES.MODE_ECB)
flag_part = unpad(cipher.decrypt(ciphertext_bytes), 16)
print(flag_part.decode())
