密码学实战 - HTB mysterybox

1,012 阅读5分钟

概述

mysterybox是来自于HTB(hackthebox.com)的一个中级密码学挑战,完成该挑战所需要掌握的知识点在于RSA签名算法。

题目分析

相关的任务文件包括server.py源代码和一个在线环境。

server.py内容节选如下

from Crypto.Util.number import getPrime, bytes_to_long, long_to_bytes, isPrime

e = getPrime(128)
while True:
  p, q = getPrime(512), getPrime(512)
  if (p-1) % e and (q-1) % e:
    break

n = p * q
d = pow(e,-1,(p-1)*(q-1))

pubkey = (n, e)
privkey = (n, d)

def sign(message, privkey):
    n, d = privkey
    return pow(message, d, n)
    
def verify(message, signature, pubkey):
    n, e = pubkey
    if pow(signature, e, n) == message:
        return True
    else:
        return False

to_sign = bytes_to_long(b"Username: Admin, Access code: CryptoBestCategoryF3")
assert isPrime(to_sign)

menu = """
[1] Sign a message
[2] Verify access to this server
[3] Exit
"""[1:]

print("Welcome to your Signing Server. With our verifying feature, we don't even need to give you our public key!")
while True:
  print(menu)
  try:
    opt = input("Enter your option: ")
    if opt == "1":
      msg = int(input("Enter your message to be signed as a decimal integer: "))
      if msg % n == to_sign:
        print("You cannot sign the admin message.")
      else:
        print(f"Signature for {msg}: {sign(msg, privkey)}")
    elif opt == "2":
      msg = int(input("Enter your message as a decimal integer: ")) % n
      sig = int(input("Enter your signature as a decimal integer: ")) % n
      if verify(msg, sig, pubkey):
        if msg == to_sign:
          print(f"Welcome, admin. Here's your flag: {open('/challenge/flag.txt').read().strip()}")
        else:
          print("Signature valid!")
      else:
        print("Signature invalid.")
    elif opt == "3":
      print("Goodbye.")
      exit(0)
    else:
      print("Option not recognized, please try again.")
  except Exception as error:
    print("An error occured, please try again.", error)

以上代码实现了一个基本的RSA签名算法,并提供了二个接口,接口一对输入的消息进行签名,而接口二则对输入的消息和签名进行校验. 获得flag的条件在于计算出与to_sign对应的数字签名, 并通过接口二的校验.

解题过程

虽然接口一不允许直接对to_sign进行签名, 但我们可以获得-1 * to_sign的签名(s), 根据RSA签名算法, -1 * s 则是to_sign的有效签名。

解题过程如下:

from Crypto.Util.number import getPrime, bytes_to_long, long_to_bytes, isPrime
to_sign = bytes_to_long(b"Username: Admin, Access code: CryptoBestCategoryF3")
to_sign
861934499667986621552658522992711737960484613144058684918624923247791760594840402997853247655770722704545163272571668019
nc 138.68.163.170 32481
Welcome to your Signing Server. With our verifying feature, we don't even need to give you our public key!
[1] Sign a message
[2] Verify access to this server
[3] Exit

Enter your option: 1
Enter your message to be signed as a decimal integer: -861934499667986621552658522992711737960484613144058684918624923247791760594840402997853247655770722704545163272571668019
Signature for -861934499667986621552658522992711737960484613144058684918624923247791760594840402997853247655770722704545163272571668019: 22142675583503372654112725522236706227354531285899737202546726055680079841779677779089796750413748887418878576042495555389048121491784956561868189175221319431721674218542407246345060001145118258287502105268097569346183341848134054358636513708578027094201620256452011012058506223300459788466424014324709119927
[1] Sign a message
[2] Verify access to this server
[3] Exit

Enter your option: 2
Enter your message as a decimal integer: 861934499667986621552658522992711737960484613144058684918624923247791760594840402997853247655770722704545163272571668019
Enter your signature as a decimal integer: -22142675583503372654112725522236706227354531285899737202546726055680079841779677779089796750413748887418878576042495555389048121491784956561868189175221319431721674218542407246345060001145118258287502105268097569346183341848134054358636513708578027094201620256452011012058506223300459788466424014324709119927
Welcome, admin. Here's your flag: ...