Oh My Data
A breached credentials dump for CyberNT was reported, but the real question — which accounts were still active after the leak — was unanswered. OSINT traced the leak to a paste site. The raw credential format was reshaped through a Bash sed pipeline into machine-readable input. The login API was reverse-engineered from browser DevTools to capture the exact POST schema. The credential-testing tool was built in Python stdlib only, with no external dependencies, so it could run in an operationally restricted environment.
Executive Summary
CyberNT disclosed a credential leak but had no visibility into which accounts in the leaked set remained active and exploitable. The analyst role was to locate the leak, validate the credentials against the live authentication surface, and identify accounts that were still compromised — answering the actual operational question, not just confirming the leak existed.
The leak was traced through OSINT to a Stikked paste site linked from the organization's own "Data Leaks" forum post. The raw dump used a human-readable email -- password format that was not directly consumable by automation. A single sed expression reshaped it to the conventional email:password combo list. Browser DevTools inspection of the login flow surfaced the exact POST endpoint, headers, and JSON body schema the application expected — including the non-standard pass key (not password) and the string marker "Sorry <user>, your account has been disabled" that distinguished valid-but-disabled accounts from valid-and-active ones.
The credential-testing tool was built using only http.client, json, and ssl from the Python standard library. No requests. No pip install. This constraint was deliberate — it meant the tool would run in any environment that had Python, regardless of package-install permissions. The script identified accounts that still authenticated successfully, confirming active compromise post-leak.
Findings & Analysis
(linked from cybernt-labs.com)
cyber surfaced the dump file named CyberNT leaked passwords.(not machine-readable)
sed 's/ -- */:/g' expression into conventional email:password combo format.Content-Type: application/json
pass (not password) — a detail that would break any generic credential-testing script that assumed the conventional key name.has been disabled"
(valid, post-leak authentications)
results.txt as confirmed active compromises. These are the IOCs the organization needed to prioritize for rotation or disabling.- Leak host: Stikked paste site (linked from cybernt-labs.com)
- Normalized input: combos.txt (
email:passwordformat) - Target endpoint: https://cybernt-labs.com/api/login (POST, JSON)
- Body schema: { "email": "...", "pass": "..." }
- Disabled marker: response contains "Sorry"
- Output: results.txt (confirmed-active compromised credentials)
Tools & Technologies
sed 's/ -- */:/g' handles the idiosyncratic separator without requiring a general-purpose parser.http.client, json, and ssl. No requests, no external packages. The constraint forced closer engagement with the HTTP layer and produced a tool that runs in any environment with Python installed.Investigation Process
Six steps. The defining move was not any one command — it was deciding, after the DevTools inspection, to build the credential tester in stdlib only rather than reach for requests or an existing framework. That choice is what made the tool portable.
Why: Start from the disclosure surface and pivot outward. The organization's own "Data Leaks" post was the shortest path to the actual dump — faster and less noisy than searching paste aggregators blindly. Saving the file locally under a known name keeps the evidence chain auditable.
Why: The raw dump used email -- password, which is human-readable but not consumable by automation that expects the standard email:password combo format. A single sed substitution with a trailing-space tolerance (' -- *') handles format variation without writing a parser. Output redirected to a new file preserves the original for audit.
Why: Never guess an API schema. The application uses pass, not password — a detail that would silently break any generic credential-testing script that assumed the conventional key. The response-body marker "Sorry" is the signal that separates disabled from active accounts; capturing it here, before writing any code, is what makes the detection logic correct on the first run.
The obvious move after DevTools is to reach for requests and have the tool running in ten lines. The decision here was to not do that — to build the credential tester using only http.client, json, and ssl from the Python standard library. That means no pip install, no dependency surface, no package-manager permissions required. The tool will run in any environment that has Python, which is the actual operational constraint a credential-validation tool needs to meet when it's going to be used on arbitrary analyst machines. The cost is extra lines; the benefit is portability. For a tool whose purpose is to run wherever the next incident happens, the trade is obviously right.
Why: Every design choice is explicit. split(":", 1) handles passwords containing colons without breaking on them. The "Sorry" not in body check matches the exact marker captured in DevTools — not a guess, not a status-code heuristic, the actual string the application returns. Valid hits are both printed (for live feedback) and appended to results.txt (for durable output). The try/except around the request isolates network failures from credential logic so one bad row doesn't abort the run.
Why: Run the tester against the normalized combo list. Each credential prints its status ([+] VALID or [-] Disabled) for live triage, and confirmed-active credentials append to results.txt. The output is immediately usable as a prioritized list of accounts for rotation or disabling.
Why: End-to-end validation. The tester identified credentials the API accepted — confirming full login through the application proves the accepted credentials actually grant portal access, not just a positive authentication response. This closes the loop on the operational question: yes, accounts remain compromised post-leak.
Recommendations
password, username) and conventional response patterns (HTTP 401, generic error bodies) will silently fail against real applications that deviate from those conventions. DevTools is the authoritative source; using it first saves debugging cycles later.ssl._create_unverified_context() was used here for the controlled lab environment and should be documented as such. In any production credential-validation context, certificate verification must be enabled — a MITM against the validation tool itself could harvest every credential it tests.Technical Note
The design decision that defines this case is refusing to use requests. That choice makes the credential tester operate at the raw http.client level — constructing the HTTPS connection, forming the JSON body, reading the response, all explicitly. There is no magic. Every behavior the tool exhibits is visible in the forty lines of code that produce it.
The operational consequence is portability. The tool has no pip dependencies. It runs in any environment with a Python 3 interpreter — including locked-down analyst workstations, customer-premises boxes under change control, and air-gapped lab images where package installation is blocked. A credential-validation tool that needs to install requests before it can run is a credential-validation tool that does not run when you need it most.
The secondary consequence is defensibility. A stdlib-only tool has a trivially small supply-chain attack surface. There is no transitive dependency graph, no version-pin drift, no typosquatting package risk. For security tooling specifically, that matters: a credential tester that has been compromised via an upstream package is a credential harvester.
References
- Python
http.clientdocumentation. Standard-library HTTP client used to construct and send the credential-validation requests without external dependencies. docs.python.org - OWASP Credential Stuffing Prevention Cheat Sheet. Defender-side guidance for detecting and mitigating the attack class this case validates from the analyst side. cheatsheetseries.owasp.org
- NIST SP 800-63B — Digital Identity Guidelines. Authoritative guidance on credential lifecycle including rotation requirements following known compromise. nist.gov