One of the most painstaking aspects to performing a penetration test against an API is getting all the requests loaded into a scanning tool and making sure each request returns a "200 OK" status (or the expected status for the given API). In the case of SOAP APIs there is a standard format, called a WSDL, that can be used for documenting each request. In the case of REST endpoints, however, each request is freeform; meaning that no two requests submit data in the same way.
Some REST endpoints may accept JSON data, others may take XML, and others may take no information at all. Due to the freeform nature of these requests there is no standard way for developers to document how their endpoints work. This is where I want to focus most of the discussion in this blog post. From a consulting standpoint, this can become a problem, because no two sets of documentation are the same and the use cases for who typically reads the documentation also changes from client to client.
When RedTeam Security is hired to test a new set of REST APIs there is often a bit of effort put into understanding the layout of the documentation, extracting the necessary information, building the requests, and hoping we get the expected response status. This is where pURL comes into play. We wanted a tool that could take the basic information needed for a request, put it all together and send it to our other tools for security testing.
We could have just used the well-known tool cURL to start making the requests, but when you are testing 50 - 100 different API requests, this becomes a bit impractical. So, I looked to scripting a solution to sending these requests. I started with the information that we need to have to successfully make the requests; each request is comprised of: request method, URL, data to be sent, request headers.
Let's look at a sample request -
The above screen capture shows the basic request format to Slack's API auth.test, and will return user information if the token is valid. There are two ways we can build out this request within pURL. We can start by manually specifying each piece of the request, similar to how cURL is used by specifying each parameter at the command line:
The other way we can make this request is by loading each of the options from a text file, which we will show in a moment. By placing one request per line within a text file, we can start to make multiple API requests without typing out each of the input parameters. Below is an example of the text file used to make multiple requests. Note the format of each line is: method, URL, data, headers. Each piece of information is tab-delimited. The reason we decided to use tab-delimited is that it makes use with Excel documents easy. If you want the client to supply the given information in the format you need, you can build out an example within Excel and all they have to do is follow the example given. Using Excel's "Save As" function we can export the data into a text file, which can be read by pURL.
Note: the reason why headers are added last on each line is that multiple headers may need to be defined. In the example below, we show where the Content-Type header and X-API-Key headers are required.
Once we have the file setup we can begin submitting requests.
In the above screen capture, we have specified our localhost (Burp) to be the proxy, and specified unsafe since our proxy will not provide a valid certificate for the domain "slack.com." The added benefit of being able to send each request through Burp's proxy is that slack.com will be added directly into our targets list, and utilizing the context menu we can add each request to the scope, and perform active/passive scanning. Whereas using repeater to build out the requests, each request needs to be manually sent to the active scanner but is still not added to the target list.
As we can see above, slack is in our target list and we have each of the 3 requests to begin testing for security vulnerabilities. Hopefully, you find this tool useful. You can download it on our GitHub site here.