Blockchain

Hack The Box: 'Blockout ' A Blockchain Writeup - Global Cyber Skills Benchmark CTF 2025

Hack The Box: 'Blockout ' A Blockchain Writeup - Global Cyber Skills Benchmark CTF 2025

Cracking "Blockout": A Tale of Gaslighting Gateways in a Blockchain CTF

Capture The Flag (CTF) competitions are a fantastic way to test and hone cybersecurity skills. Recently, in the HTB's Global Cyber Skills Benchmark 2025, the "Blockout" challenge stood out as one of the trickier blockchain puzzles. Many participants found themselves scratching their heads, with 12 pwns in 3.5 days. With a bit of perseverance (and a few strategically placed cast commands), we managed to be the first ones to plunge Volnaya's VCNKv2 power grid into darkness 12 hours in. This write-up details the journey, the vulnerabilities, and the exploit that led to capturing the flag: HTB{REDACTED}.

Screenshot 2025-05-23 205118.png

Prerequisites: Setting up Your Toolkit

Before diving into the challenge, you'll need a couple of essential tools:

  •   Foundry: A blazing fast, portable, and modular toolkit for Ethereum application development. We'll primarily use cast from the Foundry suite to interact with the smart contracts.

  •   nc (netcat): A versatile networking utility used here to communicate with the challenge server for obtaining details and submitting the flag.

Installing Foundry (on Linux)

If you don't have Foundry installed, you can get it by running:


curl -L https://foundry.paradigm.xyz | bash
# The pipe (|) bash will take your curl output
# and send it as an input for the next command

Then, in a new terminal session, run foundryup to install the latest version:


foundryup

This will make cast, forge, and other Foundry tools available in your path.

Initial Reconnaissance: Connecting and Gathering Intel

The first step in any CTF is to understand the playground. The "Blockout" challenge provides a netcat interface that dispenses crucial information.

Connect to the server (e.g., 94.237.123.80:32139 in our case) and select option 1:


echo 1 | nc 94.237.123.80 32139


Your designated RPC an Player private key are:

RPC: http://94.237.123.80:42403

PrivateKey: 0xdedd2aa848b2344cc4f6d8c46dbfdb3a92146863574cadc0ea913422e23c5738



Your Player address is: 0xEdC1bBEa176cd432945180425795154b0Bba982F

The target contract VCNKv2 is deployed at: 0x64934dd027bDEA963fA623C28C476848CC55e468

The Setup contract is deployed at: 0x37F67BBEe5F98f3bf60D759D7185b6a87efA2f05

Make a note of these essential details:

  •   Player Private Key: 0xdedd2aa848b2344cc4f6d8c46dbfdb3a92146863574cadc0ea913422e23c5738 (This is your identity on the blockchain)

  •   RPC URL: http://94.237.123.80:42403 (Your connection point to the Ethereum node)

  •   Target Contract (VCNKv2): 0x64934dd027bDEA963fA623C28C476848CC55e468 (The main contract we need to exploit)

  •   Setup Contract: 0x37F67BBEe5F98f3bf60D759D7185b6a87efA2f05 (Used to check if the challenge is solved)

For the rest of this write-up, we'll use these values. Remember to replace them if you get different ones.

First Look: Understanding the Grid and the Goal

The challenge dropped us into a Foundry-based project. Our mission, as laid out in the Setup.sol contract, was clear: we needed to set the controlUnit.status within the VCNKv2 target contract to CU_STATUS_EMERGENCY (which has a value of 3). In simpler terms, trip the main breaker.


// Excerpt from Setup.sol

function isSolved() public view returns (bool) {

uint8 CU_STATUS_EMERGENCY = 3; // Our target status

(uint8 status, , , , ) = TARGET.controlUnit(); // TARGET is the VCNKv2 contract

return status == CU_STATUS_EMERGENCY;

}

The VCNKv2.sol contract represented the power grid's control system. It had a controlUnit struct managing things like current capacity, the number of active power gateways, and their health. Emergency mode, we discovered, could be triggered in two ways, defined by the failSafeMonitor modifier:

  1.  If controlUnit.currentCapacity dropped below FAILSAFE_THRESHOLD (10 ether).

  2.  If controlUnit.healthyGatewaysPercentage fell below 50%.


// Excerpt from VCNKv2.sol - The critical modifier

modifier failSafeMonitor() {

if (controlUnit.currentCapacity <= FAILSAFE_THRESHOLD) {

controlUnit.status = CU_STATUS_EMERGENCY;

emit ControlUnitEmergencyModeActivated();

}

else if (controlUnit.healthyGatewaysPercentage < 50) { // This became our focus

controlUnit.status = CU_STATUS_EMERGENCY;

emit ControlUnitEmergencyModeActivated();

}

else {

_; // Continue normal operation

}

}