crypto
This commit is contained in:
17
Unibw 2023/crypto/T800 - I'm Back/README.md
Normal file
17
Unibw 2023/crypto/T800 - I'm Back/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
Crypto
|
||||
T800 - I'm back
|
||||
|
||||
100.00pt
|
||||
|
||||
0 solves
|
||||
|
||||
Last solution: Not yet solved
|
||||
T800 - I'm back
|
||||
|
||||
Our last ressort is Crystal Peak. It is secured by our latest and highly secure access control system.
|
||||
|
||||
Visit https://t800.codectf.localos.io
|
||||
|
||||
Hint: Works best on Firefox.
|
||||
|
||||
Basic authentication is the same as for the scoreboard
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from flask import Flask, Response, request, send_from_directory
|
||||
from ecdsa import SigningKey, VerifyingKey, BadSignatureError
|
||||
from base64 import b64decode, b64encode
|
||||
from hashlib import sha256
|
||||
from random import randrange
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
...
|
||||
|
||||
if not FLAG:
|
||||
import sys
|
||||
sys.exit(1)
|
||||
|
||||
app_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
admin_priv = SigningKey.from_pem(open('{}/keys/admin_priv.pem'.format(app_dir)).read(), hashfunc=sha256)
|
||||
admin_pub = admin_priv.verifying_key
|
||||
user_keys = dict()
|
||||
|
||||
for u in ['john', 'kate', 'silberman']:
|
||||
user_keys[u] = VerifyingKey.from_pem(open('{}/keys/{}_pub.pem'.format(app_dir, u)).read(), hashfunc=sha256)
|
||||
|
||||
K_COEFF = [randrange(0, admin_pub.curve.order) for _ in range(5)]
|
||||
chal_ts = None
|
||||
chal_sig = None
|
||||
chal_k = randrange(0, admin_pub.curve.order)
|
||||
|
||||
app = Flask(__name__, static_folder='{}/static'.format(app_dir))
|
||||
|
||||
...
|
||||
|
||||
def timestamp():
|
||||
t = int(time.time())
|
||||
|
||||
return t - t % 30
|
||||
|
||||
def sigdecode(sig, order):
|
||||
bl = (order.bit_length() + 7) // 8
|
||||
sig = b64decode(sig.encode('utf-8'))
|
||||
assert len(sig) == 2 * bl
|
||||
r = int.from_bytes(sig[:bl], 'big')
|
||||
s = int.from_bytes(sig[bl:], 'big')
|
||||
|
||||
return r % order, s % order
|
||||
|
||||
def sigencode(r, s, order):
|
||||
bl = (order.bit_length() + 7) // 8
|
||||
r = (r % order).to_bytes(bl, 'big')
|
||||
s = (s % order).to_bytes(bl, 'big')
|
||||
|
||||
return b64encode(r + s).decode('utf-8')
|
||||
|
||||
def sigcheck(pubkey, sig):
|
||||
try:
|
||||
if pubkey.verify(sig, str(chal_ts).encode('utf-8') + b'login', hashfunc=sha256, sigdecode=sigdecode):
|
||||
return True
|
||||
except BadSignatureError:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
@app.route('/static/<path:path>', methods=['GET'])
|
||||
def serve_static(path):
|
||||
return send_from_directory('static', path)
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
def index():
|
||||
return app.send_static_file('index.html')
|
||||
|
||||
@app.route('/login', methods=['POST'])
|
||||
def login():
|
||||
data = request.get_json()
|
||||
|
||||
if 'user' not in data or 'sig' not in data:
|
||||
return Response("Invalid request format", status=400)
|
||||
|
||||
user = data['user']
|
||||
|
||||
if user not in user_keys:
|
||||
return { 'invalid': 'Invalid username' }
|
||||
|
||||
sig = data['sig']
|
||||
|
||||
if sigcheck(user_keys[user], sig) or sigcheck(admin_pub, sig):
|
||||
return { 'valid': '{}'.format(FLAG) }
|
||||
|
||||
return { 'invalid': 'Invalid private key' }
|
||||
|
||||
@app.route('/challenge', methods=['GET'])
|
||||
def challenge():
|
||||
global chal_ts, chal_sig, chal_k
|
||||
ts = timestamp()
|
||||
|
||||
if ts != chal_ts:
|
||||
chal_ts = ts
|
||||
chal_k = sum(a * chal_k ** i for i, a in enumerate(K_COEFF)) % admin_pub.curve.order
|
||||
chal_sig = admin_priv.sign(str(chal_ts).encode('utf-8') + b'challenge', hashfunc=sha256, sigencode=sigencode, k=chal_k)
|
||||
|
||||
return { 'challenge': str(chal_ts), 'sig': chal_sig }
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
...
|
||||
Reference in New Issue
Block a user