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