Step 258. HTB Easy x2 (Cumulative 6) — Time-Limit Training: Solving with the Clock On
Level 3 — Real-World CTF & Advanced Offensive Skills | Difficulty ★★★★☆ | Estimated time: 12+ hours (max 6 hours per machine + retrospectives)
Prerequisites: Steps 256–257 (4 cumulative Easy machines, entry-point type table, playbook) — the machine-log habit is second nature.
- What you need: Your entry-point type table and time-trend data from Step 257, Python 3 (for the time-recording script — measured: Python 3.12.14), and an alarm (phone timer).
- ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime. Hack The Box (
hackthebox.com) is a legal learning platform officially opened by its operators for attack practice — do not use today’s techniques on anything outside this platform’s machines. - Measurement note: The time-recording script in 3-2 and its output are measured (2026-09-09) on my PC. All HTB machine-solving screens are Screen examples.
Competitions and exams run on clocks. The OSCP exam is 24 hours, CTF qualifiers are a few hours, and within that window, "where you spend your time" decides pass or win. Until now you’ve trained for accuracy — starting today, you put a clock on top of it.
Today’s structure is simple. You solve two new Easy machines, each inside a 6-hour timebox, with a goal of a 4-hour finish. And you record the timestamp of every phase, then analyze afterward "where did the time go?" A time limit is a measuring device before it is a pressure device — measure it and you see it. Where you stretch out is precisely your weakness map.
1. Learning Objectives
By the end of this chapter, you will be able to:
- Set per-phase time allocations (recon/exploitation/escalation) and enforce them with alarms
- Build and use a tool that records phase-transition timestamps
- Apply the 30-minute rule without abandoning it under time pressure
- Analyze an overtime machine by "in which phase did it overflow?"
- Complete a time retrospective for 6 cumulative machines
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | 2 HTB Easy machines + attack machine + Python timer + phone alarms |
| Today’s commands | python htb_timer.py machine-name (a tool you build today) + everything so far |
| Concepts needed | Timeboxing, per-phase time allocation, pace, the timed version of the 30-minute rule, retrospective analysis |
| Today’s deliverable | Cumulative 6 machines + time-allocation retrospective + htb_timer.py |
2-1. Why Turn the Clock On — Measurement Is Diagnosis
In Step 257 you recorded time to user. Today you raise the resolution — not "3 hours to user" but "recon 50 min, enumeration 1h 10m, exploitation 1h, escalation 40m."
What this decomposition shows: most overruns come from repetition inside a specific phase. If recon ran second-longest, it’s a tooling problem (wordlist choice, scan speed); if exploitation stretched, it’s a hypothesis-prioritization problem; if escalation ran long, it’s a hole in your pattern notes. Total time only reports the result; per-phase time reports the cause.
2-2. Time Allocation — A 6-Hour Box, a 4-Hour Goal
Start with this basic allocation.
[Operating timebox: 6 hours]
Recon (full scan + paths + hypotheses) 1 hour → alarm at 1:00
Exploitation (foothold → user) 3 hours → alarm at 4:00
Escalation (user → root) 2 hours → alarm at 6:00 (hard stop)
[Training goal: 4-hour finish]
Recon 45m / Exploitation 2h / Escalation 1h 15m
The allocation table’s real function is not "limits" but "warnings." The alarm rang and recon isn’t done — that’s the first anomaly signal of this round. However, skipping the full scan to shrink recon time is the worst possible saving (section 6, Wall 1). Recon should if anything go wider; the place you save is verification — by discarding dead hypotheses faster.
2-3. The Timed 30-Minute Rule — Procedure Under Pressure
Once the clock runs, procedure crumbles. The moment "no time for logging" crosses your mind will definitely come. So you reinforce the rule into its timed version.
[30-minute rule — time-limited edition]
- 30 minutes on one path = judged by the timer log, not an alarm
- Return procedure within 5 minutes: re-read enumeration results → re-rank hypothesis list → next path
- Things you may skip because "there's no time": none
(skipping recon or logging isn't saving; it's booking a delay)
Paradoxical as it looks, the more the training is time-limited, the more faithful you must be to procedure — because procedure doesn’t consume time; it prevents waste.
2-4. The Overtime Analysis Frame — A Map of Where the Time Went
A machine that went past 6 hours (or missed the 4-hour goal) is not a failure — it’s the best data. After the round ends, fill in these four boxes.
① In which phase did it overflow? (recon/exploitation/escalation)
② Inside that phase, what ate the time? (e.g., repeating the same hypothesis, tool setup, searching)
③ Is it a knowledge gap or a procedure slip? (the prescriptions differ)
④ The one thing to change next round (one thing only)
Why ④ is "one thing": if you fix several at once, you can’t tell which one worked. Fixing one per round means six fixes after six rounds.
3. Follow Along
3-1–3-2 are tools you build on your own PC (measured); 3-3–3-5 are operations on HTB machines (Screen examples).
3-1. The Time Recorder — htb_timer.py
Writing timestamps by hand doesn’t survive combat. You build a small tool that stamps the time when you just type a phase name. Save it as htb_timer.py (measured: written and run on Python 3.12.14).
#!/usr/bin/env python3
"""htb_timer.py — per-phase time recorder for HTB machine solving"""
import sys
import time
from datetime import datetime
from pathlib import Path
PHASES = ["recon", "enum", "foothold", "user", "privesc", "root"]
def fmt(seconds: float) -> str:
m, s = divmod(int(seconds), 60)
h, m = divmod(m, 60)
return f"{h}h {m:02d}m {s:02d}s" if h else f"{m}m {s:02d}s"
def main() -> None:
if len(sys.argv) < 2:
print("Usage: python htb_timer.py <machine-name>")
sys.exit(1)
name = sys.argv[1]
log = Path(f"htb_timer_{name}.md")
start = time.time()
marks: list[tuple[str, float]] = []
with log.open("a", encoding="utf-8") as f:
f.write(f"\n# {name} — {datetime.now():%Y-%m-%d %H:%M} start\n")
print(f"[{name}] Timer started. Enter a phase: {' / '.join(PHASES)} (q=quit)")
while True:
try:
phase = input("phase> ").strip().lower()
except EOFError:
break
if phase == "q":
break
if phase not in PHASES:
print(f" Unknown phase. One of {PHASES}, or q")
continue
marks.append((phase, time.time()))
with log.open("a", encoding="utf-8") as f:
f.write(f"- {fmt(marks[-1][1] - start)} elapsed — {phase}\n")
print(f" recorded: {phase} ({fmt(marks[-1][1] - start)} elapsed)")
total = time.time() - start
print(f"\n=== {name} summary ===")
prev = start
for phase, t in marks:
print(f" {phase:<9} +{fmt(t - prev):<10} (total {fmt(t - start)})")
prev = t
print(f" total {fmt(total)}")
if __name__ == "__main__":
main()
How to read it: At each phase transition you type a single word like recon or foothold. Every input appends the elapsed time to a markdown log file, and q ends it with a per-phase and cumulative summary. A mistyped phase name shows the list again and gets ignored — a device that keeps typos from polluting your record amid the heat of the round.
3-2. Timer Measurement — A Short Demo
This is an actual run (measured, 2026-09-09 — the demo pipes the phases in consecutively, so the times read 0 seconds; in a real round, tens of minutes of work go between inputs):
Input (measured):
printf 'recon\nenum\nfoothold\nuser\nbogus\nprivesc\nroot\nq\n' | python htb_timer.py demo-machine
Output (measured):
[demo-machine] Timer started. Enter a phase: recon / enum / foothold / user / privesc / root (q=quit)
phase> recorded: recon (0m 00s elapsed)
phase> recorded: enum (0m 00s elapsed)
phase> recorded: foothold (0m 00s elapsed)
phase> recorded: user (0m 00s elapsed)
phase> Unknown phase. One of ['recon', 'enum', 'foothold', 'user', 'privesc', 'root'], or q
phase> recorded: privesc (0m 00s elapsed)
phase> recorded: root (0m 00s elapsed)
=== demo-machine summary ===
recon +0m 00s (total 0m 00s)
enum +0m 00s (total 0m 00s)
foothold +0m 00s (total 0m 00s)
user +0m 00s (total 0m 00s)
privesc +0m 00s (total 0m 00s)
root +0m 00s (total 0m 00s)
total 0m 00s
How to read it: Notice that the typo bogus produced only a warning and was not recorded. The +per-phase column in the summary is the raw material for the 2-4 analysis frame. A log file (htb_timer_demo-machine.md) is created too — put it in your machine-log folder and it merges with Step 256’s log system.
3-3. Starting the Round — Setting Alarms and Kicking Off
Spawn the machine, start the timer, and set three phone alarms (Screen example):
cd ~/htb/machinename
export TARGET=10.129.10.10
python ~/tools/htb_timer.py machinename &
# Phone alarms: 1:00 (recon should end) / 4:00 (exploitation target) / 6:00 (hard stop)
How to read it: The alarm is not a "time’s up" device — it’s a device that asks "where should you be right now?" If you’ve already typed foothold when the 1-hour alarm rings, the round is cruising; if you’re still in enum, it’s a signal to adjust the allocation table.
3-4. Running the Round — Recording Phase Transitions
As the round progresses, type one word at each transition point (Screen example):
phase> recorded: recon (42m 10s elapsed) ← full scan + paths + hypotheses done
phase> recorded: enum (1h 05m elapsed) ← deep enumeration done
phase> recorded: foothold (2h 40m elapsed) ← first shell
phase> recorded: user (2h 48m elapsed)
phase> recorded: privesc (3h 55m elapsed) ← escalation path confirmed
phase> recorded: root (4h 12m elapsed)
How to read it: This round missed the 4-hour goal by 12 minutes, and the overflow sits in the 2h 40m to foothold — the exploitation phase. Escalation took 1h 24m, within allocation. This single scene is the answer to "where did the time go?" With only the number "4h 12m total," you would never have known.
3-5. Retrospective — The Time Map of 6 Cumulative Machines
When both machines are done, expand Step 257’s table with time (example):
## Time retrospective (cumulative 6)
| Machine | Recon | Exploit (→user) | Escalate (→root) | Total | 4h goal |
|------|------|------|------|------|------|
| Easy #1 | 1h 10m | 2h 10m | 0h 35m | 3h 55m | met |
| Easy #2 | 0h 50m | 1h 15m | 1h 10m | 3h 15m | met |
| Easy #3 | 0h 55m | 0h 55m | 1h 00m | 2h 50m | met |
| Easy #4 | 0h 45m | 0h 55m | 0h 40m | 2h 20m | met |
| Easy #5 | 0h 50m | 3h 20m | 1h 10m | 5h 20m | over |
| Easy #6 | 0h 42m | 2h 00m | 1h 30m | 4h 12m | close |
## Analysis
① Overflow phase: both #5 and #6 overflowed in exploitation — recon and escalation are already stable
② What ate the time: #5 repeated a dead hypothesis twice (30-minute rule slip); #6 was new-service research
③ Nature: #5 is a procedure slip; #6 is a knowledge gap (playbook hole)
④ One thing for the next round: separate the 30-minute alarm into a physical timer
How to read it: The table’s shape is the conclusion — the recon column converging stably means the routine is fixed, and the wide variance in the exploitation column means that’s where skill still varies.
4. Missions & Exercises
Mission — Two 6-Hour-Box Machines and a Time Retrospective
- Select 2 new Easy machines (prioritize the empty types from your Step 257 table — ⑤⑥ if they remain)
- Start htb_timer.py at the beginning of each round and set the three phone alarms (1:00/4:00/6:00)
- Enter every phase transition into the timer; goal is a 4-hour finish, hard stop is 6 hours
- Apply the 30-minute rule in its timed version (2-3) — if you slipped, leave that timestamp in the log
- For a machine not finished in time, complete it in a separate session after the timebox, but fill in the four overtime-analysis boxes (2-4) without fail
- Complete the cumulative-6 time retrospective table (3-5) and its four lines of analysis
Exercises
Q1. Explain what the principle "recon goes wider if anything; the saving happens in verification" means, and write why trying to shrink recon is the worst saving.
Q2. Explain the difference between recording only total time and recording per-phase time, connecting it to the overtime analysis frame in 2-4.
Q3. Write how the prescriptions differ between an overtime cause of "knowledge gap" and one of "procedure slip."
Q4. Unpack the sentence "procedure doesn’t consume time; it prevents waste" to explain why time-limit training demands more fidelity to procedure (logging, the 30-minute rule).
5. Model Answers & Completion Criteria
Mission Model Answer
An example of the analysis form for an overtime machine:
# Easy #5 — overtime analysis
① Overflow phase: exploitation (3h allocation, +20m over; 5h 20m total)
② What ate the time: 1h 10m on the web login bypass hypothesis — kept going with no new facts at the 30-minute mark
③ Nature: procedure slip (the knowledge was there — re-reading enumeration for 5 minutes revealed the answer)
④ One thing for the next round: separate the 30-minute timer from htb_timer into a physical alarm
⑤ Post-timebox completion: +1h 05m, root at 6h 25m total — completion record kept
How to verify: ① Are the two machines’ timer log files (htb_timer_machinename.md) in the machine folders? ② Do the three alarms’ settings cross-check against the actual phase timestamps in the log? ③ Does the overtime machine have the four-box analysis — phase, cause, nature, one thing — not "let’s do better next time"? ④ Does the cumulative-6 table show readable trends for recon/exploitation/escalation? ⑤ Does even an unfinished-in-time machine have a completion record (a timebox is a measuring device, not a quitting device)?
Exercise Answers
A1. Recon is the phase that produces the input data for every later phase, so a port or path missed here becomes "an option that doesn’t exist" later — skip the full scan to save 30 minutes, and it comes back doubled as two hours wandering after a service that isn’t there. Verification-phase waste, on the other hand, is "time spent clinging to dead hypotheses," and that can be reduced procedurally, as with the 30-minute rule. Savings should come from the efficiency of data consumption (verification), not data production (recon).
A2. Total time only tells you the result — "it overflowed" — while per-phase time tells you "in which phase." The first box of the 2-4 frame (① which phase overflowed) can’t be filled without per-phase records, and only then is the investigation scope of the second box (② what ate the time) determined. The number "5h 20m total" points at nothing to improve, but the decomposition "exploitation 3h 20m, of which 1h 10m on one hypothesis" leads to a prescription.
A3. The prescription for a knowledge gap is filling — add a playbook entry and practice that technique separately in docs and labs (e.g., how to enumerate an unfamiliar service). The prescription for a procedure slip is an enforcement device — separating alarms, moving the checklist’s position, things that "make the slip physically hard next round." Treating a knowledge problem procedurally (try harder) makes it recur; treating a procedure problem with knowledge (study more) changes nothing — that’s why box ③ exists in the analysis.
A4. Logging and the 30-minute rule cost a few seconds and 5 minutes respectively, and prevent "another 30 minutes re-knocking the same path" and "time re-researching facts already confirmed." The tighter the time, the more a human falls into the traps of repetition and forgetting — and procedure is insurance against exactly those traps. In fact, in the 3-5 example, #5’s overflow happened not during procedure-following time but during the 1h 10m of slipping — the honest conclusion the time records show is that the minutes saved by skipping procedure are few, while the time lost to procedure slips is an hour or more.
Completion Criteria Checklist
- [ ] Built htb_timer.py and confirmed it works locally
- [ ] Ran both machines with timer logs and the 3 alarms (1:00/4:00/6:00)
- [ ] Phase-transition timestamps remain in the log files
- [ ] 30-minute rule triggers/slips were recorded
- [ ] Filled the four-box analysis for overtime machines
- [ ] Completed unfinished-in-time machines in separate sessions
- [ ] Completed the cumulative-6 time retrospective table
- [ ] Wrote down the next single improvement read from the table
6. Common Pitfalls & Fixes
Wall 1. Skipped the full scan to save time and lost double
Symptom: You dropped -p- and ran only a quick scan, then wandered for two hours before discovering a service on a non-standard port.
Cause: The worst possible saving — recon is not a cost; it’s an investment.
Fix: Even inside the timebox, nmap -sV -p- stays non-negotiable. If time worries you, run the scan in the background (nmap ... &) and start investigating from the basic scan results — the dual structure of re-reading when the full scan completes is the compromise between saving and completeness.
Wall 2. The alarm rings but I start ignoring it
Symptom: The 1-hour alarm rang, you said "just this one thing," turned it off, and 6 hours flowed by.
Cause: You’ve begun perceiving the alarm as an interruption — the round’s immersion beat the clock.
Fix: Change the alarm’s meaning — not "stop" but "answer which phase you should be in right now." When the alarm rings, look at the timer log and write your current state in one sentence ("1:00 — enum in progress, recon over budget"). This 10-second ritual revives the allocation table.
Wall 3. Forgot to enter phases and the log is a smear
Symptom: The round ended and only recon is stamped.
Cause: In combat, record-keeping collapses first — it’s normal.
Fix: Put triggers outside yourself — bind inputs to "moments your hand moves": always type user right before cat user.txt, type foothold when you do the TTY upgrade. If entries are still missed, reconstruct estimates afterward from the machine log’s timestamps (Step 256’s attempt records) — an approximate record beats none, and writing the omission itself in the log makes it the next round’s assignment.
Wall 4. The 4-hour mark approaches and haste breeds mistakes
Symptom: Command typos multiply near the end, and you run an exploit without checking and kill a service.
Cause: The stretch where clock pressure shaves judgment — this is the main event of this training.
Fix: Pre-decide the rules for the last hour — "no new attacks; only wrap up and document the paths in progress." The same thing happens in the exam room. And always log mistakes made in haste — "4h 50m, downed a service (unverified exploit)" is rehearsal material for the next round. Speed training is half technique and half this mental management.
Wall 5. Past 6 hours and I want to give up finishing
Symptom: The timebox ended, and so did your motivation.
Cause: You misunderstood the timebox as a "declaration of failure."
Fix: A timebox is the end of measurement, not the end of the round. Write the four-box analysis, step away, and finish in a separate session — going all the way without a time limit is also data (the conclusion of where you were stuck). However, if you looked at a write-up during completion, that round is no longer an independent solve, so change its label and put it on the re-solve list (Step 256’s rules hold under time limits too).
7. Summary
Today’s Concepts
| Concept | One-line description |
|---|---|
| Timebox | A hard time cap over a whole round — 6-hour hard stop |
| Per-phase time allocation | Recon 1h / exploitation 3h / escalation 2h — a warning baseline |
| 4-hour finish | The convergence goal — recon 45m / exploitation 2h / escalation 1h 15m |
| Pace | The speed of moving between phases — what the alarms check |
| Overtime analysis four boxes | Phase → cause → nature (knowledge/procedure) → next one thing |
| Time retrospective table | Per-phase times across cumulative machines — a map of skill |
Today’s Commands & Tools
| Command | What it does |
|---|---|
python htb_timer.py machine-name |
Start per-phase time recording |
Type recon/enum/foothold/user/privesc/root |
Record phase transitions |
q |
Quit and print the summary |
| (external) Phone alarms 1:00/4:00/6:00 | Allocation warnings and the hard stop |
| (procedure) Write one state sentence when an alarm rings | The 10 seconds that keep the clock alive |
The Instinct That Matters More Than Commands
Time-limit training does not teach "how to type fast." Six rounds of records say the opposite — the fast person is not the one who skips recon, but the one who discards dead hypotheses quickly. And the one who keeps procedure under clock pressure. Unroll the cumulative-6 table. If the recon column’s times are converging, the playbook’s entries are growing, and the causes of being stuck have shifted from "didn’t know" to "hurried," that is your graduation evidence for this stretch. The clock was never measuring you — it was a mirror showing your growth.
Once every box is checked, Step 258 is complete. Click the checkbox in the sidebar to save your progress.