We must steal all the funds from this contract to complete the challenge. We have donate and withdraw functions to donate and withdraw our ether. However, suppose we notice the withdraw function carefully. In that case, the contract is first transferring the ether using msg.sender.call and then deducting the amount from the balance since the contract is using callif the withdrawer is a smart contract the receive, or fallback functions can be activated. We can call the withdraw function again and again until the balance is drained out recursively, and it will work since we never completed the msg.sender.call line to get our balance reduced. This way, we can steal all the funds of this contract.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
interface Building { functionisLastFloor(uint) external returns (bool); }
contract Elevator { bool public top; uint public floor;
functiongoTo(uint _floor) public { Building building = Building(msg.sender);
if (! building.isLastFloor(_floor)) { floor = _floor; top = building.isLastFloor(floor); } } }
To complete this challenge, we need to make the value of bool top as True. However, it only gets reassigned if the Building contract gives the value as False. since msg.sender is the Building contract and we are the one who defines it, we can make the value changed before the Elevator contract calls it again.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract Privacy {
bool public locked = true; uint256 public ID = block.timestamp; uint8 private flattening = 10; uint8 private denomination = 255; uint16 private awkwardness = uint16(block.timestamp); bytes32[3] private data;
constructor(bytes32[3] memory _data) { data = _data; } functionunlock(bytes16 _key) public { require(_key == bytes16(data[2])); locked = false; }
/* A bunch of super advanced solidity algorithms... ,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^` .,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*., *.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^ ,---/V\ `*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*. ~|__(o.o) ^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*' UU UU */ }
To complete this challenge, we need to understand how solidity stores each type of data and how explicit converting works in solidity, and how the storage works inside the EVM, and read the key by calculating which slot it is stored and give it to unlock function.
To complete this challenge, we need to be the entrant, and we can do that if we can get past these three function modifiers, which act like gates. We cannot pass through the first gate if we directly interact with the contract, which means we have to write a smart contract to interact with this contract. The second gate checks if the gas left is a multiple of 8191, so we need to interact with the contract giving the required amount of gas which is a multiple of 8191. The third gate needs a _gatekey, which passes all the requirements which need the _gatekey to be a bytes8 type. The least significant 16 bits must be equal to the least significant 32 bits and lowest 16 bits of tx.origin and should not be equal to the _gatekey: uint32(uint64(_gateKey)) == uint16(uint64(_gateKey) != uint64(_gateKey) == uint16(uint160(tx.origin)). Satisfying all these requirements of three gates makes us the entrant.
This challenge is a sequel of the previous one and similarly has three gates to pass, and the first is the same as the gatekeeper one challenge, second gate checks if the size of data of the caller is 0 using extcodesize(caller()). This gate can be passed if the caller contract is running. It is a constructor while this call is made. Coming to the third gate, it checks the _gatekey equal to 2**256 when xored with the caller address.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
// string public constant name = 'NaughtCoin'; // string public constant symbol = '0x0'; // uint public constant decimals = 18; uint public timeLock = block.timestamp + 10 * 365 days; uint256 public INITIAL_SUPPLY; address public player;
// Prevent the initial owner from transferring tokens until the timelock has passed modifier lockTokens() { if (msg.sender == player) { require(block.timestamp > timeLock); _; } else { _; } } }
To complete this challenge, we must spend all our locked tokens for ten years. If we look at the contract, it inherits the ERC20 library from openzeppelin and overrides the transfer function to add the check if the locked period is completed or not. However, apart from the transfer function, this contract inherits many more functions, including approve and transferFrom. However, these functions are not overridden and do not check for the locked period. So we can approve funds to our address and spend them using the approve and transferFrom functions which we have access to use.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract Preservation {
// public library contracts address public timeZone1Library; address public timeZone2Library; address public owner; uint storedTime; // Sets the function signature for delegatecall bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));
constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) { timeZone1Library = _timeZone1LibraryAddress; timeZone2Library = _timeZone2LibraryAddress; owner = msg.sender; } // set the time for timezone 1 functionsetFirstTime(uint _timeStamp) public { timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); }
// set the time for timezone 2 functionsetSecondTime(uint _timeStamp) public { timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); } }
// Simple library contract to set the time contract LibraryContract {
// stores a timestamp uint storedTime;
functionsetTime(uint _time) public { storedTime = _time; } }
To complete this challenge, we must become the contract owner. This contract stores two addresses of different instances of the same library, LibararyContract and the owner address and then it stores an uint256 storedTime. since the functions are used to perform a delegatecall and reassigns a uint256 we can replace the first slot according to LibraryContract slot of storedTime if we replace it with the address our contract we can run some malicious code and replace the owner address to be the address of player.
// clean up after ourselves functiondestroy(address payable _to) public { selfdestruct(_to); } }
This contract is a SimpleToken factory that generates token contracts but does not store the address of the created contracts. The task is to recover the 0.001 eth from the contract created. Since we do not know the address, we have to calculate it and use the destroy function to recover the funds.
In [2]: from web3.middleware import geth_poa_middleware
In [3]: url = 'https://sepolia.infura.io/v3/e1881826831143f285a553a9a8f5a308'
In [4]: io = Web3(Web3.HTTPProvider(url))
In [5]: io.middleware_onion.inject(geth_poa_middleware, layer=0)
In [6]: pub = '0x25Bf651a048be8420997944C92c80e5064C1c5d6'
In [7]: ad = '0xCCF85c12C838a1BdDf89de787B11d01b28C4d5E6'
In [8]: import rlp
In [9]: rlp.encode([bytes.fromhex(ad[2:]),1]) Out[9]: b'\xd6\x94\xcc\xf8\\\x12\xc88\xa1\xbd\xdf\x89\xdex{\x11\xd0\x1b(\xc4\xd5\xe6\x01'
In [10]: io.soliditySha3(abi_types=['bytes32'],values=[rlp.encode([bytes.fromhex(ad[2:]),1])]) Out[10]: HexBytes('0xd0729ffe5272824ee52a49613ae562cdb3c5caa78df321dcbf66feb7fe25d466')
In [11]: io.soliditySha3(abi_types=['bytes32'],values=[rlp.encode([bytes.fromhex(ad[2:]),1])])[12:] Out[11]: HexBytes('0x3ae562cdb3c5caa78df321dcbf66feb7fe25d466')
In [12]: io.toChecksumAddress(io.soliditySha3(abi_types=['bytes32'],values=[rlp.encode([bytes.fromhex(ad[2:]),1])]) ...: [12:]) Out[12]: '0x3Ae562cdb3c5cAa78DF321DcBF66feb7Fe25d466'
For this challenge, we need to provide an address of a smart contract that returns the given number 42 when it calls whatIsTheMeaningOfLife() function, but it is size must be ten opcodes which forces us to use EVM bytecode. I have given up and looked at the walkthrough of this challenge and understood the basics of EVM bytecode from this blog blog and got the code for the smart contract.