Overview
Table of Contents
Pickle Finance, a project on the Ethereum blockchain, experienced a significant security breach on November 21, 2020, resulting in a loss of approximately $19.76 million, equivalent to 19.76 million DAIs.
The methodology behind this hack involved the exploitation of two critical bugs in the ControllerV4 smart contract. These vulnerabilities were specifically related to input validation and arbitrary code execution, which the attackers manipulated to execute the breach successfully.
About Pickle Finance
Pickle Finance is a DeFi (Decentralized Finance) protocol on the Ethereum blockchain, primarily known for its yield-generating capabilities linked to YFI (Yearn Finance).
It enables users to deposit assets and earn yields via its Pickle Jars, which are adapted from Yearn Vaults v1 and managed by a specialized Controller contract.
Prior to the hack, the protocol boasted nearly $75 million in total value locked (TVL). However, the incident had a significant impact on investor confidence, as evidenced by a 50% drop in the price of Pickle Finance’s governance token on the day of the hack.
Root Cause of the Exploit
The hack on Pickle Finance was primarily facilitated by critical vulnerabilities in the ControllerV4 smart contract, especially within its swap functionality. These vulnerabilities were exploited through a complex sequence of actions, leveraging two distinct bugs in the contract:
Input Validation Bug
The ControllerV4 contract had a significant flaw in its swapExactJarForJar function. This function failed to properly validate whether the Jars (containers for user’s deposited funds) provided as input were legitimate or part of the Pickle Finance ecosystem.
The attacker utilized this bug to create two fake Jars and passed them as arguments to the swapExactJarForJar function. Due to the lack of validation, the contract processed these fake Jars, which led to the unauthorized withdrawal of all invested DAIs (19.76M) from the legitimate StrategyCmpdDaiV2 Jar back to the Pickle Jar.
Arbitrary Code Execution Vulnerability
This vulnerability was a more severe aspect of the hack, stemming from the contract’s ability to execute external, untrusted code within the context of the Controller. The critical point of failure was the _execute function call within the swapExactJarForJar method.
The attacker crafted a malicious contract and a set of inputs that, when passed through the swapExactJarForJar function, triggered a delegatecall to the CurveProxyLogic.add_liquidity.
Instead of functioning as intended, this action was manipulated to execute StrategyCmpdDaiV2.withdraw(), effectively transferring the cDAI (Compound DAI) tokens from the StrategyCmpdDaiV2 Jar to the Controller. The cDAI tokens were then deposited into the attacker’s malicious Jar, completing the transfer of funds to the attacker.
Pickle ControllerV4 Contract: https://github.com/pickle-finance/protocol/blob/4d7ecfa766536622848a29407c0464283d11fb67/src/controller-v4.solL250-L336
Detailed Analysis of the Hack
The exploiter’s modus operandi included:
Initial Setup and Funding
Malicious Contract Creation: The hack was initiated from a malicious contract created by address 0xbaC8a476B95eC741E56561a66231F92bc88bB3a8, which received funding via Tornado Cash
Step-by-Step Attack Flow
Asset Balance Query
- Method: The attacker used
StrategyCmpdDaiV2.getSuppliedUnleveraged()
to query the current asset balance, revealing 19.72M DAIs.
Exploitation of Input Validation Bug:
- Vulnerability: A bug in
ControllerV4.swapExactJarForJar()
failed to validate whether the provided Jars were genuine. - Action: Using two fake Jars, the attacker withdrew all DAIs from
StrategyCmpdDaiV2
toPickle-Jar
.
Deployment of Withdrawn DAIs
- Method: The hacker executed the
earn()
function three times. - Outcome: This resulted in the minting of 950,818,864.82119677 cDAIs to
StrategyCmpdDaiV2
.- 1st call: 19.76M DAI invested, 903,390,845.43581639 cDAI minted.
- 2nd call: 988K DAI invested, 45,169,542.27179081 cDAI minted.
- 3rd call: 49K DAI invested, 2,258,477.11358954 cDAI minted.
Arbitrary Code Execution for cDAI Withdrawal:
- Action: The
ControllerV4.swapExactJarForJar()
was again used, but with different arguments to trigger an arbitrary code execution. - Mechanism: A delegatecall was executed to withdraw cDAIs by manipulating the
CurveProxyLogic.add_liquidity()
function. - Result: The withdrawn cDAIs were deposited into a malicious
_toJar
, and then immediately transferred to the hacker.
Redemption of cDAIs:
Final Step: The hacker redeemed these cDAIs, walking away with all 19.759M DAIs. Key Transactions
Primary Hack Transaction: https://ethtx.info/mainnet/0xe72d4e7ba9b5af0cf2a8cfb1e30fd9f388df0ab3da79790be842bfbed11087b0
Malicious Contract: https://etherscan.io/address/0x2b0b02ce19c322b4dd55a3949b4fb6e9377f7913
Stolen Fund Details
The stolen funds were initially moved to the address 0x70178102AA04C5f0E54315aA958601eC9B7a4E08, then to 0x157b0f61C452b7f68C6485756D8472A461862A01, and subsequently through various addresses and cryptocurrencies.
Hack Aftermath
Initial Measures and Immediate Response
Disabling Deposits: The first reactive measure was disabling further deposits into the PickleJar. The Pickle Finance team implemented this by setting the minimum deposit amount to zero (setMin(0)
) for the DAI PickleJar, using the governance multisig.
This action was crucial to prevent further immediate losses. Governance and Security Adjustments
Switch from Timelock to Multisig: In response to the need for quicker decision-making capabilities, the governance model was shifted from a 12-hour Timelock to a multisig system. This allowed for more agile and timely responses to the unfolding situation.
Revoking Vulnerable Converter: A significant step in mitigating the hack was addressing the offending logic in the CurveProxyLogic, a Converter within the Controller that allowed arbitrary code injection. The critical code involved in this action is:
function revokeJarConverter(address _converter) public {
require(msg.sender == governance, "!governance");
approvedJarConverters[_converter] = false;
}
By invoking this function, the Pickle Finance team could revoke the problematic CurveProxyLogic from use, thus removing a key component of the exploit.
The specific revocation of CurveProxyLogic was pivotal in addressing the exploit directly.
These steps not only aimed to rectify immediate issues but also to restore trust in the protocol and contribute to the broader dialogue on DeFi security best practices.
Timeline of Key Events
- 2020-11-21, 18:37 UTC: The hack led to the loss of 19,759,355 DAI from the pDAI Jar.
- 2020-11-22, 03:58 UTC: Deposits into the pDAI Jar were suspended by setting the minimum deposit (
setMin(0)
). - 2020-11-22, 15:16 UTC: The CurveProxyLogic Converter was revoked from the Controller, eliminating a critical vulnerability.
Market Impact
Token Value Decline: The hack had an immediate impact on the market value of Pickle Finance’s governance token, which plummeted by 50% to $11.16, reflecting investor concerns and the urgent need for robust security measures.
Lessons Learnt
- Improve Input Validation: Ensure all inputs, especially in critical functions like jar swaps, are thoroughly validated.
- Restrict Arbitrary Code Execution: Implement safeguards against unauthorized delegate calls or external code execution within smart contracts.
- Enhanced Auditing and Testing: Regular and rigorous auditing of smart contract code, possibly involving third parties like ImmuneBytes, could prevent similar vulnerabilities.
Conclusion
The Pickle Finance hack demonstrates the critical need for rigorous smart contract auditing and secure coding practices.
Had comprehensive validation and security measures been in place, this exploitation could have been avoided. The future of blockchain security hinges on continuous improvement and learning from past incidents.
Engaging with experienced auditors like ImmuneBytes can be a crucial step towards ensuring more robust and secure DeFi platforms.