Fallout (Level-2) CTF
Introduction
This challenge simulates a real-world attack that happened on the “Rubixi” contract. You can check our explanation of the “Rubixi ” contract hack here: https://medium.com/@hydraxchain/the-rubixi-hack-c7ae59afd957
Smart Contract Source Code
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract Fallout {
using SafeMath for uint256;
mapping (address => uint) allocations;
address payable public owner;
/* constructor */
function Fal1out() public payable {
owner = msg.sender;
allocations[owner] = msg.value;
}
modifier onlyOwner {
require(
msg.sender == owner,
"caller is not the owner"
);
_;
}
function allocate() public payable {
allocations[msg.sender] = allocations[msg.sender].add(msg.value);
}
function sendAllocation(address payable allocator) public {
require(allocations[allocator] > 0);
allocator.transfer(allocations[allocator]);
}
function collectAllocations() public onlyOwner {
msg.sender.transfer(address(this).balance);
}
function allocatorBalance(address allocator) public view returns (uint) {
return allocations[allocator];
}
}
- We start as usual by defining the “pragma” and solidity version, and we notice that the “pragma” is unlocked, which is not best practice.
- We are using SafeMath.sol from “openzeppelin”.
- After that, we define the contract
contract Fallout
- Now we are using the “SafeMath” function and basically, It says attach the function (SafeMath) to (uint256) type.
- After that, we use a mapping structure to map the addresses inside allocations.
- Finally, we are defining a variable called “owner” and its type “address” it's payable and public.
- Here we have a constructor, and they are following the old school way, which it’s not existed since “solidity 0.4”. you use the same name of the contract to define the constructor.
NOTICE: the name of this function should be “Fallout()” but there is a typo “Fal1out()”. So basically, this won’t be initiated when the contract starts because it’s not a constructor anymore, it’s a normal function that we can just call.
- We have a control check modifier here, which set the function to be called only by the owner.
- Allocate function, it’s a public payable function we can send tokens to this function. Whatever the sender sends, the sent value will be added to the allocations, something like balance.
- This function will take an address from you, and it’s required that this address balance it’s more than 0. finally, transfer the allocations of the allocator.
- This function it’s protected by the control check modifier.
We are saying only the owner can call this function, and transfer all the balance in the allocations.
- Finally, this is a balance check function, where we can check the balance of this address.
Exploiting the Smart Contract
All we have to do is to call the function “Fal1out()”. If you remember we said that because the typo “Fal1out” is now a normal function that we can call not a constructor. if this doesn’t run when the smart contract gets deployed that means the owner is not the “msg.sender” (in this case, the deployer) so anyone who calls this function becomes the owner.
Check the addresses
Let’s, first of all, check the player’s address and the contract owner’s address
player
await contract.owner()
Call Fal1out()
await contract.Fal1out({value: 1})
This function is payable so we are passing “1” token. The transaction is successful
Now, Check the addresses again.
Submit the machine
Conclusion
Don’t forget to checkout the explanation & The previous “CTF” levels about the “Smart Contracts”.
Rubixi Hack explain: https://hydraxchain.medium.com/the-rubixi-hack-quick-explain-c7ae59afd957
Level-0: https://hydraxchain.medium.com/ethernaut-level-0-ctf-7c5a170eba72
Level-1: https://hydraxchain.medium.com/fallback-level-1-ctf-70be3aaa7282
Follow Us (Team):
- Zeyad Azima
- Mohammad Hussam Alzeyyat (MHZCYBER)