Cybersecurity is just like cooking, it's all about the layers.
Introduction to web3 security part two
Welcome back to the IInd part of our two-part blog series on web3 security. In the first part, we discussed the first five vulnerabilities commonly found in web3 applications. In this blog, we will continue our discussion and cover the remaining five vulnerabilities that can seriously threaten the security of web3 applications.
Web3 security is a complex and ever-evolving field, and staying up-to-date with the latest vulnerabilities and exploits is crucial in ensuring the security of your applications. We can proactively protect our applications and their sensitive data by understanding these vulnerabilities. So, let's dive into the second part of our blog and learn about the remaining five vulnerabilities that are commonly found in web3 applications.
Denial Of Service (DOS) Attack in Web3
A Denial of Service (DoS) attack is a cyber-attack where the attacker aims to disrupt the normal functionality of a website, server, or network by flooding it with excessive traffic or requests. The intention is to make the targeted system unavailable to legitimate users. This attack can be executed by flooding the system with a high volume of requests or exploiting vulnerabilities to cause it to crash or become unresponsive. Implementing effective mitigation strategies to protect against such attacks and ensure the availability and reliability of systems and services is essential.
DOS (Denial of Service) attacks in Ethereum smart contracts refer to exploiting vulnerabilities in the contract's code to overwhelm the network and hinder transaction processing and validation.
These attacks exploit flaws that enable malicious users to execute operations consuming excessive resources or computational power.
An attacker might create a smart contract with an infinite loop, flooding the network with requests and impeding new transactions.
Understanding Vulnerable Code
In the auction, the contract maintains a state variable currentLeader to track the current highest bidder and "highestBid" to store the highest bid amount.
The bid() function is used for bidding on the auction. It requires the sent value to be greater than the current highest bid.
The vulnerability lies in the line require(currentLeader.send(highestBid)); which is leveraged to refund the previous leader if their bid is surpassed. This line attempts to transfer the highestBid amount of ether to the currentLeader using the .send()function.
However, the .send() function has a limited gas stipend of 2300 gas units. If the currentLeader is a contract with a fallback function that consumes more than 2300 gas, the transfer will fail, and the function will revert. This behaviour can lead to a denial of service attack, preventing new bids from processing.
Mitigation against DOS
Implement identity verification: Require users to verify their identity using trusted third-party services or their verification system, adding a layer of security and helping ensure that only legitimate users can access and use the smart contract.
Establish a reputation system: Implement a mechanism where users must build a reputation within the network before utilising the smart contract. This can be done by tracking their transaction history and interactions on the network. Users with a positive reputation can access the contract, while new or unverified users may face limitations or additional scrutiny.
Enforce transaction limits: Set a limit on the number of transactions a single user can perform within a specific time frame. Restricting the number of transactions can prevent an attacker from overwhelming the network with many requests.
Set gas limits: Assign gas limits to individual transactions to prevent attackers from consuming excessive network resources. Gas limits ensure transactions have a reasonable computational cost and prevent malicious actors from exhausting the network's resources.
Monitor network activity: Continuously monitor the network for any unusual patterns or spikes in transaction volume. Implement monitoring systems that detect potential denial-of-service attacks based on unexpected traffic increments. Early detection allows for prompt response and mitigation measures.
In Ethereum smart contracts, a global variable called "tx.origin" is utilised to identify the external account responsible for initiating a transaction. This variable stores the user account address that initially created and transmitted the transaction to the network.
The "tx.origin" authentication attack is a security vulnerability that arises when a contract relies on tx.origin for message sender authentication instead of using "msg.sender". The tx.origin variable retrieves the account's address that initiated the transaction, which may not always match msg.sender.
Malicious actors can exploit this vulnerability by creating a contract to interact with the vulnerable contract and send a transaction with a different msg.sender than the tx.origin. By sending a deceptive message to the vulnerable contract, the attacker can trick it into assuming that the tx.origin is the original sender and proceed with the transaction execution.
Msg.sender vs Tx.origin
Owner can be a contract
Represents immediate sender
Represents original external sender
Flexibility and security
More flexibility and security
Less flexibility and security
It's important to note that tx.origin is not the same as msg.sender, which represents the address of the immediate sender of the current message or transaction. This is because a transaction can be forwarded or relayed by multiple contracts before it reaches the current contract, and msg.sender will always represent the immediate sender of the current message, even if it's a contract that forwarded the transaction.
Tx.origin is mainly used for security purposes to ensure that only authorised external accounts can execute certain operations in a smart contract. It is recommended to use msg.sender instead of tx.origin in most cases, as it provides more flexibility and security in contract execution.
Understanding Vulnerable Code
Exploiting this contract involves deploying it and persuading the owner of the Phishable contract to send a certain amount of ether to the deployed contract. The attacker may deceive the owner by presenting the deployed contract as their address and employing social engineering techniques to convince them to initiate a transaction to that address.
Unless the victim exercises caution, they may fail to recognise that code is associated with the attacker's address. The attacker could portray it as a sophisticated multi-signature or advanced storage wallet.
Suppose the victim initiates a transaction with sufficient gas to the AttackContract address. In such a case, it triggers the receive function, which subsequently invokes the withdrawal() function of the Phishable contract with the attacker parameter.
As a result, all funds from the Phishable contract will be transferred to the attacker's address. This occurs because the initial call to the contract was made by the victim, who is the owner of the Phishable contract.
Consequently, the tx.origin variable will equal the owner's address, satisfying the required condition in the Phishable contract.
Mitigation against tx.origin
Mitigating the tx.origin vulnerability involves adopting secure coding practices and following best practice guidelines. Here are a few mitigation strategies:
Use msg.sender for authentication: Instead of relying on tx.origin for message sender authentication, use msg.sender to verify the transaction's origin. "msg.sender" represents the immediate sender of the message and provides a more reliable source of information.
Apply access control mechanisms: Implement role-based access control (RBAC) or other access control mechanisms within your smart contracts. Only authorised users or contracts can execute sensitive functions or access critical resources.
Perform input validation and sanitisation: Validate and sanitise inputs received from external sources to prevent potential attacks, including those targeting the tx.origin vulnerability. Validate user input to ensure it aligns with expected formats and ranges, reducing the risk of malicious inputs.
Follow secure coding best practices: Adhere to secure coding practices when developing smart contracts. This includes techniques such as input validation, boundary checks, proper error handling, and adherence to the principle of least privilege. Regularly review and audit your code for potential vulnerabilities.
Third-party audits and security assessments: Consider engaging third-party security experts to conduct audits and security assessments of your smart contracts. External reviews can help identify vulnerabilities and provide recommendations for enhancing security.
Stay informed and updated: Stay up-to-date with the latest security best practices, vulnerabilities, and Ethereum and Solidity ecosystem fixes. Monitor security advisories and community discussions to stay informed about emerging threats and recommended mitigation techniques.
Entropy Illusion Attack
The Entropy Illusion attack is a critical security vulnerability that arises when the random number generator employed in a smart contract lacks true randomness and instead depends on predictable inputs. This flaw enables malicious actors to anticipate the output of the random number generator, granting them the ability to manipulate the contract's behaviour to their advantage.
The Entropy Illusion attack is a notable instance where a smart contract relies on the block timestamp as an input for generating random numbers. However, this approach poses a significant vulnerability as the block timestamp is publicly accessible and predictable. Exploiting this flaw, an attacker can strategically control the timing of their transactions to manipulate the contract's behaviour and influence the generated random numbers to their advantage.
Understanding Vulnerable Code
In the above contract, the generateRandomNumber() function attempts to generate a random number by combining the block timestamp with a nonce value. However, relying solely on the block timestamp for randomness is insecure and susceptible to the Entropy Illusion attack.
By controlling the timing of their transactions, an attacker can influence the block timestamp used in the random number generation process. This allows them to predict and manipulate the generated random numbers, compromising the integrity and fairness of any applications relying on this contract for randomness.
Mitigation against entropy illusion attack
Mitigation steps for the Entropy Illusion attack include:
Secure Random Number Generation: Implement a secure random number generation mechanism that relies on a cryptographically secure random number generator (CSPRNG) rather than predictable inputs like the block timestamp. Use established libraries or built-in functions that provide strong randomness.
External Oracle: Consider using external oracles or trusted third-party services to obtain random numbers. These oracles should have a secure entropy source and provide unpredictable random values that attackers cannot influence.
Multiple Sources of Entropy: Incorporate multiple sources of entropy to generate random numbers. This can include combining input factors such as block timestamp, block hash, miner address, transaction data, or other external factors. Diversifying the sources makes it harder for attackers to predict the outcome.
Auditing and Code Review: Conduct regular security audits and code reviews to identify and address any vulnerabilities related to random number generation. This helps ensure the code follows best practices and does not rely on predictable inputs.
Testing and Simulation: Test the smart contract extensively in different scenarios to evaluate the randomness and behaviour of the random number generation mechanism. Use simulation tools to analyse the output distribution and verify that it aligns with the expected randomness.
Education and Awareness: Raise awareness among developers about the risks and vulnerabilities associated with predictable random number generation. Promote best practices and guidelines for secure random number generation in smart contracts.
Integer Overflow and Underflow Attack
In the context of web3 and Ethereum, integer overflow and underflow refer to situations where the value of an integer variable exceeds its maximum value (overflow) or goes below its minimum value (underflow). These scenarios can lead to unexpected and potentially harmful consequences in smart contracts. The following section details the maximum capacity for various data types:
uint8 => 255
uint16 => 65535
uint24 => 16777215
uint256 => (2^256) - 1
Here, "uint" is an abbreviation for "unsigned integer." It is a built-in data type used to declare variables that can hold positive whole numbers (integers) without any fractional or decimal components. It is specified with a number representing the bits it can store, such as uint8, uint16, uint32, and so on, up to uint256. The number following uint denotes the number of bits and, therefore, the range of values that can be stored in the variable.
The integer overflow occurs when the result of an arithmetic operation on an integer exceeds the maximum value that can be stored in that data type. For example, if you have a uint8 variable with a maximum value of 255, performing an addition operation that results in a value greater than 255 will cause an overflow. When an overflow occurs, the value returns to zero, potentially leading to incorrect calculations or unexpected behaviour in the contract.
On the other hand, integer underflow occurs when the result of an arithmetic operation on an integer goes below its minimum value. Underflow is impossible for unsigned integer types like uint8 because the minimum value is always zero. However, signed integer types like int8 underflow can occur if the result of a subtraction operation goes below the minimum value, causing the value to wrap around to the maximum value.
Integer overflow and underflow can have severe security implications in smart contracts. Attackers can exploit them to manipulate calculations, bypass conditions, or drain contract balances. For example, if a contract tracks user balances and an overflow occurs during a balance update, an attacker could potentially withdraw more funds than they should be allowed.
Understanding Vulnerable Code
Integer Overflow Attack
In the above code, the deposit function allows users to add funds to their balance by simply increasing the balance variable with the += operator. However, this code does not include any checks for integer overflow.
If an attacker were to deposit a substantial value, such as the maximum value of uint256, it would cause an integer overflow. The balance variable would wrap around to zero, bypassing restrictions on the amount deposited. This could lead to incorrect balances and unexpected behaviour in the contract.
Integer Underflow Attack
In the above code, the withdraw function allows users to decrease their balance by a specified amount. However, this code does not include any checks for integer underflow.
If a user were to withdraw an amount greater than the current balance, it would cause an underflow. In Solidity, underflow occurs when a subtraction operation results in a value smaller than the minimum value allowed for that data type. In the case of unsigned integers, underflow wraps the value around to its maximum value.
For example, if the balance is 0 and a user tries to withdraw 1, an underflow will occur, and the balance will wrap around to its maximum value (2^256 - 1). This can lead to incorrect balances and unexpected behaviour in the contract.
Mitigation against Integer underflow and overflow attacks
Use Appropriate Data Types: Choose the correct data type that can accommodate the expected range of values. Consider using integer types, such as uint256 with more significant capacities, if you anticipate dealing with large numbers.
Range Checking: Implement range checks to ensure values fall within the expected range. Before performing arithmetic operations, validate that the inputs are within acceptable limits to prevent overflow or underflow. Use require or if statements to enforce these checks.
SafeMath Library: In older versions of Solidity (<0.8.0), use a library like SafeMath to perform arithmetic operations with built-in checks for overflow and underflow. However, starting from Solidity 0.8.0, the overflow and underflow checks are built into the language, so using SafeMath is not required.
Explicitly Handle Underflow: When subtracting values, handle potential underflow scenarios explicitly. Check that the result of the subtraction does not go below the minimum value allowed for the data type.
Use Assertion Libraries: Consider using assertion libraries like OpenZeppelin's SafeMath or Math libraries, which provide additional safeguards against integer overflow and underflow.
Comprehensive Testing: Thoroughly test your smart contracts to identify and fix potential vulnerabilities related to integer overflow and underflow. Write test cases that cover a wide range of input values and scenarios to ensure the correct behaviour of your contract.
Code Audits: Engage security experts or conduct third-party audits of your smart contract code. Experienced auditors can help identify potential vulnerabilities, including integer overflow and underflow, and provide recommendations for improvement.
In conclusion, the web3 security bugs demonstration sheds light on the potential vulnerabilities and risks associated with decentralised applications (dApps) and the broader web3 ecosystem. By showcasing these security bugs, we highlight the importance of prioritising robust security measures and conducting thorough audits during the development and deployment of dApps. You can find all the vulnerable code referenced in this blog here.
By addressing and mitigating these security bugs, the web3 community can help build a safer and more secure decentralised future, unlocking the full potential of blockchain technology while minimising risks and ensuring user confidence.
Thank you for reading this blog. We appreciate your interest in learning about the importance of web3 security bugs and their impact on the broader ecosystem. We can work together to create a safer and more secure web3 environment by informing ourselves and taking proactive measures. We highly recommend reading the accompanying part 1 of this blog for a complete understanding of web3 security.
Register for instructor-led online courses today!
Check out our free programs!