A Guide For Advanced Message Protected API Hacking Using Hackvertor and Burp (part 2)
More up-to-date Hackvertor game-changer techniques, code examples, and tips for advanced penetration testing and bug bounty.
Hackvertor is a Burp extension that programmatically extends Burp capabilities, by allowing you to embed neat code logic directly into HTTP requests sent/proxies by Burp and its extensions. Similar to Postman pre-request scripts.
Here, I will try to provide more structured information and recipes, so in time of need, you won’t spend time on setup and basic things. Go beyond that with your attacks!
This article is the continuation of the part #1. I will address more use cases, edge cases, and will provide code examples to quickly start using Hackvertor.
HV Is A Game-Changer Tool
- Dissect custom encryption, message signing, or any other message security layers — inside Burp.
- Leverage Burp’s features and automate testing of mobile applications, APIs, or WEB.
- Challenge security by obscurity approach; Hack easily seemingly bulletproof APIs when their message protection layers peeled off.
- Link any external tool through Burp’s proxy with HV scripts processing the requests (like sqlmap).
- Much easier than writing Burp extensions (when we don’t need to process the server’s response).
Most of the things we will do here can be done manually or using any pure programming language or in combination with additional tools, such as Postman. But you will give up on all the Burp capabilities and extensions. With HV you can leverage Intruder, Extensions, Logger, Proxy, and more to work like a PRO.
For such a thing, we need a dynamic layer in between Burp and the server, luckily, we have a well-integrated and easy-to-use solution that works across all the Burp tools — Hackvertor extension (see part 1 for more info).
Of course, you can set up your custom middleware proxy that could do the same with the full code customizations as we want. Or you can write a custom Burp extension. But at what cost? Using HV custom scripts is a much faster, and more reusable solution.
When you stumble upon a custom message security layer or any variant of message level obstacle, in most cases that area will be a white spot across many testers. Always challenge the message protocol. There would probably hide some juicy issues.
With HV you can leverage Burp’s attack capabilities and Intruder automation. Also, you can use the HV tag with external tools that support proxies. Burp’s proxy also can process tags.
Passing Parameters To Our Python Code
- Passing up to 2 params directly into the function (string/int)
We can pass more;
In delimited string “a:b:c” and them split it
input1 = str(input).split(“:”)
We can pass JSON and parse it
jsonObj = json.loads(inputJSON)
for i in jsonObj:
- Every set HV variable is automatically injected/marshaled into python
You can see all of them by running dir() inside python code. For test purposes, you can just reflect the output = str(dir()) and view all the initialized parameters
Param Sequence Notes
When we want to update our request header upon body defined param that itself contains a HV input, like
Param processing is nested and done from within the deepest layer up. For example, in the example, below inJSON parameter that would hit the Python code would contain the execution result of <@timestamp/> tag.
- Param definition
- Custom signing tag
Another example of passing parameters:
Param processing when using the Intruder. First, the Intruder’s payload is placed into the request, and the HV processes the tag. Everything works seamlessly. However, the Intruder Attack UI won’t show the processing result, only a tag. The actual processed request you can view in the Logger tab.
- Do not forget to set param type as string/int, the name won’t be saved.
- Work with files. Upon each file save Hackvertor automatically reloads the scrip, at least for Repeater/HV tab (used to tune up the logic). Save the file, alter the HV Tab view (press space) and HV will automatically update the view based using the latest version of the file
- You can debug the code without burp (set mock parameters inside the script): java -jar .\jython-standalone-2.7.0.jar script.py
- When reopening Burp, the code execution tag id should be updated. When Burp starts, click Allow Code Execution inside HV top menu, open HV tab, add a custom tag and copy the new id value to the tags already used.
<@_Custom(“id code”)><@/_ Custom>
- Debugging your Python code without Burp and Hackvertor
java -jar .\jython-standalone-2.7.0.jar .\Fireblocks.py
Note, that standalone Jython loads the classes from ./ local Lib folder, while Hackvertor’s loads from the temp folder created during the start of Burp/HV.
- We aren’t really interested in fully replicating the original SDK/client behavior and can alter classes are we need it, for example with can use just a simple random number generator instead of a secure one.
- If you can’t make a Python library work with HV, don’t hesitate to embed only relevant code parts from it into your HV script. It has more benefits than drawbacks (also much faster) and will give you more ideas on how to attack the application. All of the needed code is already there, you just need to assemble the right parts in the right order into your code.
- Remember, that you can substitute the usage of well-known Python libs by using their java counterparts through Jython.
- For advanced cases when the usage of external libs is needed, like crypto stick to java classes like java.security, javax.crypto with Jython.
- When working with crypto, stick to the same classes and formats. Note, that hashing JSON string and different JSON representations will give different hash result values. Be aware of the exact classes in use. Let’s see some examples.
We have a couple of popular Python options to work with a JSON object. But be careful when using them in crypto-related flows.
The next 4 code examples show that each hashing technique could result in a different output, that will result in an invalid message signature. Know exactly how the client library works to be able to replicate its behaviour to create a valid message.
HV_AES_Encrypt.py — This Hackvertor script shows the basic usage of symmetric encryption. We would use it when certain parameters should be sent encrypted. In this particular example using AES/CBC/PKCS5PADDING suit with a padded timestamp as an initialization vector.
HV_API_Hash_Signing.py — This Hackvertor script shows a basic example of signing an HTTP body JSON message. Each message has a timestamp and signature calculated by concatenating API-specific JSON keys altogether with a secret value/token and hashing them with SHA384. The server upon message validation checks the timestamp and validates the signature by re-calculating the input JSON with the server-side stored authentication key of the client. Also, the server decrypts the CVV with a symmetric key linked to the specific client.
HV_JWT_Based_Request_Signing.py — This Hackvertor script shows an example for creating JWT based message signature for an HTTP request. The code takes as parameters: path, query, and HTTP body. Hashes them, and creates a one-time JWT token that is signed with the client’s RSA key. The JWT token is used for both authentication and message signing.
Using External Python Libraries
I wouldn’t recommend using external python libraries. Instead, either use Java classes or copy relevant Python libs code snippets into your code.
- In part one I showed that we can easily embed JS libs into our code by just copying the minified version of them. That scenario won’t work with Python.
- Using external Python libs, even designed for 2.7, would not be sufficient since they mostly cross-depend on valid python repo ecosystem/installation.
Install the latest python 2.7 with pip, install the needed package using PIP, and then copy the library folder (Python27\Lib\site-packages\jwt) to the Lib folder loaded by Jython.
- Local run: in the same folder as HV script file
- Burp: temporary Lib folder that is set at each start; you can get the path by calling the next code from Hackvertor script
output = str(sys.path)