This page looks best with JavaScript enabled

SQLMap: One time use CSRF tokens

 ·  ☕ 3 min read

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.

Web interface

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:

1
2
3
4
5
#!/usr/bin/env python

def tamper(payload,  **kwargs):
  print(', '.join(['{}={!r}'.format(k, v) for k, v in kwargs.items()]))
  return payload

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:

1
2
3
4
#!/usr/bin/env python

def preprocess(req):
  print(type(req))

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
    Full url
  • Get header
    Get header
  • Add 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.
Share on

ITasahobby
WRITTEN BY
ITasahobby
InTernet lover