Introduction
It is pretty common to see webs that protects their forms with csrf tokens to avoid custom request being crafted from external sources.
Even though that it may seem a pretty strong protection, it can be ‘bypassed’ by crafting a before hand request to the same endpoint, then within that session crafting the malicious payloads. Keep in mind that csrf token expiration time may vary depending on how the website was developed. Furthermore the most interesting fact about this poc it is that the token refreshes on each request.
PoC
Download the files from my github and follow the “setup” steps to run the vulnerable web.
As you can see in the web you can make a post request that includes your token, however it is inside the html which gives a hard time to automated tools like sqlmap detect whether if it has csrf token or not and where it is stored.
Additionally for debugging and testing purposes you can add the parameter &god
to avoid csrf token to be checked.
Firstly thought of using tamper script, however it had a big issue, it can only access post payloads not get parameters, here is a simple tamper code to check what is available from the script:
|
|
The output is:
headers={}, delimiter='&', hints={}
After some testing found an interesting behaviour, even if you include the parameter --method=GET
in sqlmap, the payload of the tamper scripts are always included in the body as it was a POST request. Therefore as the poc scenario was using GET this parameter was of no help.
Keep in mind that this approach may work if the csrf token is passed in the headers or in the body of a POST request.
Within some time found the parameter --preprocess
that lets you run a script before it processes the request, receiving the request itself as a parameter. Started by checking what actual type of object is with a simple preprocess script:
|
|
Apparently it uses <class 'urllib.request.Request'>
so checked the official documentation in order to see what methods and atributes it has.
Found 3 interesting methods/attributes for this scenario:
- Full url
- Get header
- Add header
Then created a script that takes advantage of them, and gets the csrf token from the html content using BeautifulSoup. Finally adds the parameter to the url.
You can check the source code of the script here.
The script in case that you don’t supply
PHPSESSID
it takes the one from the first response, otherwise it uses the one you specify.
Alternatives
Without using SQLMap this could be approached in two different ways:
- Create a custom script.
- Code a proxy that behaves similarly to the preprocess script together with
--proxy
.