As a pen-tester, there are going to be situations where you will be asked to provide evidence of the seriousness of a vulnerability that has been identified. There is ample documentation on how to do this for the more common vulnerabilities such as Cross-site Scripting (XSS) or SQL Injection. But what if you need to gauge the gravity of other, less common, vulnerabilities? This article, will discuss how a Server Side Request Forgery (SSRF) vulnerability can be used to gain knowledge of the server and the internal network where the web server is hosted, including information on the services hosted on the network. Such information is very useful for a hacker, and can be used to escalate the attack further.
We’ll start off by running a scan against one of the Acunetix vulnerable test websites – http://testphp.vulnweb.com. Since this article is about Side Request Forgery (SSRF) vulnerabilities, we’ll focus on an SSRF vulnerability identified by Acunetix at http://testphp.vulnweb.com/showimage.php
.
Server-side Request Forgery (SSRF) forms part of a class of vulnerabilities known as Out-of-band (OOB) vulnerabilities. Detecting SSRF (and other OOB vulnerabilities) requires the scanner to trick the web application into sending a request to the intermediary AcuMonitor service.
We can probably come up with a couple of interesting ways to abuse this vulnerability and have the server act as a proxy of sorts. However, our goal is to obtain more information about the web server itself. To do so, we need to take the HTTP request sent by Acunetix and take it further.
From within the vulnerability alert, you can copy the HTTP Request and paste it into any application that can send crafted HTTP Requests. In this example, we’ll be using the Acunetix HTTP Editor, which is part of the freely available manual tool suite.
You can first try to identify if the website allows connections to localhost by changing the URL to the following.
/showimage.php?file=http://127.0.0.1:80
In this case, the HTTP response contains an HTML body of the same page; indicating that the web server is not restricted from making connections to itself. We can proceed with confirming this, using ports which are commonly open on a web server such as port 22 (SSH) and port 25 (SMTP):
showimage.php?file=http://127.0.0.1:22 showimage.php?file=http://127.0.0.1:25
The above requests produce an error, but also include a port banner which indicates that a server is running on the specified port, and gives away information on the server running on the web server.
The following is the HTTP response body obtained for port 25 showing that a Postfix mail server is running on the same machine.
Warning: fopen(HTTP://127.0.0.1:25): failed to open stream: HTTP request failed! 220 rs202995.rs.hosteurope.de ESMTP Postfix (Ubuntu) in /hj/var/www/showimage.php on line 7
To make it easier to differentiate between open and closed ports, we could take a note of the response that is received when a port is not open. An example of such a request would be the following (nothing ever seems to be running on port 16).
/showimage.php?file=http://127.0.0.1:16
To which the server responds as follows.
Warning: fopen(http://127.0.0.1:16): failed to open stream: Connection refused in /hj/var/www/showimage.php on line 7 Warning: fpassthru() expects parameter 1 to be resource, boolean given in /hj/var/www/showimage.php on line 13
Using the Acunetix HTTP Editor to check a bunch of ports manually is lame and tedious. The HTTP Fuzzer can be easily used to automate this.
We can copy over the same request we used in the HTTP Editor, into the HTTP Fuzzer and start off by configuring a Number Generator which iterates through the numbers between 1 and 100. This will be used for the port number (assuming we only want to test for the first 100 ports). We can then amended the GET request to make requests to the localhost and insert the Number Generator instead of the port. This can be done by clicking where you want the number generator to be inserted and selecting the Number Generator and clicking on Insert into Request.
Click Start, and the Fuzzer will start iterating through the port numbers and making the requests. While this is being done, we can proceeded to configure a Fuzzer Filter which allows us to filter out results that indicate that a port is closed.
You can started off by removing all the default rules and add a new rule as follows.
- Give a description to your new Filtering Rule,
- Change the Rule Type to Exclude,
- Apply the rule on the Response.
- Supply following Regular Expression. This text is taken from the response received for a closed port in the example above.
failed to open stream: Connection refused in /hj/var/www/showimage.php on line 7
Click Ok, this will only show responses where an open port has been identified. Note that in some cases, no response might also indicate that an open port has been identified. The below screenshot shows that ports 21 and 53 might be open on the test server.
This technique can easily be taken a step further to scan for additional ports on the local machine, or to scan for other machines on the LAN of the web server.
You might be asking yourself – how is this different than a port scan on the external interface of the web site? Often there are situations where the firewall restricts connections to a specific server running on the web server (or on the LAN of the web server), however connections from the same machine are not. Server-side Request Forgery (SSRF) vulnerabilities make it possible to identify such servers, and possibly probe them further using specially crafted requests.
Get the latest content on web security
in your inbox each week.