Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cip-security-poc — Proof-of-concept reproducing CVE-2021-22681's hardcoded-key flaw and validating a per-device mutual TLS/CRL fix over simulated EtherNet/IP, with IEC 62443-4-2 mapping. | Kitploit
Tools/GitHubGitHub/pcrosby-1990/cip-security-poc
Vulnerability AnalysisSCADA/ICS SecurityCryptographyThreat IntelligenceAuthenticationIncident Response
GitHubpcrosby-1990/cip-security-poc

cip-security-poc

Proof-of-concept reproducing CVE-2021-22681's hardcoded-key flaw and validating a per-device mutual TLS/CRL fix over simulated EtherNet/IP, with IEC 62443-4-2 mapping.

View Repository
17 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

cip-security-poc — proving the fix principle behind CVE-2021-22681 (not just its flaw)

Four runnable scripts. Real EtherNet/IP protocol traffic, real cryptography, zero Rockwell software or licensing anywhere in the chain. Built to test a claim before writing it up, not to argue for it on faith.

Provenance: built 2026-07-31, alongside a parallel investigation into the Braham, MN WWTF — one of the four utilities publicly disclosed in the coordinated Minnesota water-sector incident of July 26–27, 2026. Context for that incident lives in CISA advisory AA26-097A (joint FBI/CISA/NSA/EPA/DOE/USCYBERCOM/Treasury; issued 2026-04-07, expanded 2026-07-22), which covers the ongoing IRGC-affiliated CyberAv3ngers campaign. Attribution caveat, held precisely: no agency has formally attributed the Minnesota incident specifically to that group — only the broader ongoing campaign is. This folder is the technical-fix side, kept separate from the incident investigation on purpose.

Three different failures — keep them distinct

A disclosure packet lives or dies on not smearing these together, because each has a different fix:

  • No / absent authentication (Test 1) — a device exposed with no credential layer at all. The broad baseline the CyberAv3ngers campaign leaned on (many victims were reachable with absent or default creds).
  • One hardcoded / shared key across a fleet (the specific shape of CVE-2021-22681, modeled by Test 2) — extract the one key once, forge fleet-wide. This is the actual CVE.
  • Default credentials — factory creds never changed. Not modeled here; named so it isn't conflated with the two above.

The fix demonstrated here — per-device identity binding (Test 3) — addresses the fleet-key failure.

The hard boundary (read this first)

Do not conflate the two rows. The principle is proven. The vendor's specific implementation of it is credible (it's their own stated design intent) but untested by us against real equipment.

Tools

test1_baseline_vulnerable.py — the no-auth baseline, live

Spins up a real EtherNet/IP PLC simulator (cpppo, emulating an Allen-Bradley ControlLogix) and reads + writes a control tag with zero credentials. (Scope: this is the broad no-authentication baseline the campaign leaned on — not the specific hardcoded-key mechanism of CVE-2021-22681. Kept distinct on purpose; see "Three different failures" above.)

root@kitploit:~
python test1_baseline_vulnerable.py

test2_shared_secret_fails.py — the shape of the fleet-key flaw (narrative bridge, not a test)

Two endpoints hold one static key; a credential from Device A opens Device B unchanged — the closest structural analog to CVE-2021-22681's one-key-fits-all flaw. But it is tautological: both handlers are constructed to accept that key, so there is no execution path in which it can fail. It demonstrates nothing the code doesn't define into existence. Kept as the narrative bridge from Test 1 to Test 3; it carries no evidential weight and is deliberately not a proof-leg.

root@kitploit:~
python test2_shared_secret_fails.py

test3_mutual_tls_fix.py — the fix, with its negative control and both directions

Real CA, two individually-unique device certs — identity bound in the SubjectAlternativeName, not the deprecated CommonName. Five cases, all executed:

  • [1] Device A's own cert → GRANTED · [2] no cert → rejected at the TLS handshake · [3] Device B's CA-valid cert → DENIED on identity (strict endpoint).
  • [4] THE CONTROL — the same Device B cert against a CA-validity-only endpoint → GRANTED. This is what makes [3] mean anything: without the identity check, any fleet cert opens any device (== Test 2, in TLS clothing).
  • [5] REVERSE — a rogue server presenting Device B's cert is rejected by a client that binds device-a (check_hostname against a real SAN). Mutual — both ends bind identity.
root@kitploit:~
python test3_mutual_tls_fix.py

test4_revocation.py — the lifecycle leg: revocation

A real CA-signed CRL. A client credential (engineer-1) is granted; then its serial is added to the CRL, and the same still-valid, unexpired, CA-signed credential is denied — the empirical content of the CR 1.8 / 1.9 revocation clause. Uniqueness (Test 3) ≠ revocability; this shows a credential can be taken back.

root@kitploit:~
python test4_revocation.py

Scope boundaries (what is NOT claimed)

  • Revocation — now demonstrated (test4_revocation.py); rotation — not yet. Per-device uniqueness (Test 3) is not the same as revocability; Test 4 closes that gap — a still-valid, unexpired, CA-signed credential is granted before revocation and denied after, solely because the CA-signed CRL now lists its serial. Rotation (re-issue a replacement credential and retire the old one) is closely related and enabled by the same PKI, but is not separately demonstrated here — so "per-device identity binding" still must not silently expand into "rotation solved."
  • Constant-time (low severity, named for hygiene). The identity string compares (presented == KEY, identity in SAN) are not constant-time. Not exploitable here — the compared values are public-ish identity strings and TLS has already done the real cryptographic authentication before the compare runs — but flagged because the pattern gets copied into places where it does matter.

Setup

root@kitploit:~
python -m venv venv
venv\Scripts\activate        # or: source venv/bin/activate
pip install -r requirements.txt

Next steps (one real item left, plus two small optional ones)

  • 62443-4-2 SL 2 mapping — DRAFTED → 62443-4-2_SL2_MAPPING.md (CR 1.2 / 1.8 / 1.9 / 1.14 / 3.1, honestly tiered, every gap named; CR 1.2, CR 1.9, and CR 1.8's issuance/validation/revocation leg are now demonstrated). Before PSIRT ([email protected] / [email protected]): verify each CR's normative text against a purchased copy of IEC 62443-4-2:2019.
  • Phased rollout — DRAFTED → PHASED_ROLLOUT.md (Phase 0 stop-the-bleeding · 1 segment · 2 compensating controls · 3 CIP Security/PKI, hardware-permitting · 4 operate). Right-sized for a small utility; honest that CIP Security is hardware-gated, so Phases 0–2 carry the risk reduction regardless.
  • Still open — the actual remaining item: responsible-disclosure sequencing. PSIRT contact first, public writeup / LinkedIn after, so the chain of provenance is documented in order. Not yet drafted: the PSIRT email itself.
  • Two small technical items, named not smuggled (per the mapping doc's own summary): a rotation test (re-issue + retire) to move CR 1.8 from "enabled" to fully demonstrated, and a tamper-injection test to move CR 3.1 from "by construction" to demonstrated. Neither is load-bearing for the central claim; both are small if picked up.

Citations — retrieved, not recalled (and re-pull before submission)

Every external identifier here was pulled from a live source on 2026-07-31, not recalled from training: AA26-097A (multi-source, incl. WaterISAC / Tenable / SecurityWeek), Braham as one of the four disclosed victims, CyberAv3ngers/IRGC, PN1550 confirmed the real Rockwell advisory with its Row-2 quote checked verbatim ("When properly deployed, CIP Security remediates this vulnerability"

  • "does not make use of any hardcoded keys"), "cannot be mitigated with a patch" verbatim, CVSS 10.0 / CRITICAL (v3.1), CISA tracking ICSA-21-056-03, and 62443-4-2 CR 1.8 (PKI) + CR 3.1 (comm integrity) confirmed exact. Discipline for the packet: re-pull every identifier from primary sources at submission time. Advisories get renumbered, expanded, and superseded — AA26-097A already shows one expansion — so "verified on 2026-07-31" is not "verified at submit." The full formal CR-by-CR 62443-4-2 mapping is now written (62443-4-2_SL2_MAPPING.md) — what's left is re-pulling its cited normative text against a purchased standard copy before submission, not writing the mapping itself.

l0gic — Patrick Crosby · 2026-07-31.

Hardening log: Test 3 was strengthened to include the negative control (case 4, proving necessity not just firing), the reverse-direction case (case 5, mutual binding), and SAN-based identity (not CN), then re-verified by re-running all five cases; Test 4 (CRL revocation) was added. Test 1/2 captions were right-sized to keep the three failure classes distinct; Test 2 was demoted from "test" to narrative bridge; revocation and constant-time scope boundaries were added. The citation chain was retrieved from primary sources and stamped for re-pull at submission.

Download Tool
ClaimTierWhy
The architectural principle"a single shared secret across a fleet is compromised fleet-wide by one leak; per-device identity-bound authentication closes that"PROVENdemonstrated with real running code including the negative control that proves the check is necessary, not merely that it fires: on a strict endpoint Device B's genuinely CA-valid cert is rejected on identity (Test 3 · case 3), but on a CA-validity-only endpoint the same cert is accepted (case 4 — the control) → "validly CA-signed alone == fleet-wide access == Test 2 in TLS clothing." The binding also holds in reverse: a rogue server presenting a valid fleet cert is rejected by the client (case 5). Test 1 separately shows the broader no-auth baseline.
Rockwell's specific CIP Security implementation behaves identically"enabling CIP Security on real Rockwell hardware remediates CVE-2021-22681 exactly this way"LEAD, sourced not verifiedthis is Rockwell's own advisory (PN1550) language — "When properly deployed, CIP Security remediates this vulnerability... does not make use of any hardcoded keys" — not something we've independently confirmed against real Logix hardware. We tested the principle their advisory describes, not their exact wire-level implementation.