Lesson 04 / 15
Exploit and Payload
Breaking the chain from vulnerability to impact into steps: 5 exploits and 4 payloads produce 12 valid chains; chain length ranges from 2 to 7 and totals 53 steps; breaking a single step cuts at most 8 chains; blocking a payload cuts at most 5 chains and blocking an exploit at most 4; the same break leaves 0 completed steps at access and 41 at impact; even when all six middle steps are broken, 1 of 12 chains still stands; and that single chain carries 25.7% of the total probability mass.
Published Updated
In this lesson
- Separates exploit from payload and models the chain from vulnerability to impact as a step sequence
- Computes how many chains breaking each step cuts, and how many steps had already completed when it is cut
- Compares three levers: breaking a step, blocking an exploit, blocking a payload
Contents
The previous lesson counted every item as a single event: probability given, impact given, multiplied. But a 600-fictional-unit impact is not born in a single moment. First something is reached, then a weakness is triggered, then something is executed, privilege expands, and impact is only written once all of these have completed. The number we call probability is actually the probability of this chain completing from start to end.
Exploit is the step sequence that actually uses a vulnerability. Payload is the effect written after the exploit completes. The two are separate things, and that separation sets what this lesson measures: the same exploit can carry more than one payload, and the same payload can arrive with more than one exploit. This lesson builds the chain as a model and ties it to a single question — which step to break cuts how many chains.
A Chain Is a Sequence of Steps
The structure below is a model: there is no working exploit, no tool, no payload here — only a data structure made of step names. The vulnerability names come from the previous two lessons’ list. Trying these steps on a real system without written authorization and a defined scope is both illegal and unprofessional.
SC16: a chain follows the eight-step canonical order, and every chain is a subsequence of that order. SC17: an exploit is the step sequence that uses a vulnerability; a payload is the effect written after the exploit completes, and it brings its own extra steps. SC18: a payload matches an exploit only if the step it requires is present in that exploit. SC19: if a step is broken, every chain that includes it is cut; at the moment it is cut, the chain’s steps before it have already completed.
// security/chain.mjs — the step model of the chain from vulnerability to impact (model): there // is no working exploit here, only a data structure made of step names. No randomness. // SC16: a chain follows the eight-step canonical order; every chain is a subsequence of that order. export const STEP = ["access", "discovery", "triggering", "execution", "privilege-escalation", "lateral-movement", "persistence", "impact"]; export const LETTER = { access: "A", discovery: "D", triggering: "T", execution: "E", "privilege-escalation": "P", "lateral-movement": "M", persistence: "S", impact: "I" }; // SC17: an exploit is the step sequence that uses a vulnerability; a payload is the effect // written after the exploit completes, and it brings its own extra steps. export const EXPLOIT = [ { name: "credential-reuse", vuln: "default-password", step: ["access", "discovery"] }, { name: "input-triggering", vuln: "unvalidated-input", step: ["access", "triggering", "execution"] }, { name: "unsigned-package", vuln: "unsigned-update", step: ["access", "discovery", "triggering", "execution"] }, { name: "account-sharing", vuln: "shared-account", step: ["access", "discovery"] }, { name: "transfer-interception", vuln: "unencrypted-transfer", step: ["access"] }, ]; // SC18: a payload matches an exploit only if the step it requires is present in that exploit. export const PAYLOAD = [ { name: "data-exfiltration", need: [], extra: ["impact"] }, { name: "record-tampering", need: ["discovery"], extra: ["privilege-escalation", "impact"] }, { name: "service-disruption", need: ["execution"], extra: ["impact"] }, { name: "persistent-access", need: ["execution"], extra: ["lateral-movement", "persistence", "impact"] }, ]; export const CHAIN = EXPLOIT.flatMap((e) => PAYLOAD .filter((p) => p.need.every((n) => e.step.includes(n))) .map((p) => ({ exploit: e.name, vuln: e.vuln, payload: p.name, step: STEP.filter((s) => e.step.includes(s) || p.extra.includes(s)) }))); export const mask = (c) => STEP.map((s) => (c.step.includes(s) ? LETTER[s] : ".")).join(""); export const passing = (s) => CHAIN.filter((c) => c.step.includes(s)); // SC19: if a step is broken, every chain that includes it is cut; at the moment it is cut, // that chain's steps before it have already completed. export const priorTotal = (s) => passing(s).reduce((n, c) => n + c.step.indexOf(s), 0); export const closed = (set) => CHAIN.filter((c) => c.step.some((s) => set.includes(s))).length; // SC20: every step has a completion probability and steps are treated as independent (model); // a chain's completion probability is the product of its step probabilities. export const STEP_P = { access: 0.5, discovery: 0.7, triggering: 0.4, execution: 0.6, "privilege-escalation": 0.35, "lateral-movement": 0.5, persistence: 0.6, impact: 0.9 }; export const probability = (c) => c.step.reduce((p, s) => p * STEP_P[s], 1); export const MASS = CHAIN.reduce((s, c) => s + probability(c), 0); export const closedMass = (set) => CHAIN .filter((c) => c.step.some((s) => set.includes(s))) .reduce((s, c) => s + probability(c), 0);
// security/break.mjs — which step to break closes how many chains, how much had already happened. import { STEP, LETTER, EXPLOIT, PAYLOAD, CHAIN, MASS, mask, passing, priorTotal, closed, probability, closedMass } from "./chain.mjs"; const write = (g, ...s) => console.log(s.map((v, i) => (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join("")); const length = CHAIN.map((c) => c.step.length); console.log(`${EXPLOIT.length} exploits x ${PAYLOAD.length} payloads -> ${CHAIN.length} valid chains; ` + `step order ${STEP.map((s) => LETTER[s]).join("")} = ${STEP.join(", ")}; ` + `chain length ${Math.min(...length)}..${Math.max(...length)}, ` + `total steps ${length.reduce((a, x) => a + x, 0)}`); const A = [-26, 20, 10, 7]; console.log("\n1. valid chains"); write(A, "exploit", "payload", "mask", "steps"); for (const c of CHAIN) write(A, c.exploit, c.payload, mask(c), c.step.length); const B = [-24, 11, 10, 8, 12]; console.log("\n2. if a step is broken"); write(B, "step", "in chains", "closed", "left", "steps done"); for (const s of STEP) write(B, s, passing(s).length, closed([s]), CHAIN.length - closed([s]), priorTotal(s)); const C = [-26, 11, 10, 8]; console.log("\n3. if a payload is blocked (exploit stays in place)"); write(C, "payload", "in chains", "closed", "left"); for (const p of PAYLOAD) { const n = CHAIN.filter((c) => c.payload === p.name).length; write(C, p.name, n, n, CHAIN.length - n); } for (const e of EXPLOIT) { const n = CHAIN.filter((c) => c.exploit === e.name).length; write(C, "exploit " + e.name.slice(0, 15), n, n, CHAIN.length - n); } const MID = STEP.slice(1, -1); // access and impact are the legitimate ends, cannot be removed outright const D = [-30, 10, 8]; console.log("\n4. best single and pair of middle steps (access and impact excluded)"); write(D, "broken step set", "closed", "left"); const single = MID.map((s) => [s]).sort((x, y) => closed(y) - closed(x))[0]; const pair = MID.flatMap((s, i) => MID.slice(i + 1).map((t) => [s, t])) .sort((x, y) => closed(y) - closed(x))[0]; for (const set of [single, pair, MID]) write(D, set.map((s) => LETTER[s]).join("+"), closed(set), CHAIN.length - closed(set)); const open = CHAIN.filter((c) => !c.step.some((s) => MID.includes(s))); console.log(`chains still standing once every middle step is broken: ` + open.map((c) => `${c.exploit} + ${c.payload} (${mask(c)})`).join(", ")); const E = [-24, 11, 11, 12, 15]; console.log("\n5. chains closed vs probability mass closed"); write(E, "step", "closed", "chains %", "mass %", "mass/chain"); for (const s of STEP) { const c = (closed([s]) / CHAIN.length) * 100, m = (closedMass([s]) / MASS) * 100; write(E, s, closed([s]), c.toFixed(1), m.toFixed(1), (m / c).toFixed(2)); } const mostLikely = [...CHAIN].sort((x, y) => probability(y) - probability(x)); console.log(`total mass ${MASS.toFixed(4)}; most likely chain ${mostLikely[0].exploit} + ` + `${mostLikely[0].payload} (${probability(mostLikely[0]).toFixed(4)}, ` + `${((probability(mostLikely[0]) / MASS) * 100).toFixed(1)}% of mass), least likely ` + `${mostLikely.at(-1).exploit} + ${mostLikely.at(-1).payload} (${probability(mostLikely.at(-1)).toFixed(4)})`);
5 exploits x 4 payloads -> 12 valid chains; step order ADTEPMSI = access, discovery, triggering, execution, privilege-escalation, lateral-movement, persistence, impact; chain length 2..7, total steps 53 1. valid chains exploit payload mask steps credential-reuse data-exfiltration AD.....I 3 credential-reuse record-tampering AD..P..I 4 input-triggering data-exfiltration A.TE...I 4 input-triggering service-disruption A.TE...I 4 input-triggering persistent-access A.TE.MSI 6 unsigned-package data-exfiltration ADTE...I 5 unsigned-package record-tampering ADTEP..I 6 unsigned-package service-disruption ADTE...I 5 unsigned-package persistent-access ADTE.MSI 7 account-sharing data-exfiltration AD.....I 3 account-sharing record-tampering AD..P..I 4 transfer-interception data-exfiltration A......I 2 2. if a step is broken step in chains closed left steps done access 12 12 0 0 discovery 8 8 4 8 triggering 7 7 5 11 execution 7 7 5 18 privilege-escalation 3 3 9 8 lateral-movement 2 2 10 7 persistence 2 2 10 9 impact 12 12 0 41 3. if a payload is blocked (exploit stays in place) payload in chains closed left data-exfiltration 5 5 7 record-tampering 3 3 9 service-disruption 2 2 10 persistent-access 2 2 10 exploit credential-reus 2 2 10 exploit input-triggerin 3 3 9 exploit unsigned-packag 4 4 8 exploit account-sharing 2 2 10 exploit transfer-interc 1 1 11 4. best single and pair of middle steps (access and impact excluded) broken step set closed left D 8 4 D+T 11 1 D+T+E+P+M+S 11 1 chains still standing once every middle step is broken: transfer-interception + data-exfiltration (A......I) 5. chains closed vs probability mass closed step closed chains % mass % mass/chain access 12 100.0 100.0 1.00 discovery 8 66.7 60.1 0.90 triggering 7 58.3 25.7 0.44 execution 7 58.3 25.7 0.44 privilege-escalation 3 25.0 14.1 0.56 lateral-movement 2 16.7 3.1 0.19 persistence 2 16.7 3.1 0.19 impact 12 100.0 100.0 1.00 total mass 1.7492; most likely chain transfer-interception + data-exfiltration (0.4500, 25.7% of mass), least likely unsigned-package + persistent-access (0.0227)
Numbers belong to the measurement class; their inputs are SC16–SC19.
Five Exploits, Twelve Chains
The first table shows once more how a product narrows. Five exploits and four payloads make
twenty combinations; the valid ones are twelve, because not every payload matches every
exploit. service-disruption and persistent-access require the execution step;
transfer-interception consists only of the access step, so it carries a single payload and
produces the shortest chain, at two steps.
Chain lengths range from 2 to 7 and total 53 steps. Length comes from the payload: the
unsigned-package exploit is four steps, the persistent-access payload adds three more on top,
and the chain climbs to seven. The same exploit ends at five steps with the data-exfiltration
payload. The exploit is fixed; the payload sets the chain’s length.
This is why the separation matters. The input-triggering mask appears in three chains as
A.TE...I, A.TE...I, and A.TE.MSI — the first two are exactly the same step sequence and
differ only in the payload’s name. Looked at from the defense side, these two chains pass through
the same places, produce the same records, and get cut by the same control; the only difference is
the effect written once they occur.
Which Step to Break Cuts How Many Chains
The second table is this lesson’s central measurement. For each of the eight steps there are two numbers: how many chains it cuts, and how many steps have already completed when it is cut.
The order of cutting power is access and impact (12), discovery (8), triggering and execution (7), privilege-escalation (3), lateral-movement and persistence (2). The order decreases from the front of the chain to the back, because chains are shared early on and branch later. An earlier step closes more paths.
The last column reverses the same ranking. When access is broken, no step has completed;
when impact is broken, 41 steps have already completed across the twelve chains. execution
cuts 7 chains and leaves 18 completed steps behind it; discovery cuts 8 chains and leaves only
8. Two steps with close to the same cutting power leave behind very different amounts of work
already done.
The 12 that appears in the table for both end steps is misleading. access is in every chain, but
breaking it outright means shutting down the service itself — legitimate requests pass through the
same step. impact is also in every chain, but breaking it there means limiting the damage after
the event, not closing a path. The usable lever sits in the six middle steps.
Blocking a Payload Does Not Cut the Chain
The third table sets three levers side by side. Blocking a payload closes at most 5 chains
(data-exfiltration); blocking an exploit closes at most 4 (unsigned-package); breaking a
step closes 8. All three columns run over the same twelve chains, and the difference comes
purely from where the lever is placed.
The payload is the weakest lever, and the reason is visible in the table: the payload sits at
the end of the chain and is interchangeable. The unsigned-package exploit carries four
payloads; blocking one of them leaves the remaining three chains in place. Cutting the same
exploit closes all four at once. Breaking a step is wider still, because a single step is shared
across multiple exploits: the discovery step appears in three separate exploits and cuts eight
chains at once.
The practical payoff of this ordering is where defense gets written. A control that recognizes and stops a specific effect closes a single column; putting the same effort into a step the chain shares closes four times as much. A defense placed at the end of the chain has to be repeated once for every branch the chain has.
The Chain the Middle Steps Cannot Reach
The fourth table shows the lever’s limit. The best single middle step is discovery, closing 8
chains and leaving 4. The best pair is discovery and triggering: 11 chains close, 1
remains. When all six middle steps are broken, the result does not change — still 11 close, 1
remains.
The chain still standing is the transfer-interception exploit with the data-exfiltration
payload, and its mask is A......I. This chain has no step in its middle: it goes straight from
access to impact. Every defense written into the six middle steps never touches it at all, because
it does not pass through any of them.
This row records a limit of the chain model itself. Breaking the chain into steps makes it possible to choose where a defense goes; but a chain whose middle-step set is empty falls outside that choice. The only way to close it is to touch the first step — access — and access is exactly the step the table sets aside as “cannot be removed outright.” The next question is unavoidable because of this: access was written as a single step, yet how many separate forms does reaching an asset actually take.
Chain Count and Probability Mass Are Not the Same Thing
The fifth table gives every chain a completion probability — the product of its step probabilities — and counts not how many chains a broken step closes, but how much probability mass it closes. The total mass of the twelve chains is 1.7492.
The two columns do not move together. discovery closes 66.7% of the chains and 60.1% of
the mass; the ratio, 0.90, is balanced. triggering and execution close 58.3% of the chains
but only 25.7% of the mass — a ratio of 0.44. Two controls that do almost the same job by
count differ by two and a half times in terms of realized probability. The reason is length:
chains that pass through execution are longer, and every additional step multiplies the
probability down once more. lateral-movement and persistence are the extreme case — they close
16.7% of the chains and 3.1% of the mass.
The last line ties back to the previous lesson’s number. The most likely chain is the
transfer-interception and data-exfiltration pair: two steps, a probability of 0.4500, and on
its own it carries 25.7% of the total mass. The least likely is the seven-step
unsigned-package with persistent-access: 0.0227. The third lesson wrote a probability of 0.03
for the unsigned-update item and 0.25 for unencrypted-transfer; this is where those two
numbers come from — as the chain lengthens, probability falls and impact grows.
This sharpens the fourth table’s finding even further. The single chain still standing once every middle step is broken is also the chain carrying a quarter of the mass. Counted by number, it is a remainder of 1 in 12; weighed by probability, it is the single largest share the defense leaves outside.
Summary
- Exploit is the step sequence that uses a vulnerability, and payload is the effect written after the exploit completes; five exploits with four payloads produce 12 valid chains, lengths 2 to 7, totaling 53 steps.
- Breaking a step closes more paths the closer it sits to the start of the chain: 12, 8, 7, 7, 3, 2, 2. Two chains of the same exploit can follow the identical step sequence and differ only in the payload’s name.
- The same break leaves a different amount of completed work depending on where it sits in the chain: 0 steps at access, 8 at discovery, 18 at execution, 41 at impact.
- The three levers are not equal: blocking a payload closes at most 5, blocking an exploit at most 4, and breaking a step 8 chains; the payload is the weakest lever because it sits at the end of the chain.
- When all six middle steps are broken, 1 of 12 chains still stands — the one with no step in its middle, going straight from access to impact.
- Chain count and probability mass are separate measures: triggering closes 58.3% of the chains but 25.7% of the mass; the one chain still standing carries 25.7% of the mass.
Next Step
Every measurement in this lesson stood on a single assumption: that access is one step. All
twelve of the twelve chains started from that step, and that step was never opened up. But
reaching an asset is not passing through a single door — there are separate paths starting from a
branch endpoint, a field app, a shared interface, or a management endpoint, and each passes
through a different number of stops. The topic’s last lesson models these paths on a graph,
actually runs the path count, and counts how many paths reducing the attack surface closes and
how many legitimate work items it stops.
To keep your progress and take notes, Log in
My notes
Log in to take notes.