Tower of Hanoi

X-MAS CTF - 残響

by on under XMASCTF2021
4 minute read ·

Challenge: 残響


nc 8014

Analizing Given Files:

Analizing the given files we can understand that:

  • Setup.sol, as the name suggest, is a contract that setup the blockchain environment interacting with the Iterator.sol contract and creating a new Iterator contract transferring it a value of 30 Ether.
  • Iterator.sol is a contract with some functions that permit to donate and withdraw ethers from and to that contract and also check the balance of an address. Analyzing its code we can find out that its witdraw function is vulnerable to a Re-Entrancy Attack: the variable balances isn’t safety updated in the witdraw function, so it’s possible to call witdraw multiple times before it finishes executing.

Re-Entrancy Attack

This type of attack consist of calling recursively a vulnerable function that didn’t check it’s own state. This attack was the hearth of The DAO Hack, an hacking attack that happened in June 2016 and drained the funds of the largest smart contract of that time, that held more than 150 million dollars in Ether. A more detailed description of the history of the DAO’s hack can be found here.

Exploit Creation

To perform this kind of attack we need to create a new contract, Reentrancy.sol, in which we write the exploit. The contract must first call the existing Iterator.sol contract:

Iterator public iterator;

constructor(address payable etherIteratorAddress) public {
    iterator = Iterator(etherIteratorAddress);

The heart of the exploit is the function attack:

function attack() external payable {
    require(msg.value >= 1 ether);
    iterator.donate.value(1 ether)(address(this)); 
    iterator.withdraw(1 ether);

The attack function, because of the lack of state variables or function modifiers in the witdraw function of Iterator.sol, was able to call iterator.withdraw() multiple times before it finished executing. This resulted in more refunds and essentially recovering all the Ether in the contract.

Transaction Sending

After the creation of Reentrancy.sol, we can connect to the blockchain given by the challenge with the rpc endpoint given through nc 8014, after selecting launch new instance. With that command we also receive the Setup contract address and an uuid that will then be necessary to get the flag. To connect to the blockchain provided we can use a web-based IDE, Remix, that provides the possibility to connect to an external blockchain. The connection and contract development in the external blockchain can also be done also with the python library.
With Remix IDE all we have to do is: open the File Explorer tab and upload the three contracts, then go to the Solidity Compiler tab and compile the three contracts by selecting the correct version of solidity (in this case 0.6.0) and finally deploy the contracts by going to the Deploy and Run Transactions tab.

To deploy the contracts we must first connect to the external blockchain of the challenge, to do this we have to change the Remix environment to Web3 Provider (that enables the connection to a remote node) and insert the rpc endpoint link given. Then we insert the address of the Setup.sol contract in Load Contract from Address and by clicking on At Address we will load the contract in the address given. We could then see the contract loaded in the Deployed Contracts section with the respective callable functions. To call a function of a contract in Remix IDE it’s needed to go to the Deployed Contracts selection and click on the button named as the function.
By calling the Setup.iterator() function we can obtain the address of the Iterator.sol contract. We then deploy the Reentrancy.sol contract by selecting it and giving the Iterator contract address as a parameter. Finally by calling the Reentrancy.attack() function, which requests to receive an ether since it is a payable function and we have set require (msg.value> = 1 ether);, we can empty the Iterator.sol contract of the 30 ethers that originally contained (see address (iterator) .transfer (30 ether); from Setup.sol).
Now by calling the Setup.isSolved() function, which checks if the balance of the Iterator.sol contract is equal to zero, we get a value of true.

Getting the flag

Finally, after the function Setup.isSolved() returned true, we can get the flag by connecting to nc 8014, selecting get flag and inserting our uuid.

Turns out that the flag was: X-MAS{Th1s_goes_0n_and_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on_and_on}

X-MAS CTF, Solidity, Ethereum, Blockchain, Re-Entrancy, Smart Contract
comments powered by Disqus