Skip to main content
EtherReaper centralises all captured credentials in a single SQLite table. Credentials arrive from several different tools and capture methods, are automatically deduplicated on write, and immediately become available to authenticated scan dropdowns without any manual steps.

Credentials table schema

CREATE TABLE credentials (
    id            INTEGER PRIMARY KEY AUTOINCREMENT,
    username      TEXT,
    password      TEXT DEFAULT '',
    hash          TEXT DEFAULT '',
    domain        TEXT DEFAULT '',
    source        TEXT DEFAULT 'manual',
    discovered_at TIMESTAMP,
    hostname      TEXT,
    ip            TEXT
)
A row may have either password or hash populated, or both (for example when a plaintext password is entered and its NTLM hash is derived separately). The source column identifies how the credential was obtained.

Capture sources

Responder

LLMNR/NBT-NS/mDNS poisoning captures NTLM challenge-response hashes from machines on the same broadcast domain. Hashes are written to the Responder log file and parsed into the credentials table.

netexec

Authenticated SMB, LDAP, and LSA sweeps return plaintext passwords and hashes. Each appears with a distinct source tag: netexec(SMB), netexec(LDAP), or netexec(LSA).

Kerberoast

Service account TGS hashes in $krb5tgs$ format are extracted from the kerberoast output file and stored with source = 'kerberoast'.

ASREPRoast

AS-REP hashes in $krb5asrep$ format are extracted with source = 'asreproast'. These are for accounts with Kerberos pre-authentication disabled.

GMSA Passwords

Group Managed Service Account NTLM hashes are parsed from netexec output and stored with source = 'gmsa'.

Manual entry

Credentials added directly through the DATA → Credentials UI use source = 'manual'.

Deduplication logic

Each capture function applies source-specific deduplication before writing to the database.

Kerberoast hashes (parse_kerberoast_hashes)

Kerberoast hashes change on every request (they include a fresh timestamp), so deduplication is by username + source rather than by hash value. When a username already exists with source = 'kerberoast', the existing row is updated with the new hash:
cursor.execute(
    "SELECT id FROM credentials WHERE username = ? AND source = 'kerberoast'",
    (username,)
)
existing = cursor.fetchone()

if existing:
    cursor.execute("""
        UPDATE credentials
        SET hash = ?, discovered_at = ?
        WHERE username = ? AND source = 'kerberoast'
    """, (full_hash, datetime.now(), username))
else:
    cursor.execute("""
        INSERT INTO credentials (username, hash, domain, source, discovered_at)
        VALUES (?, ?, ?, 'kerberoast', ?)
    """, (username, full_hash, domain, datetime.now()))
Username extraction handles three Kerberoast hash formats:
  • Type 23 (most common): $krb5tgs$23$*username$realm$spn*$...
  • Type 17/18 computer accounts: $krb5tgs$18$accountname$$REALM$... (trailing $ preserved)
  • Type 17/18 user accounts: $krb5tgs$17$accountname$REALM$...

ASREPRoast hashes (parse_asreproast_hashes)

AS-REP hashes also contain timestamps and change on each request. Deduplication is the same pattern — update by username + source = 'asreproast':
# Extract username from $krb5asrep$23$user@REALM:... or $krb5asrep$23$user:...
username_match = re.search(r'\$krb5asrep\$23\$([^@:]+)', full_hash)
username = username_match.group(1) if username_match else 'unknown'

GMSA passwords (parse_gmsa_passwords)

GMSA entries are matched with the pattern Account: <name> NTLM: <32-hex>. Deduplication is by username + source = 'gmsa':
pattern = re.compile(r"Account:\s+([^\s]+)\s+NTLM:\s+([a-fA-F0-9]{32})")

How saved credentials populate scan dropdowns

Every authenticated scan modal (BloodHound, Kerberoast, ADCS, Shares, etc.) queries the credentials table and populates a Saved Credentials dropdown. Selecting an entry auto-fills the username, password or hash, and domain fields. This means credentials captured in one scan are immediately usable in subsequent scans without copy-pasting.

Filtering by source

The DATA → Credentials page supports filtering by source. Available source values:
SourceDescription
netexec(SMB)SMB authentication sweep
netexec(LDAP)LDAP authentication sweep
netexec(LSA)LSA secrets dump
kerberoastKerberoastable TGS hashes
asreproastAS-REP hashes
gmsaGMSA NTLM hashes
manualManually entered credentials

Hash Calculator

The Hash Calculator derives cryptographic key material from a plaintext password without needing a domain controller. It uses impacket’s RFC 3962 string_to_key implementation to produce:
  • NTLM hash — MD4 of the UTF-16LE encoded password
  • AES-128 Kerberos key — RFC 3962 string_to_key with 128-bit key
  • AES-256 Kerberos key — RFC 3962 string_to_key with 256-bit key

Salt formula

The salt used for AES key derivation depends on account type:
Account typeDetectionSalt formula
User accountNo $ suffixREALM + username (e.g. CORP.LOCALjsmith)
Machine accountUsername ends with $REALM + host/ + FQDN (e.g. CORP.LOCALhost/ws01.corp.local)
Machine accounts are auto-detected by the $ suffix on the username.
All Hash Calculator results are click-to-copy and can be saved directly to the credentials database from the same UI panel.

Export

The DATA → Credentials page provides a Export to TXT button that writes all credentials (or the current filtered set) to a plain text file, one credential per line. This is useful for feeding hashes directly into hashcat or john.

Build docs developers (and LLMs) love