---
title: 'Credential Theft'
source: 'https://academia.sh/en/courses/identity-and-cryptography/credential-theft'
course: 'Identity, Access and Cryptography'
language: en
updated: '2026-09-26T03:02:53+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - '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'
---

# 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.

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.

```js
// 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",
};
```

```js
// 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.
