$ cat writeup.md…
$ cat writeup.md…
HackTheBox
**Goal:** Make `isPortalActive["orcKingdom"]` return `true` so that `Setup.isSolved()` passes.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
The group, who had gathered all the keys, found themselves at the portal station, trying to find a way to get to the Orc Kingdom, where the treasure was located according to the map. But as they looked around, they realized that the expert who usually helped them navigate the portals was nowhere to be found. They need to reverse engineer the process and figure out how to spawn a portal to their destination.
Goal: Make isPortalActive["orcKingdom"] return true so that Setup.isSolved() passes.
Setup.sol — deploys PortalStation and checks if TARGET.isPortalActive("orcKingdom") is true.
Portal.sol — main contract with two methods to activate portals:
contract PortalStation { mapping(string => address) public destinations; mapping(string => bool) public isPortalActive; bool isExpertStandby; constructor() { destinations["orcKingdom"] = 0xFC31cde4aCbF2b1d2996a2C7f695E850918e4007; destinations["elfKingdom"] = 0x598136Fd1B89AeaA9D6825086B6E4cF9ad2BD4cF; destinations["dawrfKingdom"] = 0xFc2D16b59Ec482FaF3A8B1ee6E7E4E8D45Ec8bf1; isPortalActive["elfKingdom"] = true; } function requestPortal(string calldata _destination) public payable { require(destinations[_destination] != address(0)); require(isExpertStandby, "Portal expert has a day off"); require(msg.value > 1337 ether); isPortalActive[_destination] = true; } function createPortal(string calldata _destination) public { require(destinations[_destination] != address(0)); (bool success, bytes memory retValue) = destinations[_destination].delegatecall( abi.encodeWithSignature("connect()") ); require(success, "Portal destination is currently not available"); require(abi.decode(retValue, (bool)), "Connection failed"); } }
Path 1: requestPortal() — Dead end:
isExpertStandby to be true (it's false, no setter exists)msg.value > 1337 ether (player only has ~15 ETH)Path 2: createPortal() — Exploitable:
delegatecall to destinations["orcKingdom"] = 0xFC31cde4aCbF2b1d2996a2C7f695E850918e4007Ethereum contract addresses created via CREATE opcode are deterministic:
address = keccak256(rlp(deployer_address, nonce))[12:]
...
$ grep --similar