Skip to content
academia.sh

Lesson 21 / 21

Credential Theft

How long verification items stay in memory and the path controls close: 6 of 8 item types can be presented directly without knowing the password, 22 paths and 298,958 machine-hours of exposure, six controls closing 17 paths and dropping exposure to 1%, and the remaining 5 paths not closing under any control.

Published Updated

In this lesson

  • Measures verification items by the product of time-in-memory and scope
  • Explains conceptually why pass-the-hash works without knowing the password
  • Calculates separately the paths controls close and the exposure that remains
Contents

The previous lesson counted escalation through configuration items: a membership, a permission, an account. There is one more item that stays silent behind the edge list. Moving from one account to another usually does not require knowing that account’s password, but rather getting hold of the value used to authenticate it; such a value sits in the memory of machines for every logged-in user.

This lesson measures those values on the defense axis: which item stays where for how long, how many items can be presented directly without knowing the password, and which control closes how many paths. No working step sequence, tool name, or command is written in this lesson; what is measured is not how the item is obtained, but what it opens assuming it has been obtained. Running such a test without written authorization and a defined scope is both illegal and unprofessional.

What Is Presented Is Not the Password

EI23: in most mechanisms the authentication input is not the password itself but a value derived from or produced with it; the verifying side expects that value. EI24: because of this, whoever gets hold of the value does not need to know the password — what is presented is already not the password. EI25: an item’s time in the machine is multiplied by its scope; defense is measured by one of removing the item, shortening its lifetime, or narrowing its scope.

EI24 is this lesson’s conceptual core and explains the entire class called pass-the-hash. The password is never stored anywhere; what is stored and passes over the network is a value derived from it. The verifying side compares the value presented to it with the value in its own record and accepts if they match. This is not a flaw but a design — done so the password does not pass over the network. But the same design also says this: whoever can present the derived value gets the same result as whoever knows the password. This is why changing the password renews the item, and it is also the only action to take for an account whose item was stolen.

Eight Item Types, Twenty-Two Paths

The inventory below is a model: the verification items sitting on machines after a session is opened, in the fictional regional measurement network organization. There is no real organization, real machine, or working step sequence.

// theft/item.mjs — verification items sitting on a machine after a session is opened
// (model): there is no real organization, real machine, real item, or working step
// sequence. No randomness.

// EI23: in most mechanisms the authentication input is not the password itself but a value derived
// from or produced with it; the verifying side expects that value. EI24: because of this, whoever
// gets hold of the value does not need to know the password — what is presented is already not the password.
// EI25: an item's time in the machine is multiplied by its scope; defense is measured by one
// of removing the item, shortening its lifetime, or narrowing its scope.
// Columns: life = the item's time on the machine (hours), scope = number of systems the item
// can open, presentable = is it accepted when presented directly without knowing the password.
export const ITEM = `
  password-derived-verifier    720   13   yes
  ticket-granting-ticket        10   21   yes
  service-ticket                10    1   yes
  session-key                   10    1   no
  application-session-cookie    72    1   yes
  cached-verifier                8    1   no
  renewal-ticket               168   21   yes
  service-account-secret       720    1   yes`
  .trim().split("\n").map((r) => {
    const p = r.trim().split(/\s+/);
    return { name: p[0], life: +p[1], scope: +p[2], presentable: p[3] === "yes" };
  });

export const CLASS = [
  { name: "branch-workstation", count: 96 },
  { name: "server", count: 21 },
  { name: "field-laptop", count: 140 },
  { name: "meter-collector", count: 44 },
];

// Which item is found on which class: each pair is a path.
export const FOUND_ON = {
  "password-derived-verifier": ["branch-workstation", "server", "field-laptop"],
  "ticket-granting-ticket": ["branch-workstation", "server", "field-laptop"],
  "service-ticket": ["branch-workstation", "server", "field-laptop", "meter-collector"],
  "session-key": ["branch-workstation", "server", "field-laptop", "meter-collector"],
  "application-session-cookie": ["branch-workstation", "field-laptop"],
  "cached-verifier": ["branch-workstation", "field-laptop"],
  "renewal-ticket": ["branch-workstation", "field-laptop"],
  "service-account-secret": ["server", "meter-collector"],
};

// Each control states which (item, class) pair it removes, by its own criterion.
export const CONTROL = {
  "privileged-session-isolation": (k, s) => k.scope > 1 && s.name !== "server",
  "protected-account-group": (k) => k.name === "cached-verifier" ||
    k.name === "password-derived-verifier",
  "local-admin-restriction": (k, s) => s.name === "branch-workstation" || s.name === "meter-collector",
  "logoff-enforcement": (k) => k.life > 24,
  "service-account-isolation": (k) => k.name === "service-account-secret",
  "origin-bound-factor": (k) => k.name === "application-session-cookie" || k.name === "renewal-ticket",
};
// theft/tally.mjs — which item stays where for how long, how many items can be presented
// without knowing the password, how many paths each control closes, and what exposure remains.
import { ITEM, CLASS, FOUND_ON, CONTROL } from "./item.mjs";

const print = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const classOf = (name) => CLASS.find((s) => s.name === name);
const PATH = ITEM.flatMap((k) => FOUND_ON[k.name].map((s) => ({ k, s: classOf(s) })));
const exposure = (y) => y.reduce((a, x) => a + x.s.count * x.k.life, 0);
const open = (closed = []) =>
  PATH.filter((y) => !closed.some((d) => CONTROL[d](y.k, y.s)));

console.log(`${ITEM.length} item types, ${CLASS.length} machine classes, ` +
  `${PATH.length} paths, ${CLASS.reduce((a, s) => a + s.count, 0)} machines`);
console.log(`items presentable directly without knowing the password ` +
  `${ITEM.filter((k) => k.presentable).length}/${ITEM.length}; ` +
  `total exposure ${exposure(PATH)} machine-hours`);

const A = [-28, 7, 8, 8, 8, 12];
console.log("\n1. per item: where, how long, how wide");
print(A, "item", "life", "scope", "class", "machine", "machine-hr");
for (const k of ITEM) {
  const y = PATH.filter((x) => x.k === k);
  print(A, k.name, k.life, k.scope, y.length, y.reduce((a, x) => a + x.s.count, 0), exposure(y));
}

const B = [-30, 8, 12, 12, 10];
console.log("\n2. paths closed and exposure per control");
print(B, "control", "closed", "open paths", "open expo", "open %");
for (const d of Object.keys(CONTROL)) {
  const rest = open([d]);
  print(B, d, PATH.length - rest.length, rest.length, exposure(rest),
    `${(100 * exposure(rest) / exposure(PATH)).toFixed(0)}%`);
}

const C = [-30, 8, 9, 12, 10];
console.log("\n3. controls added cumulatively");
print(C, "added", "paths", "closed", "exposure", "open %");
const chosen = [];
print(C, "none", PATH.length, 0, exposure(PATH), "100%");
for (const d of Object.keys(CONTROL)) {
  chosen.push(d);
  const rest = open(chosen);
  print(C, d, rest.length, PATH.length - rest.length, exposure(rest),
    `${(100 * exposure(rest) / exposure(PATH)).toFixed(0)}%`);
}

const D = [-26, -18, 8, 13];
console.log("\n4. paths remaining with all controls open");
const rest = open(Object.keys(CONTROL));
print(D, "item", "class", "machine", "machine-hr");
for (const y of rest) print(D, y.k.name, y.s.name, y.s.count, y.s.count * y.k.life);
console.log(`remaining paths ${rest.length}/${PATH.length}, ` +
  `remaining exposure ${exposure(rest)}/${exposure(PATH)} machine-hours`);
8 item types, 4 machine classes, 22 paths, 301 machines
items presentable directly without knowing the password 6/8; total exposure 298958 machine-hours

1. per item: where, how long, how wide
item                           life   scope   class machine  machine-hr
password-derived-verifier       720      13       3     257      185040
ticket-granting-ticket           10      21       3     257        2570
service-ticket                   10       1       4     301        3010
session-key                      10       1       4     301        3010
application-session-cookie       72       1       2     236       16992
cached-verifier                   8       1       2     236        1888
renewal-ticket                  168      21       2     236       39648
service-account-secret          720       1       2      65       46800

2. paths closed and exposure per control
control                         closed  open paths   open expo    open %
privileged-session-isolation         6          16       87030       29%
protected-account-group              5          17      112030       37%
local-admin-restriction             10          12      170590       57%
logoff-enforcement                   9          13       10478        4%
service-account-isolation            2          20      252158       84%
origin-bound-factor                  4          18      242318       81%

3. controls added cumulatively
added                            paths   closed    exposure    open %
none                                22        0      298958      100%
privileged-session-isolation        16        6       87030       29%
protected-account-group             13        9       70022       23%
local-admin-restriction              7       15       28630       10%
logoff-enforcement                   5       17        3430        1%
service-account-isolation            5       17        3430        1%
origin-bound-factor                  5       17        3430        1%

4. paths remaining with all controls open
item                      class              machine   machine-hr
ticket-granting-ticket    server                  21          210
service-ticket            server                  21          210
service-ticket            field-laptop           140         1400
session-key               server                  21          210
session-key               field-laptop           140         1400
remaining paths 5/22, remaining exposure 3430/298958 machine-hours

The numbers are of the measurement class; their inputs are EI23–EI25 and the item inventory.

The Product of Life and Scope

The first table lays the eight items side by side. The password-derived verifier stays 720 hours, opens 13 systems, and is found on 257 machines across three classes: on its own it produces 185,040 machine-hours of exposure, 62% of the total. The ticket-granting ticket opens 21 systems but stays only 10 hours; its exposure is 2,570. Scope alone does not give a ranking; multiplied by lifetime, it does.

The renewal ticket ranks second: 168 hours, 21 systems, 39,648 machine-hours. The 72-hour session window measured in the fourth lesson and the 168-hour renewal ticket seen here are two views of the same setting — one written as revocation delay, the other as time-in-memory. The same number produces cost in two different columns.

The service account secret is found on only 65 machines but stays 720 hours and yields 46,800 machine-hours. The second lesson measured that breaking one of 21 service-account keys drops 214 principals; the 46,800 here is the counterpart of how long that item stays exposed on machines.

Six Controls, Seventeen Paths

The second table runs the controls one at a time. The local-admin restriction closes the most paths — 10 of 22 — but the remaining exposure is 57%, because the paths it closes are in classes hosting short-lived items. The logoff enforcement closes only 9 paths but drops exposure to 4%; the items it removes are the long-lived ones.

These two rows repeat one of the course’s rules: a number cannot be read without choosing a unit of measure. Ranked by path count, local-admin restriction is first; ranked by exposure, logoff enforcement is first. The two rankings give different defense priorities, and which one is correct depends on what the organization is measuring.

The third table adds all six cumulatively. The path count drops from 22 to 5, exposure from 298,958 to 3,430; the remaining ratio is 1%. The last two controls — service-account isolation and origin-bound factor — close no new paths, because the items they close have already been removed by the earlier controls. It is the same pattern seen in the seventh lesson: a control that is effective on its own can contribute zero in the cumulative list.

The Five Paths That Do Not Close

The fourth table lists what remains with all six controls open. Five paths remain, and all five are short-lived items on servers and field laptops: the ticket-granting ticket, the service ticket, and the session key. Total exposure is 3,430 machine-hours.

These five do not close, because removing them means removing the session itself. If a user has a session open on a server, that session’s key has to stay there; without a ticket, the service cannot be reached. This is where the course’s measured root falls shortest most plainly: the way to close the remaining paths is not a better control, it is shortening the session’s duration — and that also stops legitimate work.

Summary

  • The authentication input is not the password itself but a value derived from it; 6 of 8 item types are accepted when presented directly without knowing the password.
  • Exposure is the product of life and scope: the password-derived verifier alone produces 62% of the total 298,958 machine-hours with 720 hours and 257 machines.
  • The control most effective by path count and the control most effective by exposure are not the same: one closes 10 paths and leaves 57%, the other closes 9 paths and leaves 4%.
  • Six controls together close 17 paths and drop exposure to 1%; the last two controls contribute zero in the cumulative list.
  • The remaining 5 paths do not close under any control, because removing them means removing the session itself.

Course Wrap-Up

Twenty-one lessons were measured with the same three columns. The table below lays each lesson’s trust root, the number of items that must be correct at the same time from root to use, and what drops if the root breaks, side by side.

Lesson Trust root Items that must hold What drops if the root breaks
Hashing, Encryption, and Encoding operation–domain match 2 secret items 24,800 records
Hash Functions lookup cost 25,242 items 12,502 items
Salt and Password Storage password unpredictability 2 factors 340 records
Symmetric Encryption shared key 4 items 12,401 ends
Asymmetric Encryption private key secrecy 12,401 secret items 1 participant
Key Exchange secret exponent 3 items 52,560 sessions
Digital Signatures signing key 6 items 2,190 signatures
Certificates audited fields 8 items 13 attempts
Certificate Authorities root certificate 14 items 8,802 items
Certificate Revocation publication freshness 29.5-hour window 271,877 connections
TLS Handshake the server’s private key 11 items 5 presentations
Certificate Lifecycle renewal automation 4,397 items 1,458 connections
End-to-End Encryption the key at the end 4 items 172,200 records
Directory Services the integrity of the central repository 119 items 646 items
Ticket-Based Authentication the ticket-granting service’s key 471 key items 214 principals
Authentication for Network Access shared secret 480 items 80 devices
Single Sign-On signing key 90 items 1,562 connections
Multi-Factor Authentication the bond at the registration moment 4 items 10 paths
Group Policies policy repository 12 settings 295 machines
Privilege Escalation inventory accuracy 20 edges 37 paths
Credential Theft the verifier in memory 8 item types 22 paths

The table’s common column is the second one. In no row does the root stand alone: the smallest asks for two, the largest for more than twelve thousand items, and most of the items are not cryptographic. An hour, a record, a distribution round, an inventory row — these items around the root determine where the break actually comes from.

Three topics show three different root classes. In the cryptography-fundamentals lessons the root is a secret or a cost assumption: a secret exponent, a private key, the unpredictability of a password. In the pki lessons the root is a decision: which authority is trusted, which field is checked, how often revocation is published. In the enterprise-identity lessons the root is an operational item: a repository record, a distribution round, an inventory row, a moment of registration. Moving from plain mathematics toward operations does not make protecting the root harder — it makes seeing it harder.

The third column’s magnitude follows this same order too. A secret exponent dropping opens 52,560 sessions and the event is obvious; a directory record getting corrupted drops 646 items and it is not even known that it happened. Three lessons in the course showed that the root itself is not enough: a signature does not prove who the signing key belongs to, a certificate does not guarantee revocation is learned, multi-factor authentication cannot verify its own moment of registration. In all three, what is missing is not inside the mechanism, it is around it.

The course’s rule is this: cryptography is not a secrecy tool, it is a method of reducing trust to a single root; whoever does not know where the root stands cannot protect it. The third column writes the price of that — 646 items, 8,802 items, 214 principals, 1,562 connections. These numbers do not come from the mechanism’s weakness but from the reduction’s success: because trust is concentrated in one place, that is where it breaks.

In this course the root was named every time and its chain counted. But under every root an unwritten assumption remained: the integrity of the machine the root stands on. A private key sits in a file, a ticket in a region of memory, a policy repository on a disk. If that machine is compromised, the whole chain — even if correctly set up, correctly renewed, correctly audited — stays valid in the attacker’s hands. The Endpoint and System Hardening course starts with this question.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close