Initial commit
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import hmac
|
||||
from base64 import urlsafe_b64encode, urlsafe_b64decode
|
||||
from hashlib import sha224, sha256, sha384, sha512
|
||||
from ecdsa import ecdsa, SigningKey, VerifyingKey, NIST256p, NIST224p, NIST384p, NIST521p
|
||||
|
||||
allowed_curve = [
|
||||
NIST224p,
|
||||
NIST256p,
|
||||
NIST384p,
|
||||
NIST521p
|
||||
]
|
||||
|
||||
hashfunc = [
|
||||
sha224,
|
||||
sha256,
|
||||
sha384,
|
||||
sha512
|
||||
]
|
||||
|
||||
key_size = [28, 32, 48, 66]
|
||||
signature_size = [56, 64, 96, 132]
|
||||
|
||||
|
||||
class PastaSigner:
|
||||
def __init__(self, secret: bytes, version: int):
|
||||
self.purpose = 'public'
|
||||
if version > 4 or version < 1:
|
||||
version = 1
|
||||
self.version = version
|
||||
self.hashfunc = hashfunc[self.version - 1]
|
||||
self.key_size = key_size[self.version - 1]
|
||||
self.priv = SigningKey.from_string(secret[:self.key_size], curve=allowed_curve[self.version - 1])
|
||||
|
||||
def serialize(self, data: bytes, sig):
|
||||
token = 'v' + str(self.version) + '.'
|
||||
token += self.purpose + '.'
|
||||
token += urlsafe_b64encode(data + sig).decode().replace('=', '')
|
||||
return token
|
||||
|
||||
def sign(self, data: str):
|
||||
data = data.encode()
|
||||
pub = self.priv.get_verifying_key().to_string()
|
||||
h = self.hashfunc(data + pub).digest()
|
||||
nonce = hmac.new(self.priv.to_string(), data, self.hashfunc).hexdigest()
|
||||
sig = self.priv.sign_digest(h, k=int(nonce, 16))
|
||||
|
||||
return self.serialize(data + pub, sig)
|
||||
|
||||
|
||||
class PastaVerifier:
|
||||
|
||||
def __init__(self, secret):
|
||||
self.purpose = 'public'
|
||||
self.secret = secret
|
||||
|
||||
def deserialize(self, data: bytes):
|
||||
try:
|
||||
version, purpose, payload = data.split(b'.')
|
||||
version = int(version.replace(b'v', b''))
|
||||
if version > 4 or version < 1:
|
||||
return False
|
||||
self.version = version
|
||||
self.hashfunc = hashfunc[self.version - 1]
|
||||
self.key_size = key_size[self.version - 1]
|
||||
self.priv = SigningKey.from_string(self.secret[:self.key_size], curve=allowed_curve[self.version - 1])
|
||||
|
||||
raw_data = urlsafe_b64decode(payload + (b'==' * 2))
|
||||
size = signature_size[self.version - 1]
|
||||
signature = raw_data[-size:]
|
||||
public_key = raw_data[-size * 2:-size]
|
||||
message = raw_data[:-size]
|
||||
|
||||
return message, public_key, signature
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def verify(self, token: str):
|
||||
deserialized = self.deserialize(token.encode())
|
||||
if deserialized:
|
||||
message, _, signature = deserialized
|
||||
h = self.hashfunc(message).digest()
|
||||
verifier = self.priv.get_verifying_key()
|
||||
return verifier.verify_digest(signature, h)
|
||||
|
||||
return False
|
||||
@@ -0,0 +1,129 @@
|
||||
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))
|
||||
Reference in New Issue
Block a user