Portal Noncense
HackTheBox
**Goal:** Make `isPortalActive["orcKingdom"]` return `true` so that `Setup.isSolved()` passes.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Portal Noncense — HackTheBox
Description
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.
Analysis
Contracts
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"); } }
Attack Vector Analysis
Path 1: requestPortal() — Dead end:
- Requires
isExpertStandbyto be true (it's false, no setter exists) - Requires
msg.value > 1337 ether(player only has ~15 ETH)
Path 2: createPortal() — Exploitable:
- Does
delegatecalltodestinations["orcKingdom"]=0xFC31cde4aCbF2b1d2996a2C7f695E850918e4007 - This address has no code deployed on the challenge chain
- The challenge name "Portal Noncense" hints at nonce manipulation
Key Insight: Deterministic CREATE Addresses
Ethereum contract addresses created via CREATE opcode are deterministic:
address = keccak256(rlp(deployer_address, nonce))[12:]
...
$ grep --similar
Similar writeups
- [blockchain][free]Magic Vault— hackthebox
- [pwn][free]Portaloo— hackthebox
- [blockchain][free]Token to Wonderland— hackthebox
- [gamepwn][free]NoRadar— HackTheBox
- [blockchain][free]Honor Among Thieves— hackthebox