Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- $ cat /challenge/chat-server
- #!/usr/bin/env python
- import functools
- import hashlib
- import os
- import sqlite3
- import textwrap
- from Crypto.Cipher import AES
- from Crypto.Util.Padding import pad, unpad
- from flask import Flask, request, session, redirect
- HOST = os.getenv("CHAT_HOST", "127.0.0.1")
- PORT = int(os.getenv("CHAT_PORT", 8080))
- DB_PATH = os.getenv("DB_PATH", "./chat.db")
- app = Flask(__name__)
- def initialize_db():
- db = sqlite3.connect(DB_PATH)
- db.execute("CREATE TABLE IF NOT EXISTS users (username TEXT, hashed_password TEXT, admin BOOLEAN)")
- db.execute("CREATE TABLE IF NOT EXISTS encrypted_chats (encrypted_username_1 TEXT, encrypted_username_2 TEXT, encrypted_contents TEXT)")
- return db
- db = initialize_db()
- def encrypt(data, key=None):
- cipher = AES.new(app.secret_key, AES.MODE_ECB)
- return cipher.encrypt(pad(data, cipher.block_size))
- def decrypt(data, key=None):
- cipher = AES.new(app.secret_key, AES.MODE_ECB)
- try:
- return unpad(cipher.decrypt(data), cipher.block_size)
- except ValueError:
- raise RuntimeError("Invalid padding")
- def authed_only(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- if "username" not in session:
- return "You are not logged in! Please <a href='/login'>login</a> or <a href='/register'>register</a>.", 403
- return func(*args, **kwargs)
- return wrapper
- @app.after_request
- def format_response(response):
- if response.content_type.startswith("text/html"):
- original_data = response.get_data(as_text=True)
- dedented_data = textwrap.dedent(original_data).strip() + "\n"
- response.set_data(dedented_data)
- return response
- @app.route("/")
- def index():
- if "username" not in session:
- return 'Hello! Please <a href="/login">login</a> or <a href="/register">register</a>.'
- return f"""Hello {session['username']}! You are {'an admin' if session.get('admin') else 'not an admin'}.
- <br>
- <form action="/chat" method="get">
- <input type="text" name="other_username" placeholder="Username" required>
- <input type="submit" value="Chat">
- </form>
- """
- @app.route("/register", methods=["GET", "POST"])
- def register():
- if request.method == "GET":
- return """
- <form method="post">
- <input type="text" name="username" placeholder="Username" required>
- <input type="password" name="password" placeholder="Password" required>
- <input type="submit" value="Register">
- </form>
- """
- try:
- username = request.form["username"]
- password = request.form["password"]
- except KeyError:
- return "Missing username or password. Back to <a href='/'>home</a>.", 400
- if db.execute(f"SELECT * FROM users WHERE username='{username}'").fetchone():
- return "Username already exists. Back to <a href='/'>home</a>.", 400
- hashed_password = hashlib.sha256(password.encode()).hexdigest()
- admin = request.remote_addr == "127.0.0.1"
- db.execute(f"INSERT INTO users VALUES ('{username}', '{hashed_password}', {'true' if admin else 'false'})")
- db.commit()
- session["username"] = username
- session["admin"] = admin
- return redirect("/")
- @app.route("/login", methods=["GET", "POST"])
- def login():
- if request.method == "GET":
- return """
- <form method="post">
- <input type="text" name="username" placeholder="Username" required>
- <input type="password" name="password" placeholder="Password" required>
- <input type="submit" value="Login">
- </form>
- """
- try:
- username = request.form["username"]
- password = request.form["password"]
- except KeyError:
- return "Missing username or password. Back to <a href='/'>home</a>.", 400
- hashed_password = hashlib.sha256(password.encode()).hexdigest()
- result = db.execute(f"SELECT * FROM users WHERE username='{username}' and hashed_password='{hashed_password}'").fetchone()
- if not result:
- return "Invalid username or password. Back to <a href='/'>home</a>.", 400
- username, _, admin = result
- if admin and request.remote_addr != "127.0.0.1":
- return "Admins may only login locally. Back to <a href='/'>home</a>.", 403
- session["username"] = username
- session["admin"] = admin
- return redirect("/")
- @app.route("/chat/", methods=["GET"])
- @app.route("/chat/<other_username>", methods=["HEAD", "GET", "POST"])
- @authed_only
- def chat(other_username=None):
- if request.args.get("other_username"):
- return redirect(f"/chat/{request.args['other_username']}")
- username = session["username"]
- result = db.execute(f"SELECT * FROM users WHERE username='{other_username}'").fetchone()
- if not result:
- return "User does not exist. Back to <a href='/'>home</a>.", 404
- encrypted_username_1, encrypted_username_2 = sorted([encrypt(username.encode()).hex(), encrypt(other_username.encode()).hex()])
- result = db.execute(f"SELECT encrypted_contents FROM encrypted_chats WHERE encrypted_username_1='{encrypted_username_1}' AND encrypted_username_2='{encrypted_username_2}'").fetchone()
- try:
- contents = decrypt(bytes.fromhex(result[0])).decode() if result else ""
- except RuntimeError:
- # Failed to correctly decrypt, web server restarted (and generated a new secret key) or it was tampered with
- # Delete the chat and start a new one
- contents = ""
- etag = hashlib.sha256(contents.encode()).hexdigest()
- if request.method == "HEAD":
- return "", 200, {"ETag": etag}
- if request.method == "GET":
- contents_html = "\n<br>\n".join(contents.splitlines())
- return f"""
- <main>
- {contents_html}
- </main>
- <form method="post">
- <input id="message" type="text" name="message" placeholder="Message" required>
- <input type="submit" value="Send">
- </form>
- <script>
- let etag = "{etag}";
- window.scrollTo(0, document.body.scrollHeight);
- message.value = localStorage.getItem("message") || "";
- localStorage.removeItem("message");
- message.focus();
- interval = setInterval(() => {{
- fetch(location.href, {{method: "HEAD"}}).then(response => {{
- if (response.headers.get("ETag") !== etag) {{
- localStorage.setItem("message", message.value);
- location.reload();
- }}
- }});
- }}, 5000);
- </script>
- """, 200, {"ETag": etag}
- if request.method == "POST":
- try:
- message = request.form["message"].strip().replace("\n", " ")
- except KeyError:
- return "Missing message. Back to <a href='/'>home</a>.", 400
- encrypted_contents = encrypt((contents + f"{username}: {message}\n").encode()).hex()
- if contents:
- db.execute(f"UPDATE encrypted_chats SET encrypted_contents='{encrypted_contents}' WHERE encrypted_username_1='{encrypted_username_1}' AND encrypted_username_2='{encrypted_username_2}'")
- else:
- db.execute(f"INSERT INTO encrypted_chats VALUES ('{encrypted_username_1}', '{encrypted_username_2}', '{encrypted_contents}')")
- db.commit()
- return redirect(f"/chat/{other_username}")
- @app.route("/user/modify", methods=["GET"])
- @app.route("/user/<username>/modify", methods=["GET", "POST"])
- @authed_only
- def modify_user(username=None):
- if username is None:
- return redirect(f"/user/{session['username']}/modify")
- result = db.execute(f"SELECT * FROM users WHERE username='{username}'").fetchone()
- if not result:
- return "User does not exist. Back to <a href='/'>home</a>.", 400
- username, password, admin = result
- admin = bool(admin)
- if request.method == "GET" and session["admin"]:
- return f"""
- Modify user {username}:
- <form method="post">
- <input type="text" name="username" placeholder="Username" value="{username}">
- <input type="password" name="password" placeholder="Password">
- <input type="checkbox" name="admin" value="{'true' if admin else 'false'}"> Admin
- <input type="submit" value="Modify">
- <input type="submit" name="delete" value="Delete User">
- </form>
- """
- elif request.method == "GET" and not session["admin"]:
- return f"""
- Modify user {username}:
- <form method="post">
- <input type="password" name="password" placeholder="Password">
- <input type="submit" value="Modify">
- <input type="submit" name="delete" value="Delete">
- </form>
- """
- new_username = request.form.get("username", username)
- new_password = hashlib.sha256(request.form["password"].encode()).hexdigest() if request.form.get("password") else password
- new_admin = request.form.get("admin", ("true" if admin else "false")) == "true"
- admin_only = not all((username == new_username == session["username"],
- admin == new_admin == session["admin"]))
- if admin_only and not session.get("admin"):
- return "You must be an admin to modify other users. Back to <a href='/'>home</a>.", 403
- encrypted_username = encrypt(username.encode()).hex()
- if "delete" in request.form:
- db.execute(f"DELETE FROM users WHERE username='{username}'")
- db.execute(f"UPDATE encrypted_chats SET encrypted_username_1=NULL WHERE encrypted_username_1='{encrypted_username}'")
- db.execute(f"UPDATE encrypted_chats SET encrypted_username_2=NULL WHERE encrypted_username_2='{encrypted_username}'")
- db.execute(f"DELETE FROM encrypted_chats WHERE encrypted_username_1 IS NULL AND encrypted_username_2 IS NULL")
- db.commit()
- if session["username"] == username:
- session.clear()
- return "User deleted. Back to <a href='/'>home</a>."
- db.execute(f"UPDATE users SET username='{new_username}', hashed_password='{new_password}', admin={'true' if new_admin else 'false'} WHERE username='{username}'")
- if new_username != username:
- encrypted_username = encrypt(username.encode()).hex()
- encrypted_new_username = encrypt(new_username.encode()).hex()
- result = db.execute(f"SELECT * FROM encrypted_chats WHERE encrypted_username_1='{encrypted_username}' OR encrypted_username_2='{encrypted_username}'").fetchall()
- for encrypted_username_1, encrypted_username_2, encrypted_contents in result:
- contents = decrypt(bytes.fromhex(encrypted_contents)).decode()
- new_encrypted_username_1, new_encrypted_username_2 = sorted([encrypted_new_username if encrypted_username_1 == encrypted_username else encrypted_username_1,
- encrypted_new_username if encrypted_username_2 == encrypted_username else encrypted_username_2],
- key=lambda k: k or "")
- new_encrypted_contents = encrypt("".join(
- (line.replace(f"{username}: ", f"{new_username}: ", 1) if line.startswith(f"{username}: ") else line) + "\n"
- for line in contents.splitlines()
- ).encode()).hex()
- sql_set = ", ".join(f"{k}='{v}'" if v is not None else f"{k}=NULL" for k, v in
- dict(encrypted_username_1=new_encrypted_username_1,
- encrypted_username_2=new_encrypted_username_2,
- encrypted_contents=new_encrypted_contents).items())
- sql_where = " AND ".join(f"{k}='{v}'" if v is not None else f"{k} IS NULL" for k, v in
- dict(encrypted_username_1=encrypted_username_1,
- encrypted_username_2=encrypted_username_2,
- encrypted_contents=encrypted_contents).items())
- db.execute(f"UPDATE encrypted_chats SET {sql_set} WHERE {sql_where}")
- db.commit()
- if session["username"] == username:
- if new_username != username:
- session["username"] = new_username
- if new_admin != admin:
- session["admin"] = new_admin
- return "User modified. Back to <a href='/'>home</a>."
- if __name__ == "__main__":
- app.secret_key = os.urandom(16)
- app.config.update(SESSION_COOKIE_HTTPONLY=False)
- app.run(host=HOST, port=PORT, threaded=False)
- $ cat /challenge/run
- #!/usr/bin/exec-suid --real --environ=none -- /usr/local/bin/python -I
- import atexit
- import logging
- import multiprocessing
- import os
- import pathlib
- import re
- import signal
- import subprocess
- import sys
- import tempfile
- import threading
- import time
- import psutil
- import requests
- from dojjail import Host, Network, UNPRIVILEGED_UID
- from dojjail.capabilities import limit_capabilities, get_securebits, set_securebits, CAP, SECBIT
- from Crypto.Cipher import AES
- from Crypto.Util.Padding import pad, unpad
- from selenium import webdriver
- from selenium.webdriver.firefox.options import Options as FirefoxOptions
- from selenium.webdriver.firefox.service import Service as FirefoxService
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support.wait import WebDriverWait
- from selenium.webdriver.support import expected_conditions as EC
- from selenium.common.exceptions import TimeoutException
- logger = logging.getLogger(__name__)
- DH_p = int.from_bytes(bytes.fromhex(
- "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 "
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD "
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 "
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED "
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D "
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F "
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D "
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B "
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 "
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510 "
- "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"
- ), "big")
- DH_g = 2
- def start_chat_server():
- old_umask = os.umask(0o077)
- chat_server_dir = pathlib.Path(tempfile.mkdtemp())
- os.umask(old_umask)
- os.chown(chat_server_dir, UNPRIVILEGED_UID, UNPRIVILEGED_UID)
- set_securebits(get_securebits() | SECBIT.NO_SETUID_FIXUP)
- os.setresgid(UNPRIVILEGED_UID, UNPRIVILEGED_UID, UNPRIVILEGED_UID)
- os.setresuid(UNPRIVILEGED_UID, UNPRIVILEGED_UID, UNPRIVILEGED_UID)
- limit_capabilities(CAP.NET_BIND_SERVICE)
- os.chdir(chat_server_dir)
- dev_null_fd = os.open("/dev/null", os.O_RDWR)
- log_fd = os.open(chat_server_dir / "chat-server.log", os.O_RDWR | os.O_CREAT | os.O_APPEND, 0o644)
- os.dup2(dev_null_fd, 0)
- os.dup2(log_fd, 1)
- os.dup2(log_fd, 2)
- os.environ["CHAT_HOST"] = "0.0.0.0"
- chat_server_path = pathlib.Path(__file__).parent / "chat-server"
- os.execve(chat_server_path, ["chat-server"], os.environ)
- def main():
- if os.geteuid() != 0:
- print("Error: must be run as root", file=sys.stderr)
- sys.exit(1)
- flag = open("/flag").read().strip()
- cwd = os.getcwd()
- parent_process = psutil.Process(os.getppid())
- parent_euid = parent_process.uids().effective
- parent_env = parent_process.environ()
- if parent_euid == 0:
- logger.setLevel(logging.DEBUG)
- handler = logging.FileHandler("/tmp/run.log")
- handler.setLevel(logging.DEBUG)
- logger.addHandler(handler)
- os.environ["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
- alice_host = Host("alice")
- bob_host = Host("bob")
- mallory_host = Host("mallory")
- sharon_host = Host("sharon")
- hacker_host = Host("hacker", privileged_uid=parent_euid)
- network = Network("router", hosts={
- alice_host: "10.0.0.1",
- bob_host: "10.0.0.2",
- mallory_host: "10.0.0.3",
- sharon_host: "10.0.0.4",
- hacker_host: "10.0.0.5",
- })
- print("Starting...", end="", flush=True)
- network.run()
- os.environ["CHAT_HOST"] = network.host_ips[alice_host]
- os.environ["CHAT_PORT"] = "80"
- chat_server_url = f"http://{network.host_ips[alice_host]}"
- alice_host.exec(start_chat_server, wait=False)
- def wait_for_chat_server():
- for _ in range(50):
- try:
- requests.get("http://127.0.0.1")
- except requests.ConnectionError:
- time.sleep(0.1)
- continue
- return
- raise RuntimeError("Chat server did not start")
- alice_host.exec(wait_for_chat_server)
- def create_account(username, password, *, url=chat_server_url):
- requests.post(f"{url}/register", data={"username": username, "password": password})
- alice_password = os.urandom(16).hex()
- alice_host.exec(lambda: create_account("alice", alice_password, url="http://127.0.0.1"))
- bob_password = os.urandom(16).hex()
- bob_host.exec(lambda: create_account("bob", bob_password))
- mallory_password = os.urandom(16).hex()
- mallory_host.exec(lambda: create_account("mallory", mallory_password))
- sharon_username = f"sharon{int.from_bytes(os.urandom(8), 'big')}"
- sharon_password = os.urandom(16).hex()
- sharon_host.exec(lambda: create_account(sharon_username, sharon_password))
- def share_flag():
- """
- Sharon shares the flag with Bob.
- """
- session = requests.Session()
- session.post(f"{chat_server_url}/login", data={"username": sharon_username, "password": sharon_password})
- session.post(f"{chat_server_url}/chat/bob", data={"message": f"The flag is {flag}."})
- sharon_host.exec(share_flag)
- def check_flag():
- """
- Bob notices that the flag is shared with him and notifies Mallory.
- """
- session = requests.Session()
- session.post(f"{chat_server_url}/login", data={"username": "bob", "password": bob_password})
- response = session.get(f"{chat_server_url}/chat/{sharon_username}")
- if flag not in response.text:
- raise RuntimeError("Flag not shared")
- session.post(f"{chat_server_url}/chat/mallory", data={"message": "Wow, someone shared the flag with me!"})
- bob_host.exec(check_flag)
- def delete_account():
- """
- Sharon deletes her account.
- """
- session = requests.Session()
- session.post(f"{chat_server_url}/login", data={"username": sharon_username, "password": sharon_password})
- session.post(f"{chat_server_url}/user/{sharon_username}/modify", data={"delete": "Delete"})
- sharon_host.exec(delete_account)
- def check_chat_is_gone():
- """
- Bob notices that the chat with Sharon is gone.
- """
- session = requests.Session()
- session.post(f"{chat_server_url}/login", data={"username": "bob", "password": bob_password})
- response = session.get(f"{chat_server_url}/chat/{sharon_username}")
- if response.status_code != 404:
- raise RuntimeError("Chat not deleted")
- bob_host.exec(check_chat_is_gone)
- listening_event = multiprocessing.Event()
- reported_event = multiprocessing.Event()
- def browse():
- """
- Alice browses chat messages with Mallory.
- """
- os.environ["HOME"] = tempfile.mkdtemp()
- options = FirefoxOptions()
- options.add_argument("--headless")
- service = FirefoxService(executable_path="/usr/local/bin/geckodriver", log_path="/dev/null")
- browser = webdriver.Firefox(service=service, options=options)
- atexit.register(browser.quit)
- browser.get(f"http://127.0.0.1/login")
- browser.find_element(By.NAME, "username").send_keys("alice")
- browser.find_element(By.NAME, "password").send_keys(alice_password)
- browser.find_element(By.CSS_SELECTOR, "input[type='submit']").submit()
- try:
- WebDriverWait(browser, 2).until(EC.text_to_be_present_in_element((By.TAG_NAME, "body"), "Hello alice!"))
- except TimeoutException:
- raise RuntimeError("Login failed")
- browser.find_element(By.NAME, "other_username").send_keys("mallory")
- browser.find_element(By.CSS_SELECTOR, "input[type='submit']").submit()
- try:
- WebDriverWait(browser, 2).until(EC.url_matches(f"http://127.0.0.1/chat/mallory"))
- except TimeoutException:
- raise RuntimeError("Failed to open chat with mallory")
- listening_event.set()
- message_history = []
- while True:
- try:
- WebDriverWait(browser, 2).until(EC.presence_of_element_located((By.TAG_NAME, "main")))
- all_messages = [line.strip() for line in
- browser.find_element(By.TAG_NAME, "main").get_attribute("innerHTML").splitlines()
- if line.strip() and line.strip() != "<br>"]
- new_messages = all_messages[len(message_history):]
- for message in new_messages:
- logger.info(f"New message: {message}")
- if message == "mallory: I heard someone shared the flag with Bob!":
- browser.find_element(By.NAME, "message").send_keys("Thanks for letting me know!")
- browser.find_element(By.CSS_SELECTOR, "input[type='submit']").submit()
- reported_event.set()
- message_history.append(message)
- except Exception:
- logger.exception("Error while browsing")
- return
- time.sleep(1)
- alice_host.exec(browse, uid=UNPRIVILEGED_UID, wait=False)
- listening_event.wait()
- print("\r", end="", flush=True)
- pid = os.getpid()
- hacker_pid = hacker_host.exec(lambda: subprocess.run("/bin/bash", env=parent_env, cwd=cwd), wait=False)
- hacker_thread = threading.Thread(target=lambda: (os.waitpid(hacker_pid, 0),
- logger.info("Hacker shell exited"),
- os.killpg(pid, signal.SIGTERM)))
- hacker_thread.start()
- logger.info("Hacker shell started")
- reported_event.wait()
- logger.info("Mallory told Alice that someone shared the flag with Bob")
- def alice_message_bob():
- """
- Alice has a secure conversation with Bob, discovering from him who shared the flag.
- """
- session = requests.Session()
- session.post("http://127.0.0.1/login", data={"username": "alice", "password": alice_password})
- dh_a = int.from_bytes(os.urandom(256), "big")
- dh_A = pow(DH_g, dh_a, DH_p)
- session.post("http://127.0.0.1/chat/bob", data={"message": f"Hey Bob, I need to chat with you about something important. Let's chat securely over DHE-AES: {dh_A}."})
- logger.info(f"Alice told bob to chat securely with DHE-AES: {dh_A}")
- dh_B_re = re.compile(r"^bob: Hey Alice, sure: (\d+)\.$", re.MULTILINE)
- while True:
- response = session.get("http://127.0.0.1/chat/bob")
- if match := dh_B_re.search(response.text):
- break
- time.sleep(1)
- dh_B = int(match.group(1))
- dh_s = pow(dh_B, dh_a, DH_p)
- logger.info(f"Alice received DHE-AES response from Bob: {dh_B}")
- time.sleep(1)
- key = dh_s.to_bytes(256, "big")[:16]
- cipher_send = AES.new(key, AES.MODE_ECB)
- cipher_recv = AES.new(key, AES.MODE_ECB)
- encrypt = lambda data: cipher_send.encrypt(pad(data.encode(), cipher_send.block_size)).hex()
- decrypt = lambda data: unpad(cipher_recv.decrypt(bytes.fromhex(data)), cipher_recv.block_size).decode()
- logger.info(f"Alice established shared key with Bob: {key.hex()}")
- session.post("http://127.0.0.1/chat/bob", data={"message": encrypt("Hey Bob, I know that someone shared the flag with you. Who was it?")})
- logger.info("Alice asked Bob who shared the flag")
- encrypted_message_re = re.compile(r"^bob: ([0-9a-f]+)$", re.MULTILINE)
- flag_sharer_re = re.compile(r"Oh, it was '(\w+)'\.")
- while True:
- response = session.get("http://127.0.0.1/chat/bob")
- encrypted_messages = encrypted_message_re.findall(response.text)
- for encrypted_message in encrypted_messages:
- if match := flag_sharer_re.match(decrypt(encrypted_message)):
- break
- else:
- time.sleep(1)
- continue
- break
- flag_sharer = match.group(1)
- logger.info(f"Alice learned who shared the flag: {flag_sharer}")
- time.sleep(1)
- session.post("http://127.0.0.1/chat/bob", data={"message": encrypt("Thanks Bob, I'll look into it.")})
- logger.info("Alice thanked Bob")
- def bob_message_alice():
- """
- Bob has a secure conversation with Alice, confirming that Sharon shared the flag with him.
- """
- session = requests.Session()
- session.post(f"{chat_server_url}/login", data={"username": "bob", "password": bob_password})
- dh_A_re = re.compile(r"^alice: Hey Bob, I need to chat with you about something important\. Let's chat securely over DHE-AES: (\d+)\.$", re.MULTILINE)
- while True:
- response = session.get(f"{chat_server_url}/chat/alice")
- if match := dh_A_re.search(response.text):
- break
- time.sleep(1)
- dh_A = int(match.group(1))
- logger.info(f"Bob received DHE-AES request from Alice: {dh_A}")
- time.sleep(1)
- dh_b = int.from_bytes(os.urandom(256), "big")
- dh_B = pow(DH_g, dh_b, DH_p)
- dh_s = pow(dh_A, dh_b, DH_p)
- session.post(f"{chat_server_url}/chat/alice", data={"message": f"Hey Alice, sure: {dh_B}."})
- key = dh_s.to_bytes(256, "big")[:16]
- cipher_send = AES.new(key, AES.MODE_ECB)
- cipher_recv = AES.new(key, AES.MODE_ECB)
- encrypt = lambda data: cipher_send.encrypt(pad(data.encode(), cipher_send.block_size)).hex()
- decrypt = lambda data: unpad(cipher_recv.decrypt(bytes.fromhex(data)), cipher_recv.block_size).decode()
- encrypted_message_re = re.compile(r"^alice: ([0-9a-f]+)$", re.MULTILINE)
- while True:
- response = session.get(f"{chat_server_url}/chat/alice")
- encrypted_messages = encrypted_message_re.findall(response.text)
- if any(decrypt(encrypted_message) == "Hey Bob, I know that someone shared the flag with you. Who was it?"
- for encrypted_message in encrypted_messages):
- break
- time.sleep(1)
- logger.info("Bob asked by Alice about flag sharer")
- time.sleep(1)
- session.post(f"{chat_server_url}/chat/alice", data={"message": encrypt(f"Oh, it was '{sharon_username}'. I think she deleted her account.")})
- logger.info("Bob told Alice about flag sharer")
- while True:
- response = session.get(f"{chat_server_url}/chat/alice")
- encrypted_messages = encrypted_message_re.findall(response.text)
- if any(decrypt(encrypted_message) == "Thanks Bob, I'll look into it."
- for encrypted_message in encrypted_messages):
- break
- time.sleep(1)
- logger.info("Bob thanked by Alice")
- alice_host.exec(alice_message_bob, wait=False)
- bob_host.exec(bob_message_alice, wait=False)
- hacker_thread.join()
- if __name__ == "__main__":
- main()
- $
Add Comment
Please, Sign In to add comment