Pivot Chain Challenge
hackthebox
Task: Find minimum detection risk path through a network graph. Solution: Dijkstra algorithm with priority queue for weighted shortest path.
$ ls tags/ techniques/
Pivot Chain Challenge — HackTheBox
Description
After bypassing CygnusCorp's perimeter defenses and cracking the PIN to gain internal access, you've uncovered a crucial piece of the network: the Core Administration Server. Your goal is to pivot laterally through the internal network to reach the server, but the path is not clear. The network is heavily monitored, and each host you move through carries a detection risk. Can you navigate the network stealthily, identify the safest paths, and reach the Core Administration Server without being detected?
Target: 94.237.120.233:40330
Analysis
Reconnaissance
- Connected to the service — discovered an HTTP server with a web code editor
- Page title "Pivot Chain" with an interface for solving challenges
- Found API endpoint
/runfor submitting code in Python, C, C++ or Rust
Challenge Format
- Input: N (hosts), M (paths), start host, target host
- Then M lines of edges: source destination risk
- Output: minimum total detection risk from start to target
- Constraints: 5 <= N <= 150000, 6 <= M <= 10^6
- Example: 5 hosts, 6 paths, optimal path host_1→host_2→host_3→host_4→host_5 with total risk 26
Algorithm Selection
This is a classic shortest path problem in a weighted directed graph:
- Dijkstra's algorithm — optimal for finding minimum cost path
- heapq from Python — efficient priority queue implementation
- Complexity: O((V + E) log V)
Solution
import sys import heapq from collections import defaultdict def solve(): input_data = sys.stdin.read().strip().split('\n') # Parse first line: N M start target first_line = input_data[0].split() N = int(first_line[0]) M = int(first_line[1]) start = first_line[2] target = first_line[3] # Build graph graph = defaultdict(list) for i in range(1, M + 1): parts = input_data[i].split() src = parts[0] dst = parts[1] risk = int(parts[2]) graph[src].append((dst, risk)) # Dijkstra algorithm dist = {start: 0} pq = [(0, start)] # (risk, node) while pq: curr_risk, node = heapq.heappop(pq) if node == target: print(curr_risk) return if curr_risk > dist.get(node, float('inf')): continue for neighbor, edge_risk in graph[node]: new_risk = curr_risk + edge_risk if new_risk < dist.get(neighbor, float('inf')): dist[neighbor] = new_risk heapq.heappush(pq, (new_risk, neighbor)) print(-1) # No path found solve()
Submitting the Solution
import requests code = '''...''' # code above response = requests.post( 'http://94.237.120.233:40330/run', json={'code': code, 'language': 'python'} ) print(response.json()) # {"challengeCompleted":true,"flag":"HTB{st34lthy_p1v0t1ng_compl3t3}"}
Key Indicators
Use this technique when:
- The task involves finding minimum/optimal path in a graph
- Edges have weights (cost, risk, time)
- Need to find a path from point A to point B
- Weights are non-negative (for Dijkstra)
- Large constraints require an efficient O((V+E) log V) algorithm
Alternative Approaches
| Algorithm | When to use |
|---|---|
| Dijkstra | Non-negative weights, single source |
| Bellman-Ford | Negative weights, detecting negative cycles |
| Floyd-Warshall | All pairs of vertices, small graph |
| BFS | Unweighted graph (all weights = 1) |
| A* | Heuristic available for estimating distance to target |
Notes
- Using
defaultdict(list)simplifies graph construction - Check
curr_risk > dist.get(node, float('inf'))prunes stale entries in the queue - Early exit upon reaching the target saves time
- For very large graphs, C++ can be used for speed
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar
Similar writeups
- [misc][free]Dynamic Paths— HackTheBox
- [misc][free]PINsmith— hackthebox
- [crypto][free]Rhome— HackTheBox
- [misc][free]PyDome— HackTheBox
- [hardware][free]Outrun— hackthebox