rsa-buffet

rsa-buffet

boston-key-party-2017
在这里插入图片描述
encrypt.py

import random
from Crypto.Cipher import AES,PKCS1_OAEP
from Crypto.PublicKey import RSA

def get_rand_bytes(length):
  return "".join([chr(random.randrange(256)) for i in range(length)])

def encrypt(public_key, message):
  """Encrypt a message with a given public key.
  
  Takes in a public_key generated by Crypto.PublicKey.RSA, which must be of
  size exactly 4096
  """
  symmetric_key = get_rand_bytes(32)
  msg_header = PKCS1_OAEP.new(public_key).encrypt(symmetric_key)
  assert len(msg_header) == 512
  msg_iv = get_rand_bytes(16)
  msg_body = AES.new(symmetric_key,
      mode=AES.MODE_CFB,
      IV=msg_iv).encrypt(message)
  return msg_header + msg_iv + msg_body

def decrypt(private_key, ciphertext):
  """Decrypt a message with a given private key.

  Takes in a private_key generated by Crypto.PublicKey.RSA, which must be of
  size exactly 4096

  If the ciphertext is invalid, return None
  """
  if len(ciphertext) < 512 + 16:
    return None
  msg_header = ciphertext[:512]
  msg_iv = ciphertext[512:512+16]
  msg_body = ciphertext[512+16:]
  try:
    symmetric_key = PKCS1_OAEP.new(private_key).decrypt(msg_header)
  except ValueError:
    return None
  if len(symmetric_key) != 32:
    return None
  return AES.new(symmetric_key,
      mode=AES.MODE_CFB,
      IV=msg_iv).decrypt(msg_body)


if __name__=="__main__":
  # Test!
  message = "This is my test message.  It's kind of ssilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregsilly.wireheirhgwieruhgwieurghwiregilly.wireheirhgwieruhgwieurghwireg"
  private_key = RSA.generate(4096)
  public_key = private_key.publickey()
  ciphertext = encrypt(public_key, message)
  assert message == decrypt(private_key, ciphertext)


generate-plaintexts.py

# pip install secretsharing
# https://github.com/blockstack/secret-sharing
from secretsharing import PlaintextToHexSecretSharer as SS

with open('message1.txt', 'r') as f:
  PLAINTEXTS = [f.read()] * 5

for i in range(2, 6):
  with open('message' + str(i) + '.txt', 'r') as f:
    msg = f.read()
  shares = SS.split_secret(msg, i, 5)
  for j in range(5):
    PLAINTEXTS[j] += shares[j] + '\n'

for j in range(5):
  with open('plaintext-' + str(j+1) + '.txt', 'w') as f:
    f.write(PLAINTEXTS[j])

admin的WP

这个挑战涉及两个密码系统:RSA和Shamir的Secret Sharing。必须首先恢复足够的RSA公钥的私钥,才能成功解密5个给定密文中的3个。github上有一个方便的小库,可以通过顺序执行对RSA的知名攻击(维纳,哈斯塔德,费马,因子DB等)来帮助您做到这一点。使用该库的分支,我在程序中运行了每个公钥,并成功恢复了3个私钥。

$ python RsaCtfToolcli.py --publickey ../rsa-buffet/key-1.pem --private
$ python RsaCtfToolcli.py --publickey ../rsa-buffet/key-2.pem --private
$ python RsaCtfToolcli.py --publickey ../rsa-buffet/key-3.pem --private

这会将恢复的私钥写入文件。现在我们有了3个私钥,我们可以开始尝试解密一些密文。我编辑了提供encrypt.py文件的主要部分以执行解密。

if __name__ == "__main__":
    k_text = open(sys.argv[1], 'r').read()
    c = open(sys.argv[2], 'rb').read()
    k = RSA.importKey(k_text)
    print(decrypt(k, c))

经过反复试验,我发现以下密钥密文解密对:key1 +密文5,key2 +密文1,key3 +密文4。

$ python encrypt.py key1 ciphertext-5.bin
Congratulations, you decrypted a ciphertext!  One down, two to go :)
5-7d29041c468b680fcff93c16011a2869f17de75b929b787503b412becde0321ec72fe1e499f2150a1dacb9a5f701c0b37470049dd560cef5163543469817971f50782f763f0b05ab7088f7ae
5-a7a1e271cf263279cece532b540545fa539b0f3650e2929163b02ee5459debdc53c1e07149eb2153015bb5c88e6270e8
5-149480c5c75cbe320564adfa432ac8ea241e048ed39c8bc6be14ca80c392487f43a7882075d785d62cb314ea6c89a6b5f28adfa56ec481e124567b88241de2a6cabcc7ec9de3acac8be5375b
5-7285289084282d559573f68eef10191091d76d6670014202670651f867cd2bc8640a86eef1c1e482affc7ae801fa446956c2186972fb6b7bac88c91d050c9d3cca
$ python encrypt.py key2 ciphertext-1.bin
Congratulations, you decrypted a ciphertext!  One down, two to go :)
1-32a1cd9f414f14cff6685879444acbe41e5dba6574a072cace6e8d0eb338ad64910897369b7589e6a408c861c8e708f60fbbbe91953d4a73bcf1df11e1ecaa2885bed1e5a772bfed42d776a9
1-e0c113fa1ebea9318dd413bf28308707fd660a5d1417fbc7da72416c8baaa5bf628f11c660dcee518134353e6ff8d37c
1-1b8b6c4e3145a96b1b0031f63521c8df58713c4d6d737039b0f1c0750e16e1579340cfc5dadef4e96d6b95ecf89f52b8136ae657c9c32e96bf4384e18bd8190546ff5102cd006be5e1580053
1-c332b8b93a914532a2dab045ea52b86d4d3950a990b5fc5e041dce9be1fd3912f9978cad009320e18f4383ca71d9d79114c9816b5f950305a6dd19c9f458695d52
$ python encrypt.py key3 ciphertext-4.bin
Congratulations, you decrypted a ciphertext!  One down, two to go :)
4-4a87367d053c533fd995032ed1e651487cb5dc1e0b1cb70a7662b152c73650f039a60f391a52f2413f43bd54eb7b12c41b42f31ac557edd4bfe46a396a8cdbe19dc9d8121924f43be51c976d
4-abbbcee71f140198ff8c50f51069465075979c31d32b052e7ae82ec7f6783aef7b41a597f9504d3340967b8d70cbe5a3
4-35fbbe40058e20463547b363d1f164c0bbbb97cfd9ffe7619bce31a59392f0e9625a2cd035276e09c4df3c0932f22bd322f16e375c7c7fd88da0f972832707eb549ff1e776db37649019ebce
4-12b466934911986bda845d8d26710a12250d210546f46716c78d7a17b1f2c893b95b934c8c7beafcf81a3123eb2ea05ca89101b23349e455794a8d56608c8ee49dd

现在有了来自秘密共享的足够的秘密,我就可以恢复该flag。

from secretsharing import PlaintextToHexSecretSharer as SS

files = ["ciphertext5.txt", "ciphertext1.txt", "ciphertext4.txt"]
secrets = []
for fn in files:
    a = []
    with open(fn, "r") as f:
        a = f.readlines()

    a = a[1:] # strip the "Congratulation" line
    for i in range(0,len(a)):
        a[i] = a[i].strip("\n")

    secrets.append(a)

for i in range(0, 2):
    a = SS.recover_secret([secrets[0][i], secrets[1][i], secrets[2][i]])
    print(a)

运行这个小脚本会产生一些结果,并生成flag。

And another one's down, and another one's down, and another one bites the dust!

Three's the magic number!  FLAG{ndQzjRpnSP60NgWET6jX}.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值