CTFs and solutions
This commit is contained in:
71
back-to-the-future/2
Normal file
71
back-to-the-future/2
Normal file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
from Cryptodome.Cipher import ChaCha20
|
||||
from Cryptodome.Random import get_random_bytes
|
||||
from Cryptodome.Util.number import long_to_bytes, bytes_to_long
|
||||
import time
|
||||
from random import randint
|
||||
from pwn import *
|
||||
import base64
|
||||
import requests
|
||||
import time
|
||||
from requests.utils import cookiejar_from_dict
|
||||
LOGIN ="http://130.192.5.212:6522/login"
|
||||
FLAG = "http://130.192.5.212:6522/flag"
|
||||
username='aa'
|
||||
admin=0
|
||||
expire_date=int(time.time()) + 30 * 24 * 60 * 60
|
||||
cookie = f"username={username}&expires={expire_date}&admin={admin}"
|
||||
print(f"Cookie len:{len(cookie.encode())}")
|
||||
LOGIN="http://127.0.0.1:5000/login"
|
||||
FLAG="http://127.0.0.1:5000/flag"
|
||||
# expire = 1.748.345.396
|
||||
PARAMS = {"username":'aa','admin':1}
|
||||
|
||||
s = requests.Session()
|
||||
r = s.get(url=LOGIN,params=PARAMS)
|
||||
cookie= r.json()['cookie']
|
||||
print(f"Cookie encrypted len:{len(long_to_bytes(cookie))}")
|
||||
#sleep(1000)
|
||||
nonce = r.json()['nonce']
|
||||
|
||||
cookie = bytearray(long_to_bytes(cookie))
|
||||
|
||||
for i in range(1,256):
|
||||
cookie[-1]= cookie[-1] ^ i
|
||||
|
||||
COOKIES = {'cookie':bytes_to_long(cookie), 'nonce': nonce}
|
||||
f = s.get(url=FLAG,params=COOKIES)
|
||||
print(f.text)
|
||||
"""if(f.text == "You have expired!"):
|
||||
print(f"Guessed byte:{i}")
|
||||
cookie[20] = 2 ^ i
|
||||
COOKIES['cookie'] = bytes_to_long(cookie)
|
||||
f = s.get(url=FLAG,params=COOKIES)
|
||||
print(f.text)"""
|
||||
#break
|
||||
"""decCookie = cipher.decrypt(encCookie)
|
||||
print(decCookie)
|
||||
sleep(10000)
|
||||
r = s.get(url=LOGIN,params=PARAMS)
|
||||
for cookie in s.cookies:
|
||||
print(cookie)
|
||||
keyEncoded = cookie.value
|
||||
key = base64.urlsafe_b64decode(keyEncoded+'=')
|
||||
|
||||
print(f"LEN:{len(key)}")
|
||||
|
||||
LOG_PARAMS = {"username":'aaaaaaaaa','admin':1}
|
||||
r = s.get(url=LOGIN,params=LOG_PARAMS)
|
||||
print(f"login:{r.json()}")
|
||||
cookie=long_to_bytes(r.json()['cookie'])
|
||||
nonce=long_to_bytes(r.json()['nonce'])
|
||||
print(f"Nonce:{bytes_to_long(nonce)}")
|
||||
cipher = ChaCha20.new(key=key, nonce=nonce)
|
||||
decrypt=cipher.decrypt(cookie)
|
||||
print(len(decrypt))
|
||||
sleep(1000)
|
||||
nonce = bytes_to_long(nonce)
|
||||
cookie = bytes_to_long(cipher.encrypt(testCookie.encode()))
|
||||
PARAMS = {'cookie':cookie, 'nonce':nonce }
|
||||
f = s.get(url=FLAG, params=PARAMS)
|
||||
print(f.text)"""
|
||||
BIN
back-to-the-future/__pycache__/chall.cpython-313.pyc
Normal file
BIN
back-to-the-future/__pycache__/chall.cpython-313.pyc
Normal file
Binary file not shown.
50
back-to-the-future/attack.py
Normal file
50
back-to-the-future/attack.py
Normal file
@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
from Cryptodome.Cipher import ChaCha20
|
||||
from Cryptodome.Random import get_random_bytes
|
||||
from Cryptodome.Util.number import long_to_bytes, bytes_to_long
|
||||
import time
|
||||
from random import randint
|
||||
from pwn import *
|
||||
import base64
|
||||
import requests
|
||||
import time
|
||||
from requests.utils import cookiejar_from_dict
|
||||
LOGIN ="http://130.192.5.212:6522/login"
|
||||
FLAG = "http://130.192.5.212:6522/flag"
|
||||
|
||||
#LOGIN="http://127.0.0.1:5000/login"
|
||||
#FLAG="http://127.0.0.1:5000/flag"
|
||||
# expire = 1.748.345.396
|
||||
PARAMS = {"username":'aa','admin':1}
|
||||
givenTime = int(time.time())
|
||||
|
||||
minAdminDate = givenTime - 10 * 24 * 60 * 60
|
||||
maxAdminDate = givenTime - 259 * 24 * 60 * 60
|
||||
avgAdminDate = int((minAdminDate + maxAdminDate)/2)
|
||||
expire_date = givenTime + 30 * 24 * 60 * 60
|
||||
eMin = expire_date - minAdminDate
|
||||
eMax = expire_date - maxAdminDate
|
||||
eAvg = (eMin+eMax) / 2
|
||||
plaintext = f"username={PARAMS['username']}&expires={expire_date}&admin={PARAMS['admin']}"
|
||||
plaintext = plaintext.encode()
|
||||
s = requests.Session()
|
||||
r = s.get(url=LOGIN,params=PARAMS)
|
||||
cookie= r.json()['cookie']
|
||||
cookie = long_to_bytes(cookie)
|
||||
print(f"Cookie encrypted len:{len(cookie)}, Plaintext len:{len(plaintext)}")
|
||||
nonce = r.json()['nonce']
|
||||
|
||||
ks = bytes([c ^ p for c,p in zip(cookie, plaintext)])
|
||||
|
||||
print(f"Keystream len:{len(ks)}")
|
||||
for i in range(1):
|
||||
|
||||
payload = f"username={PARAMS['username']}&expires={maxAdminDate + 295 * 24 * 60 * 60}&admin={1}".encode()
|
||||
|
||||
cookie = bytes([p ^ k for p,k in zip(payload,ks)])
|
||||
print(f"Malicious cookie len:{len(cookie)}")
|
||||
COOKIES = {'cookie':bytes_to_long(cookie),'nonce':nonce}
|
||||
f = s.get(url=FLAG,params=COOKIES)
|
||||
print(f.text)
|
||||
|
||||
##########
|
||||
99
back-to-the-future/chall.py
Normal file
99
back-to-the-future/chall.py
Normal file
@ -0,0 +1,99 @@
|
||||
from Crypto.Cipher import ChaCha20
|
||||
from Crypto.Random import get_random_bytes
|
||||
from Crypto.Util.number import long_to_bytes, bytes_to_long
|
||||
import time
|
||||
from random import randint
|
||||
#from secret import flag
|
||||
from flask import Flask, session, jsonify, request
|
||||
from flask_session import Session
|
||||
import sys
|
||||
flag="PuppaFlag"
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = get_random_bytes(16).hex()
|
||||
app.config['SESSION_TYPE'] = 'filesystem'
|
||||
sess = Session()
|
||||
sess.init_app(app)
|
||||
|
||||
|
||||
def make_cipher():
|
||||
key = get_random_bytes(32)
|
||||
nonce = get_random_bytes(12)
|
||||
cipher = ChaCha20.new(key=key, nonce=nonce)
|
||||
return nonce, key, cipher
|
||||
|
||||
|
||||
def sanitize_field(field: str):
|
||||
return field \
|
||||
.replace(" ", "_") \
|
||||
.replace("/", "_") \
|
||||
.replace("&", "") \
|
||||
.replace(":", "") \
|
||||
.replace(";", "") \
|
||||
.replace("<", "") \
|
||||
.replace(">", "") \
|
||||
.replace('"', "") \
|
||||
.replace("'", "") \
|
||||
.replace("(", "") \
|
||||
.replace(")", "") \
|
||||
.replace("[", "") \
|
||||
.replace("]", "") \
|
||||
.replace("{", "") \
|
||||
.replace("}", "") \
|
||||
.replace("=", "")
|
||||
|
||||
|
||||
def parse_cookie(cookie: str) -> dict:
|
||||
parsed = {}
|
||||
for field in cookie.split("&"):
|
||||
key, value = field.split("=")
|
||||
key = sanitize_field(key)
|
||||
value = sanitize_field(value)
|
||||
parsed[key] = value
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET"])
|
||||
def login():
|
||||
username = request.args.get("username")
|
||||
admin = int(request.args.get("admin"))
|
||||
|
||||
nonce, key, cipher = make_cipher()
|
||||
session['key'] = key
|
||||
username = sanitize_field(username)
|
||||
if admin != 1:
|
||||
admin = 0
|
||||
else:
|
||||
#MAX = 22.377.600
|
||||
#MIN = 864.000
|
||||
session['admin_expire_date'] = int(time.time()) - randint(10, 259) * 24 * 60 * 60
|
||||
#ADD = 2.592.000
|
||||
expire_date = int(time.time()) + 30 * 24 * 60 * 60
|
||||
cookie = f"username={username}&expires={expire_date}&admin={admin}"
|
||||
|
||||
return jsonify({
|
||||
"nonce": bytes_to_long(nonce),
|
||||
"cookie": bytes_to_long(cipher.encrypt(cookie.encode()))
|
||||
})
|
||||
|
||||
|
||||
@app.route("/flag", methods=["GET"])
|
||||
def get_flag():
|
||||
nonce = int(request.args.get("nonce"))
|
||||
cookie = int(request.args.get("cookie"))
|
||||
cipher = ChaCha20.new(nonce=long_to_bytes(nonce), key=session['key'])
|
||||
|
||||
try:
|
||||
dec_cookie = cipher.decrypt(long_to_bytes(cookie)).decode()
|
||||
token = parse_cookie(dec_cookie)
|
||||
if int(token["admin"]) != 1:
|
||||
return f"Admin value:{token['admin']}"
|
||||
#25.056.000 < value < 25.920.000
|
||||
#
|
||||
if 290 * 24 * 60 * 60 < abs(int(token["expires"]) - session['admin_expire_date']) < 300 * 24 * 60 * 60:
|
||||
return f"OK! Your flag: {flag}"
|
||||
else:
|
||||
return f"You have expired! with expiration: {token['expires']} and {session['admin_expire_date']}"
|
||||
except:
|
||||
return f"Something didn't work :C"
|
||||
158
back-to-the-future/des.py
Normal file
158
back-to-the-future/des.py
Normal file
@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
# encoding: utf-8
|
||||
|
||||
"""
|
||||
Flask session cookie toolkit.
|
||||
|
||||
Decode, verify or generate a signed Flask session cookie.
|
||||
|
||||
Credits to Terry Vogelsang for the original script (https://terryvogelsang.tech/MITRECTF2018-my-flask-app/)
|
||||
which I just slightly modified for my personal use.
|
||||
"""
|
||||
|
||||
from hashlib import sha512
|
||||
from flask.sessions import session_json_serializer
|
||||
from itsdangerous import URLSafeTimedSerializer, BadTimeSignature
|
||||
import argparse
|
||||
import base64
|
||||
from zlib import decompress
|
||||
import sys
|
||||
import json
|
||||
|
||||
# GENERAL FUNCTIONS.
|
||||
|
||||
def debug(msg):
|
||||
if VERBOSE_OUTPUT:
|
||||
print("[DEBUG] " + msg)
|
||||
|
||||
def pretty_print_json_data(json_data):
|
||||
json_pretty_str = json.dumps(json_data, indent=4)
|
||||
print(json_pretty_str)
|
||||
|
||||
# COOKIE DECODER.
|
||||
|
||||
def decode_cookie_payload(cookie):
|
||||
debug(f"Cookie:\n{cookie}")
|
||||
# If the cookie starts with a dot the paylod is base64 encoded and GZIP compressed.
|
||||
if cookie[0] == ".":
|
||||
b64_gzip_payload = cookie[1:].split(".")[0]
|
||||
# Python needs the padding which is stripped in the base64_URLsafe version (see https://stackoverflow.com/questions/2941995/python-ignore-incorrect-padding-error-when-base64-decoding#comment12174484_2942039)
|
||||
b64_gzip_payload += "=" * (-len(b64_gzip_payload) % 4)
|
||||
debug(f"Encoded and compressed payload:\n{b64_gzip_payload}")
|
||||
gzip_payload = base64.urlsafe_b64decode(b64_gzip_payload)
|
||||
payload = decompress(gzip_payload)
|
||||
debug(f"Decoded and decompressed payload:\n{payload}")
|
||||
else:
|
||||
# If the cookie does not start with a dot the payload is just base64 encoded.
|
||||
b64_payload = cookie.split(".")[0]
|
||||
# Python needs the padding which is stripped in the base64_URLsafe version (see https://stackoverflow.com/questions/2941995/python-ignore-incorrect-padding-error-when-base64-decoding#comment12174484_2942039)
|
||||
b64_payload += "=" * (-len(b64_payload) % 4)
|
||||
debug(f"Encoded payload:\n{b64_payload}")
|
||||
payload = base64.urlsafe_b64decode(b64_payload)
|
||||
debug(f"Decoded payload:\n{payload}")
|
||||
|
||||
return payload
|
||||
|
||||
def output_decoded_payload(payload, json_pretty, str_encoding):
|
||||
str_payload = payload.decode(str_encoding)
|
||||
if json_pretty:
|
||||
# Pretty print the JSON data.
|
||||
try:
|
||||
debug(f"Payload string (encoding=\"{str_encoding}\"):\n{str_payload}")
|
||||
pretty_print_json_data(json.loads(str_payload))
|
||||
except:
|
||||
print("The payload is not valid JSON!", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
# Do not pretty print the JSON data.
|
||||
print(str_payload)
|
||||
sys.exit(0)
|
||||
|
||||
# COOKIE VERIFIER.
|
||||
|
||||
def readAndVerifyCookie(cookie, secret_key):
|
||||
debug(f"Cookie:\n{cookie}")
|
||||
signer = URLSafeTimedSerializer(
|
||||
secret_key, salt="cookie-session",
|
||||
serializer=session_json_serializer,
|
||||
signer_kwargs={"key_derivation": "hmac", "digest_method": sha512}
|
||||
)
|
||||
try:
|
||||
session_data = signer.loads(cookie)
|
||||
print("The signature is correct!")
|
||||
return session_data
|
||||
except BadTimeSignature:
|
||||
print(f"The signature is not correct!")
|
||||
sys.exit(1)
|
||||
|
||||
# COOKIE GENERATOR.
|
||||
|
||||
def generate_cookie(json_str_payload, key):
|
||||
try:
|
||||
payload = json.loads(json_str_payload)
|
||||
except:
|
||||
print("Your payload is not a valid JSON string!")
|
||||
sys.exit(1)
|
||||
|
||||
signer = URLSafeTimedSerializer(
|
||||
key, salt="cookie-session",
|
||||
serializer=session_json_serializer,
|
||||
signer_kwargs={"key_derivation": "hmac", "digest_method": sha512}
|
||||
)
|
||||
cookie = signer.dumps(payload)
|
||||
return cookie
|
||||
|
||||
# MAIN.
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Argparse setup.
|
||||
argparser = argparse.ArgumentParser(description="Pefroma various actions regarding a Flask session COOKIE.")
|
||||
argparser.add_argument("command", metavar="COMMAND", choices=["decode", "verify", "generate"], help="the command to execute")
|
||||
argparser.add_argument("-c", "--cookie", metavar="COOKIE", help="the COOKIE to decode or verify")
|
||||
argparser.add_argument("-k", "--key", metavar="SECRET_KEY", help="the SECRET_KEY to sign or verify the cookie with")
|
||||
argparser.add_argument("-p", "--payload", metavar="PAYLOAD", help="the PAYLOAD to encode in teh cookie")
|
||||
argparser.add_argument("-v", "--verbose", action="store_true", help="enable verbose output")
|
||||
argparser.add_argument("--pretty-json", action="store_true", help="whether to pretty print the JSON data")
|
||||
argparser.add_argument("--encoding", default="UTF-8", help="the ENCODING to use when parsing data as a string")
|
||||
# Parse arguments.
|
||||
args = argparser.parse_args()
|
||||
command = args.command
|
||||
VERBOSE_OUTPUT = args.verbose
|
||||
# Choose command.
|
||||
if command == "decode":
|
||||
# Check arguments.
|
||||
if args.cookie is None:
|
||||
argparser.error("The 'decode' command requires the --cookie argument.")
|
||||
cookie = args.cookie
|
||||
json_pretty = args.pretty_json
|
||||
str_encoding = args.encoding
|
||||
# Decode.
|
||||
payload = decode_cookie_payload(cookie)
|
||||
# Output.
|
||||
output_decoded_payload(payload, json_pretty, str_encoding)
|
||||
elif command == "verify":
|
||||
# Check arguments.
|
||||
if args.cookie is None or args.key is None:
|
||||
argparser.error("The 'verify' command requires both the --cookie and the --key arguments.")
|
||||
cookie = args.cookie
|
||||
key = args.key
|
||||
pretty_json = args.pretty_json
|
||||
# Verify.
|
||||
session_data = readAndVerifyCookie(cookie, key)
|
||||
# Output.
|
||||
print('')
|
||||
if pretty_json:
|
||||
debug(f"Session data:\n{session_data}")
|
||||
pretty_print_json_data(session_data)
|
||||
else:
|
||||
print(json.dumps(session_data))
|
||||
elif command == "generate":
|
||||
# Check arguments.
|
||||
if args.payload is None or args.key is None:
|
||||
argparser.error("The 'generate' command requires both the --payload and the --key arguments.")
|
||||
payload = args.payload
|
||||
key = args.key
|
||||
# Generate.
|
||||
cookie = generate_cookie(payload, key)
|
||||
# Output.
|
||||
print(cookie)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user