Pentest Methodology & Recon · intermediate · ~12 min

Service enumeration and the toolset

**What you will learn** - Enumerate the most common network services (HTTP, SMB, FTP, SSH, DNS, SNMP, NFS, databases) for the details that turn an open port into an understood service. - Choose the right tool for each service and know how *noisy* (loggable, active) each choice is. - Run enumeration inside authorization and scope: rate-limited, wordlist-controlled, and documented. - Read enumeration from the **defender's** side — what these probes look like in server and IDS logs, and how to detect and slow them down. - Verify a hardening change actually reduced what an enumerator can see (mitigation verification), not just assume it did. - Write an evidence trail (target, command, timestamp, result) you can drop straight into a report.

Overview

Security objective. The asset under discussion is a set of network services — the SMB share, the web app, the FTP server, the DNS server. The threat is an attacker who has already found open ports and now interrogates each service to find a foothold: a readable share, an anonymous login, a hidden admin directory, a leaky DNS zone. As the learner, you will practice enumeration the way an authorized tester does, and — just as important — learn to detect and blunt it as a defender: what to log, what abuse looks like, and how to confirm a fix.

Scanning (your prereq, Port, service, and OS scanning) answered what is listening? It produced a bare list: 22/tcp open, 445/tcp open, 80/tcp open. That list is nearly useless on its own. Enumeration is the next step: it answers what exactly is this, and what can I reach through it? An open SMB port is a shrug; an SMB port with a world-readable Backups share is a finding.

The field mantra is "enumerate, then enumerate again." Each service speaks its own protocol and hides its detail in a different place, so each needs its own probes and its own tool. This lesson connects directly to your scanning prereq — scanning hands you the port list; enumeration is what you do with it — and it feeds the next phases (vulnerability analysis and, in a lab, exploitation). Everything here is framed for systems you own or are explicitly authorized to test: localhost, containers, and intentionally-vulnerable lab VMs.

Why it matters

In authorized professional work — a scoped penetration test, a red-team engagement, an internal security assessment — footholds almost never come from the port list. They come from enumeration detail. A client rarely cares that port 445 is open; they care that an unauthenticated user can read \\server\HR-Payroll. Enumeration is where you find that.

The skill has two halves, and both are billable value:

Habit Why it matters professionally
Right tool per service Efficient, repeatable, and defensible in a report. You are not guessing.
Awareness of noise Directory and vhost brute-forcing is active and logged. Knowing this keeps you in scope, keeps rate limits sane, and lets you warn the client's SOC before you run it.

The defensive payoff is just as real. The same knowledge that lets you enumerate a service tells a blue-teamer exactly what enumeration looks like in their logs — the burst of 404s, the SMB null-session, the AXFR request — so they can detect it, rate-limit it, and shrink the attack surface. On a professional engagement you are expected to hand back both: the findings and the detection guidance.

Core concepts

1. Enumeration vs. scanning

Definition. Scanning discovers which ports/services exist. Enumeration extracts actionable detail from each one: versions, shares, users, directories, records, credentials-in-the-open.

How it works. You take each open port and speak its protocol — HTTP to the web server, SMB to the file server, DNS to the resolver — asking questions the service is willing (or misconfigured) to answer.

When / when not. Enumerate every in-scope service; do not enumerate hosts or services outside your authorization, and do not brute-force against production without telling the owner and setting rate limits.

Pitfall. Stopping at the port list. "445 open" is not a finding. "445 open, Backups share readable by anonymous" is.

2. Per-service enumeration (each service is its own puzzle)

Service (port) What you enumerate Insecure assumption it exploits
HTTP/S (80/443) Directories, files, virtual hosts, tech stack, endpoints "Nobody will guess /admin or /backup.zip"
SMB (445) Shares, users, password policy "Internal network is trusted"
FTP (21) Anonymous login, readable/writable files "Anonymous FTP is harmless"
SSH (22) Version, allowed auth methods "An old banner doesn't matter"
DNS (53) Zone transfer (AXFR), record sweeps "Anyone can copy our whole zone"
SNMP (161/udp) Community strings, device/system inventory "public is fine as a community string"
NFS (2049) Exported shares you can mount "Export to everyone is convenient"
Databases (3306/5432/1433) Reachability, default creds, version "The DB is behind a firewall so it's safe"

Definitions of the less-obvious ones. A zone transfer (AXFR) asks a DNS server for its entire list of records at once — meant for server-to-server replication, dangerous when open to anyone. A community string is SNMP's simple shared password; the factory default public grants read access to a device's inventory. A null session is an SMB connection with an empty username and password.

Pitfall. Using one tool (say, Nmap) for everything. Nmap scripts help, but SMB shares are clearer with smbclient, DNS with dig, HTTP paths with ffuf. Match the tool to the protocol.

3. Active vs. passive — brute-forcing is loud

Definition. Directory and vhost discovery sends thousands of guesses. It is active: every request hits the server and lands in its access log.

How it works. A wordlist drives requests like GET /admin, GET /backup, GET /.git/; you keep the ones that don't return 404. That is a flood of requests from one source in a short window — a textbook detectable signature.

When / when not. In scope, rate-limited, and (on client systems) pre-announced to the SOC. Never as a "quick check" against something you don't have written permission to test.

Pitfall. Treating brute-forcing as passive recon. It is not. It is noisy, it is logged, and off-scope it can be a crime.

4. Tool fit and tool noise

Definition. Every tool has a job and a noise level. Picking well makes you efficient and keeps you inside scope.

Tool Job Noise
Nmap (+ NSE) Port/service/OS scan, scripted checks Medium — tunable with timing flags
Masscan Very fast port sweeps High — can saturate a network
Netcat Manual connect, banner grab Low — one connection
Gobuster / ffuf Directory / file / vhost brute force High — thousands of requests
WhatWeb / Wappalyzer Web tech fingerprint Low–medium
dig / nslookup DNS queries, AXFR attempt Low per query
curl Craft raw HTTP requests Low — you control each request

Masscan caution. Masscan can send packets faster than a small network can absorb, effectively a self-inflicted denial of service. Use it only where you are explicitly authorized, and set --rate conservatively.

Pitfall. Reaching for the fastest/loudest tool by reflex. Speed you don't need is just noise that gets you noticed — or gets you out of scope.

Threat model (text diagram)

            AUTHORIZED LAB (localhost / container / vulnerable VM)
  +-------------------------------------------------------------------+
  |                                                                   |
  |   Tester box            === trust boundary (network) ===          |
  |  (you, in scope) --------------------+                            |
  |     |  enumeration probes            |   ENTRY POINTS / ASSETS    |
  |     |  (HTTP dir brute, SMB null,    v                            |
  |     |   AXFR, SNMP public, curl)  +-----------------------------+  |
  |     |                             | 80/443  Web app + hidden    |  |
  |     |                             |         dirs (asset)        |  |
  |     |                             | 445     SMB shares (asset)  |  |
  |     |                             | 53      DNS zone (asset)    |  |
  |     |                             | 161u    SNMP inventory      |  |
  |     |                             | 3306    Database (asset)    |  |
  |     |                             +-----------------------------+  |
  |     |                                     |                       |
  |     |                                     v                       |
  |     |                            +------------------+             |
  |     +--------------------------->|  Server LOGS /   |  <-- defender|
  |         every probe recorded     |  IDS / SIEM      |      detects |
  |                                  +------------------+             |
  +-------------------------------------------------------------------+
     Off this lab boundary = NOT authorized. Do not probe real hosts.

Knowledge check.

  1. What asset is protected when you close an anonymous SMB share — the port, or the files the share exposes? (The files/data. The port being open is not the vulnerability; the readable data is.)
  2. Where is the trust boundary in a DNS zone-transfer finding? (At the DNS server: it should replicate its full zone only to authorized secondary servers, not to any client that asks.)
  3. What insecure assumption makes SNMP public dangerous? ("A default community string is harmless" — it grants anyone who can reach 161/udp read access to device inventory.)
  4. Which logs detect directory brute-forcing? (Web server access logs — a burst of 404s from one source — and a WAF/IDS.)
  5. Why run all of this only in an authorized lab? (Enumeration is active and logged; against systems you don't own or aren't authorized to test, it is unauthorized access and can be illegal.)

Syntax notes

The shape of an enumeration command is: tool + target + what-to-ask-for + safety flags. Below are lab-safe skeletons. TARGET is a host you own — use 127.0.0.1, a container name, or a lab VM you set up; never a third party.

# HTTP directory discovery with an explicit, controlled rate.
# -w wordlist  -u URL with FUZZ marker  -mc match codes  -rate cap  -t threads
ffuf -w /usr/share/wordlists/dirb/common.txt \
     -u http://TARGET/FUZZ \
     -mc 200,204,301,302,401,403 \
     -rate 50 -t 20

# SMB: list shares. -N = no password (tests for anonymous/null access).
smbclient -L //TARGET -N

# DNS: attempt a zone transfer (AXFR). Succeeds only if the server is misconfigured.
dig AXFR lab.example @TARGET

# HTTP banner / headers only, no body — quiet, precise.
curl -sS -I http://TARGET/

# Manual banner grab with netcat (one connection).
nc -vn TARGET 22

Key safety knobs to notice: -rate / --rate cap requests per second; -mc filters to interesting responses so you send fewer follow-ups; -N and AXFR are tests — a successful result is itself the finding. Always point these at a lab target, and log the exact command + timestamp you ran.

Lesson

Scanning finds services. Enumeration interrogates each one for the detail that leads to a foothold.

The mantra is simple: "enumerate, then enumerate again."

Per-service enumeration

  • HTTP/S — directory and file discovery (gobuster, ffuf), virtual-host discovery, and parameter/endpoint mapping.
  • SMB (445) — shares, users, and policies. A classic internal goldmine.
  • FTP (21) — anonymous login, plus readable or writable files.
  • SSH (22) — version and supported authentication methods.
  • DNS (53) — zone-transfer attempts and record sweeps. A zone transfer asks a DNS server for its full list of records at once.
  • SNMP (161/udp) — community strings that expose device and system inventory. A community string is a simple shared password used by SNMP.
  • NFS (2049) — exported shares you may be able to mount.
  • Databases (3306/5432/1433) — reachable instances, default credentials, and version.

The toolset

Tool Job
Nmap Port, service, and OS scanning; NSE scripts
Masscan Very fast port sweeps — lab or authorized use only; can overwhelm networks
Netcat Manual connect, banner grab, quick checks
Gobuster / ffuf Directory, file, and vhost brute forcing
WhatWeb / Wappalyzer Web technology fingerprinting
dig / nslookup DNS queries
curl Crafting raw HTTP requests

Discipline

Enumeration brute force (directories, vhosts) is active and noisy. Keep it in scope and rate-limited.

Masscan needs extra care. It can saturate a network, so use it only where you are authorized.

Code examples

The example below walks the insecure -> secure -> verify shape for the most common enumeration finding: an HTTP server that leaks a sensitive file and a hidden admin path. Everything runs against a local lab you control.

1) WARNING: intentionally vulnerable — use only in a local, isolated, authorized lab. Do not deploy.

A throwaway lab web root that exposes exactly what enumeration hunts for:

# Build an intentionally-vulnerable lab web root (localhost only).
mkdir -p /tmp/lab-web/admin
cd /tmp/lab-web

echo 'DB_PASSWORD=<development-placeholder>' > backup.env      # secret-looking file left in web root
echo '<h1>Admin panel</h1>'                > admin/index.html   # hidden but unauthenticated
echo '<h1>Welcome</h1>'                     > index.html

# Serve on loopback ONLY (127.0.0.1), so nothing leaves this machine.
python3 -m http.server 8000 --bind 127.0.0.1

An authorized enumerator finds the leaks:

# Directory/file discovery, rate-limited, matching interesting codes only.
ffuf -w /usr/share/wordlists/dirb/common.txt \
     -u http://127.0.0.1:8000/FUZZ \
     -mc 200,301,403 -rate 50 -t 10
# -> finds  admin  (301)  and  backup.env  (200)

curl -sS http://127.0.0.1:8000/backup.env
# -> DB_PASSWORD=<development-placeholder>     <-- secret exposed: this is the finding

Why it's vulnerable: the assumption "nobody will guess these paths" is false — a wordlist guesses them in seconds — and there is no authentication on /admin and no rule preventing .env-style files from being served.

2) SECURE fix

Don't rely on secrecy of the path. Remove the secret from the web root, require auth on admin, and block sensitive file types. Here is the same idea expressed as an Nginx config (concept-track, real directives):

server {
    listen 127.0.0.1:8080;
    root /tmp/lab-web-secure;

    # 1) Never serve dotfiles or secret-bearing extensions.
    location ~ /\.(?!well-known) { deny all; }
    location ~* \.(env|bak|old|sql|key|pem)$ { deny all; }

    # 2) Require authentication for the admin area.
    location /admin/ {
        auth_basic "restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;   # created with htpasswd
    }

    # 3) Log everything so enumeration is detectable (see Security & safety).
    access_log /var/log/nginx/lab_access.log;
}

And the operational fix that matters most: move the secret out of the web root entirely (into an environment variable or a secrets store), so no misconfiguration can serve it.

3) VERIFY the fix rejects bad input and accepts good input

# BAD input must now be REJECTED:
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/backup.env
# expected: 403   (blocked by the file-extension rule)

curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/admin/
# expected: 401   (auth now required)

# GOOD input must still be ACCEPTED:
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/
# expected: 200   (normal page still served)

# GOOD input WITH credentials reaches admin:
curl -sS -o /dev/null -w '%{http_code}\n' -u admin:'<lab-password>' http://127.0.0.1:8080/admin/
# expected: 200

Expected output, read together: before the fix, backup.env returned 200 and printed the secret, and /admin/ returned 200 with no login. After the fix, backup.env -> 403, /admin/ -> 401, the home page still 200, and admin-with-credentials 200. That contrast is the mitigation verification: the fix rejects the two bad requests and still accepts the two legitimate ones.

Line by line

Walkthrough of the insecure -> secure -> verify example.

Setup (insecure lab).

  • mkdir -p /tmp/lab-web/admin and the echo lines create three files: a normal index.html, a hidden admin/index.html with no auth, and backup.env containing a placeholder secret. This reproduces two classic leaks: a guessable admin path and a sensitive file left in the web root.
  • python3 -m http.server 8000 --bind 127.0.0.1 serves them. --bind 127.0.0.1 is the safety control: the server is reachable only from this machine, so your lab never touches the outside network.

Enumeration (the attack you are learning to detect).

  • ffuf ... -u http://127.0.0.1:8000/FUZZ replaces FUZZ with each wordlist entry. -mc 200,301,403 keeps only interesting responses; -rate 50 -t 10 caps the flood. It reports admin (a 301 redirect to the directory) and backup.env (200).
  • curl -sS .../backup.env fetches the file and prints DB_PASSWORD=<development-placeholder>. The secret is exposed — that printed line is the finding you would document.

Secure config.

  • location ~ /\.(?!well-known) denies dotfiles (like .env, .git) except .well-known. location ~* \.(env|bak|old|sql|key|pem)$ { deny all; } blocks secret-bearing extensions regardless of path.
  • location /admin/ { auth_basic ...; } forces HTTP auth on the admin area; unauthenticated requests get 401.
  • access_log ensures every probe is recorded — the detection half of the fix.
  • The unwritten but critical step: the real secret is removed from the web root, so even a future misconfig can't serve it.

Verification trace.

Request Before fix After fix Meaning
GET /backup.env 200 + secret 403 Bad input rejected
GET /admin/ 200, no auth 401 Bad input rejected
GET / 200 200 Good input still accepted
GET /admin/ with creds (n/a) 200 Authorized access works

Reading the two right-hand columns together proves the mitigation: the two attacker requests now fail closed while the two legitimate requests still succeed. A fix you cannot demonstrate this way is a fix you cannot claim in a report.

Common mistakes

1. Stopping at the port list.

  • WRONG: report "445/tcp open" as a finding.
  • WHY WRONG: an open port is not a vulnerability; it's an invitation to enumerate. The client can't act on it.
  • CORRECTED: enumerate the share — smbclient -L //TARGET -N — and report the readable share and its contents.
  • RECOGNISE/PREVENT: if your finding has no impact sentence ("an anonymous user can read X"), you stopped too early.

2. Brute-forcing at full speed on a client's production system.

  • WRONG: run ffuf with default threads and no rate cap against a live app.
  • WHY WRONG: thousands of requests/second can degrade the service and floods the SOC with alerts — outside the spirit of a scoped test.
  • CORRECTED: set -rate, use a sensible wordlist, and notify the SOC of your source IP and window.
  • RECOGNISE/PREVENT: agree rate limits and a de-confliction contact before testing.

3. Using one tool for every protocol.

  • WRONG: try to read SMB shares or do DNS zone transfers with only a web scanner.
  • WHY WRONG: the tool doesn't speak the protocol; you miss findings and misread results.
  • CORRECTED: smbclient/enum4linux for SMB, dig AXFR for DNS, ffuf for HTTP paths.
  • RECOGNISE/PREVENT: keep a per-service checklist so you always reach for the protocol-native tool.

4. Treating a scanner's silence as proof of security.

  • WRONG: "ffuf found nothing, so the app is secure."
  • WHY WRONG: a scan only covers your wordlist and codes; absence of a hit is not absence of a vuln. Passing an automated scan does not prove a system is secure, and nothing is ever "completely secure."
  • CORRECTED: state exactly what you tested (wordlist, codes, rate) and its limits; combine with manual review.
  • RECOGNISE/PREVENT: never write "no vulnerabilities"; write "no issues found with these specific checks."

5. Running Masscan without care.

  • WRONG: point Masscan at a network at its default blazing rate.
  • WHY WRONG: it can saturate links and cause an outage — a self-inflicted DoS.
  • CORRECTED: cap --rate, confirm authorization, and prefer Nmap unless you truly need the speed.
  • RECOGNISE/PREVENT: if you can't state why you need Masscan's speed, you don't need it.

Debugging tips

ffuf/gobuster returns everything (every path looks like a hit).

  • Likely the server returns 200/301 for unknown paths (a catch-all or SPA). Add -mc to match real codes and -fs/-fc to filter the default response size/code. Confirm with curl -I http://TARGET/definitely-not-real to see the baseline.

dig AXFR ... @TARGET returns "Transfer failed."

  • That usually means the server correctly refuses zone transfers — often a good sign, not a bug in your command. Verify reachability first with dig SOA lab.example @TARGET. If SOA works but AXFR is refused, the finding is "AXFR properly restricted."

smbclient -L //TARGET -N gives NT_STATUS_ACCESS_DENIED.

  • Null/anonymous session is blocked (good for the defender). Note it as such. Don't escalate to credential guessing unless that is in scope and authorized.

curl hangs.

  • Wrong port, filtered by a firewall, or the service speaks a non-HTTP protocol. Add -v for the handshake, set --max-time 5, and reconfirm the port from your scan results.

Nothing responds at all.

  • Ask: Is the lab service actually running (ss -tlnp / netstat)? Am I hitting 127.0.0.1 vs the container's IP? Is a host firewall dropping packets? Did I bind the service to loopback only?

Questions to ask when enumeration "fails":

  1. Is the target in scope and running right now?
  2. Am I using the protocol-native tool for this service?
  3. What is the baseline (a known-bad request) so I can tell a real hit from noise?
  4. Is a defense (WAF, auth, rate limit) causing the failure — and is that itself the finding?

Memory safety

Security & safety — detection and logging.

Enumeration is active and loud; the defender's job is to see it and slow it down. When you build or assess these services, log with intent.

What to log for each enumeration-relevant event:

  • Timestamp (with timezone).
  • Source IP and, if available, source port / user-agent.
  • Resource requested (URL path, share name, DNS query type, SNMP OID range).
  • Result / status (HTTP code, ACCESS_DENIED, AXFR refused, auth success/failure).
  • The security decision made (allowed / blocked / rate-limited).
  • A correlation ID so one enumeration session can be reconstructed across services.

What to NEVER log: passwords, session cookies or tokens, API keys, private keys, full credentials submitted in a request body, full payment card numbers (PANs), or unneeded PII. If you must reference a secret, log that it was present, not its value.

Events that signal abuse (enumeration in progress):

  • A burst of 404s (and occasional 403/401) from one source in a short window -> directory/vhost brute force.
  • SMB null/anonymous session attempts, or many share-listing requests.
  • A DNS AXFR request from a client that is not a configured secondary.
  • SNMP GETs using default community strings like public.
  • Many failed logins across services from one source -> credential probing.

How false positives arise: a legitimate uptime monitor or crawler can look like light brute force; a misconfigured internal replica may issue AXFR; a vulnerability scanner run by your own team will trip every one of these. That is why detections should correlate with known-good sources and scheduled scan windows before alerting a human — and why testers de-conflict with the SOC in advance.

Defensive controls that reduce what enumeration yields: authentication on sensitive paths, denying dotfiles/secret extensions, restricting AXFR to named secondaries, changing/removing default SNMP community strings, disabling anonymous FTP and SMB null sessions, least-privilege share permissions, and per-source rate limiting. Each control should be paired with a verification step (as in the code section) proving it now rejects the bad request while still allowing legitimate use.

Real-world uses

Concrete authorized use case. During a scoped internal penetration test, a tester enumerates a file server: smbclient -L reveals a Finance share readable by anonymous users, and ffuf against the intranet portal uncovers /backups/ serving a database dump. Both become report findings with impact, evidence (command + timestamp + output), and remediation (fix share ACLs, remove the dump, block the path, add auth). The blue team uses the same detail to write detections for the next real attacker.

Professional best-practice habits.

  • Validation & scope: test only in-scope hosts you're authorized for; keep an authorization letter and target list at hand.
  • Least privilege: enumerate with the minimum access needed; don't hoard credentials or pivot beyond scope.
  • Secure defaults: on the defense side, ship services with auth on, defaults removed, and dangerous features (AXFR to all, SNMP public, anonymous FTP/SMB) off.
  • Logging: record every command you run and its result; ensure the target logs every probe (for detection).
  • Error handling: treat "access denied" / "transfer refused" as data — often evidence of a working control — not as a dead end to force past.
Level What it looks like
Beginner Enumerate one service at a time against a local lab, rate-limited, and record command + result. Recognise when a refusal is actually a good control.
Advanced Chain enumeration across services with a correlation ID, tune wordlists to the target, de-conflict with the SOC, and deliver both findings and detection guidance.

Practice tasks

All tasks are lab-only: run against 127.0.0.1, a container, or an intentionally-vulnerable VM you own. Before starting, tick the authorization checklist. After each, do the DEFENSIVE conclusion: remediate and verify.

Authorization checklist (do this first, every time):

  • I own this system or have explicit written authorization to test it.
  • The target is a lab (localhost / container / vulnerable VM / CTF), not a third party.
  • I know my rate limits and will log each command + timestamp.
  • I have a cleanup/reset plan.

Beginner 1 — Rate-limited directory discovery.

  • Objective: find hidden paths on the lab web server from the code section.
  • Requirements: run ffuf with -mc and -rate 50; capture which paths return non-404.
  • Input/output: input = wordlist + http://127.0.0.1:8000/FUZZ; output = list of hits with status codes.
  • Constraints: loopback target only; cap the rate.
  • Hints: establish a baseline with curl -I on a bogus path first.
  • Concepts: active brute force, -mc filtering, tool noise.
  • Defensive conclusion: block one exposed file via config, then re-run and confirm it now returns 403.

Beginner 2 — Banner and header enumeration.

  • Objective: fingerprint a service without brute force.
  • Requirements: use curl -I on the web port and nc -vn on the SSH port; note versions/headers.
  • Input/output: output = server header and SSH banner strings.
  • Constraints: one connection each; no automated flooding.
  • Hints: compare what a passive banner reveals vs. an active brute force.
  • Concepts: low-noise enumeration, banner grabbing.
  • Defensive conclusion: suppress or genericise one version banner, then re-grab to confirm the change.

Intermediate 1 — SMB share enumeration and lock-down.

  • Objective: determine whether a lab SMB server allows anonymous share listing.
  • Requirements: run smbclient -L //127.0.0.1 -N; record the result (shares listed vs. access denied).
  • Input/output: output = share list or NT_STATUS_ACCESS_DENIED.
  • Constraints: do not attempt credential guessing.
  • Hints: a refusal is itself a finding — note whether null sessions are allowed.
  • Concepts: null session, least-privilege shares.
  • Defensive conclusion: disable anonymous/null access (or tighten a share ACL), then re-run and confirm listing is now denied while an authorized user still works.

Intermediate 2 — DNS zone-transfer test.

  • Objective: check whether a lab DNS server leaks its full zone.
  • Requirements: confirm reachability with dig SOA lab.example @127.0.0.1, then attempt dig AXFR lab.example @127.0.0.1.
  • Input/output: output = full record dump (vulnerable) or "Transfer failed" (restricted).
  • Constraints: lab zone only.
  • Hints: SOA succeeding but AXFR failing means the control works.
  • Concepts: AXFR, trust boundary between primary and secondaries.
  • Defensive conclusion: if AXFR succeeds, restrict transfers to a named secondary, then re-test to confirm arbitrary clients are refused.

Challenge — Multi-service enumeration report + detections.

  • Objective: enumerate three lab services and produce a mini-report plus detection guidance.
  • Requirements: for HTTP, SMB, and DNS, run the appropriate tool, log command + timestamp + result, and for each finding write: affected component, evidence, impact, and remediation. Then, for each, describe the log signature a defender would use to detect that enumeration.
  • Input/output: output = a short structured report (findings + detections) — no full exploit code.
  • Constraints: lab-only; severity must reflect actual exploitability/impact, not "everything is critical."
  • Hints: reuse the insecure -> secure -> verify shape; a refused probe is a good result worth noting.
  • Concepts: correlation ID, detection/logging, mitigation verification, severity judgement.
  • Defensive conclusion: for each finding, apply the fix and re-run the exact probe to prove it now fails closed while legitimate use still works; write a cleanup/reset step to restore the lab.

Lab cleanup / reset (all tasks):

  • Stop lab servers (Ctrl-C the http.server; stop containers with docker stop/docker rm).
  • Remove lab files: rm -rf /tmp/lab-web /tmp/lab-web-secure.
  • Revert any config changes and delete test log files you created.
  • Confirm nothing is left listening: ss -tlnp.

Summary

Main concepts. Scanning finds which services are open; enumeration extracts the actionable detail that becomes a foothold. Each service (HTTP, SMB, FTP, SSH, DNS, SNMP, NFS, databases) is its own puzzle with its own protocol, its own tool, and its own insecure assumption. Directory/vhost brute-forcing is active and logged — never passive.

Key syntax / commands. ffuf -w LIST -u http://TARGET/FUZZ -mc 200,301,403 -rate 50 (web paths), smbclient -L //TARGET -N (SMB shares), dig AXFR zone @TARGET (zone transfer), curl -sS -I (headers), nc -vn TARGET PORT (banner). Match the tool to the protocol and cap the rate.

Common mistakes. Stopping at the port list; brute-forcing full-speed on production; one tool for every protocol; treating a clean scan as proof of security (it isn't — nothing is "completely secure"); running Masscan carelessly.

What to remember. Enumerate, then enumerate again — but only where you're authorized (localhost / containers / lab VMs). A refused probe is often evidence of a working control. For every issue, deliver the full loop: what/why/impact -> secure fix -> mitigation verification (bad request now rejected, good request still accepted) -> detection & logging (log source, resource, result, decision, correlation id; never log secrets).

Practice with these exercises