
CVE-2021-22681의 하드코딩 키 결함을 재현하고 시뮬레이션된 EtherNet/IP 환경에서 장치별 상호 TLS/CRL 수정을 검증하며 IEC 62443-4-2 매핑을 포함하는 개념 증명(PoC)
실행 가능한 스크립트 4개. 실제 EtherNet/IP 프로토콜 트래픽, 실제 암호화, 체인 어디에도 Rockwell 소프트웨어나 라이선스가 전혀 없음. 주장을 문서로 정리하기 전에 검증하기 위해 만들어진 것이지, 맹목적으로 옹호하기 위한 것이 아님.
출처: 2026-07-31 제작, 미네소타주 브레이햄(Braham, MN) WWTF(폐수처리시설)에 대한 병행 조사와 함께 — 2026년 7월 26~27일 미네소타 물 부문 합동 공격 사건에서 공개적으로 알려진 4개 시설 중 하나. 해당 사고의 맥락은 CISA 권고 AA26-097A(FBI/CISA/NSA/EPA/DOE/USCYBERCOM/재무부 합동; 2026-04-07 발행, 2026-07-22 확장)에 있으며, 이는 진행 중인 IRGC 연계 CyberAv3ngers 캠페인을 다룹니다. 귀속 주의사항, 정확히 유지함: 어떤 기관도 특히 미네소타 사고를 해당 그룹으로 공식적으로 지목하지 않았습니다 — 오직 더 넓은 범위의 진행 중인 캠페인만이 그렇습니다. 이 폴더는 기술 수정 측면이며, 의도적으로 사고 조사와 분리되어 있습니다.
공개 패킷의 성패는 이 셋을 한데 뭉개지 않느냐에 달려 있습니다. 각각 다른 수정 방법을 갖고 있기 때문입니다:
여기서 입증하는 수정 — 장치별 신원 바인딩 (Test 3) — 플릿 키 실패를 해결합니다.
두 행을 혼동하지 마십시오. 원칙은 입증되었습니다. 공급업체의 특정 구현은 신뢰할 만하지만(그들이 명시한 설계 의도 자체이므로) 실제 장비에 대한 우리의 검증은 이루어지지 않았습니다.
test1_baseline_vulnerable.py — 무인증 기준선, 실시간실제 EtherNet/IP PLC 시뮬레이터(cpppo, Allen-Bradley ControlLogix 에뮬레이션)를 가동하고 자격 증명 없이 제어 태그를 읽고 씁니다. (범위: 이는 캠페인이 기댄 광범위한 무인증 기준선입니다 — CVE-2021-22681의 특정 하드코딩 키 메커니즘이 아닙니다. 의도적으로 구별하여 유지함; 위의 "세 가지 서로 다른 실패" 참조.)
python test1_baseline_vulnerable.py
test2_shared_secret_fails.py — 플릿 키 결함의 형태 (내러티브 다리, 테스트 아님)두 엔드포인트가 하나의 정적 키를 보유합니다; 장치 A의 자격 증명이 변경 없이 장치 B를 엽니다 — CVE-2021-22681의 만능 키(one-key-fits-all) 결함과 가장 구조적으로 유사한 형태입니다. 하지만 이는 동어반복입니다: 두 핸들러 모두 해당 키를 수락하도록 구성되어 있으므로 실패할 수 있는 실행 경로가 없습니다. 코드가 존재로 정의하지 않는 어떤 것도 증명하지 않습니다. Test 1에서 Test 3으로 가는 내러티브 다리로 유지됩니다; 증거적 가치가 없으며 의도적으로 증명 근거로 삼지 않습니다.
python test2_shared_secret_fails.py
test3_mutual_tls_fix.py — 수정, 음성 대조군 및 양방향 포함실제 CA, 개별적으로 고유한 두 장치 인증서 — 신원은 폐기 예정(deprecated) CommonName이 아닌 SubjectAlternativeName에 바인딩됨. 5가지 케이스, 모두 실행됨:
device-a를 바인딩하는 클라이언트에 의해 거부됩니다(실제 SAN에 대한 check_hostname). 상호적 — 양쪽 끝 모두 신원을 바인딩합니다.python test3_mutual_tls_fix.py
test4_revocation.py — 수명 주기 단계: 폐기실제 CA 서명 CRL(인증서 폐기 목록). 클라이언트 자격 증명(engineer-1)이 허용됩니다; 그런 다음 그 일련번호가 CRL에 추가되고, 동일한 여전히 유효하고 만료되지 않은 CA 서명 자격 증명이 거부됩니다 — CR 1.8 / 1.9 폐기 조항의 경험적 내용입니다. 고유성(Test 3) ≠ 폐기 가능성; 자격 증명을 되돌릴 수 있음을 보여줍니다.
python test4_revocation.py
test4_revocation.py); 교체 — 아직 아님. 장치별 고유성(Test 3)은 폐기 가능성과 같지 않습니다; Test 4가 그 격차를 메웁니다 — 여전히 유효하고 만료되지 않은 CA 서명 자격 증명이 폐기 전에는 허용되고 폐기 후에는 거부됩니다. CA 서명 CRL이 이제 해당 일련번호를 나열하기 때문입니다. 교체(대체 자격 증명을 재발급하고 이전 것을 폐기)는 밀접하게 관련되어 있으며 동일한 PKI로 가능하지만, 여기서 별도로 입증되지는 않습니다 — 따라서 "장치별 신원 바인딩"이 조용히 "교체 해결됨"으로 확장되어서는 안 됩니다.presented == KEY, identity in SAN)는 상수 시간이 아닙니다. 여기서는 악용할 수 없습니다 — 비교되는 값은 공개에 가까운 신원 문자열이고 비교가 실행되기 전에 TLS가 이미 실제 암호화 인증을 수행했기 때문입니다 — 그러나 이 패턴이 실제로 중요한 곳에 복사되므로 플래그를 표시합니다.python -m venv venv
venv\Scripts\activate # or: source venv/bin/activate
pip install -r requirements.txt
62443-4-2_SL2_MAPPING.md (CR 1.2 / 1.8 / 1.9 / 1.14 / 3.1, 정직하게 등급화되었고 모든 격차가 명명됨; CR 1.2, CR 1.9, CR 1.8의 발급/검증/폐기 단계는 이제 입증됨). PSIRT([email protected] / [email protected])에 제출하기 전: 구매한 IEC 62443-4-2:2019 사본으로 각 CR의 규범적 본문을 대조 검증하십시오.PHASED_ROLLOUT.md (0단계 출혈 멈추기 · 1단계 망 분리 · 2단계 보완 통제 · 3단계 CIP Security/PKI, 하드웨어 허용 시 · 4단계 운영). 소규모 유틸리티에 적합한 규모; CIP Security가 하드웨어에 의해 제한된다는 점을 정직하게 명시하므로 0~2단계가 어쨌든 위험 감소를 담당합니다.여기에 있는 모든 외부 식별자는 훈련 데이터에서 기억해낸 것이 아니라 2026-07-31에 실제 소스에서 직접 가져온 것입니다: AA26-097A(다중 출처, WaterISAC / Tenable / SecurityWeek 포함), 공개된 4개 피해 시설 중 하나인 Braham, CyberAv3ngers/IRGC, PN1550이 실제 Rockwell 권고임을 확인했으며 2행 인용문을 축어적으로 대조 확인함("When properly deployed, CIP Security remediates this vulnerability" + "does not make use of any hardcoded keys"), "cannot be mitigated with a patch" 축어적 확인, CVSS 10.0 / CRITICAL (v3.1), CISA 추적 번호 ICSA-21-056-03, 62443-4-2 CR 1.8(PKI) + CR 3.1(통신 무결성) 정확성 확인.
패킷 작성 규율: 제출 시점에 모든 식별자를 1차 출처에서 다시 검색하십시오. 권고는 번호가 다시 매겨지고, 확장되고, 대체됩니다 — AA26-097A는 이미 한 차례 확장된 바 있습니다 — 따라서 "2026-07-31에 검증됨"은 "제출 시점에 검증됨"이 아닙니다. CR별 공식 62443-4-2 매핑 전체는 이제 작성되었습니다(62443-4-2_SL2_MAPPING.md) — 남은 것은 매핑 자체를 작성하는 것이 아니라, 제출 전에 구매한 표준 사본으로 인용된 규범적 본문을 다시 대조 확인하는 것입니다.
l0gic — Patrick Crosby · 2026-07-31.
강화 기록: Test 3은 음성 대조군(case 4, 단순 발동이 아닌 필요성 증명), 역방향 케이스(case 5, 상호 바인딩), SAN 기반 신원(CN이 아님)을 포함하도록 강화되었으며, 이후 5개 케이스를 모두 재실행하여 재검증되었습니다; Test 4(CRL 폐기)가 추가되었습니다. Test 1/2 설명은 세 가지 실패 클래스를 구별할 수 있도록 규모를 조정했습니다; Test 2는 "테스트"에서 내러티브 다리로 강등되었습니다; 폐기 및 상수 시간 범위 경계가 추가되었습니다. 인용 체인은 1차 출처에서 검색되었으며 제출 시 재검색하도록 스탬프가 찍혔습니다.
| 주장 | 수준 | 근거 |
|---|
| 아키텍처 원칙 | "플릿 전반의 단일 공유 비밀은 한 번의 유출로 플릿 전체가 손상됩니다; 장치별 신원 바인딩 인증이 이를 차단합니다" | 입증됨 | 실제 실행 코드로 입증됨 — 검사가 단순히 발동한다는 사실만이 아니라 필수적임을 증명하는 음성 대조군 포함: 엄격한 엔드포인트에서 장치 B의 진짜 CA 유효 인증서는 신원 확인에서 거부되지만(Test 3 · case 3), CA 유효성-만 확인하는 엔드포인트에서는 동일한 인증서가 허용됩니다(case 4 — 대조군) → "유효한 CA 서명만으로 == 플릿 전체 접근 == TLS 옷을 입은 Test 2." 바인딩은 역방향에서도 성립합니다: 유효한 플릿 인증서를 제시하는 악성 서버는 클라이언트에 의해 거부됩니다(case 5). Test 1은 더 넓은 무인증 기준선을 별도로 보여줍니다. |
| Rockwell의 특정 CIP Security 구현도 동일하게 동작함 | "실제 Rockwell 하드웨어에서 CIP Security를 활성화하면 CVE-2021-22681을 정확히 이런 방식으로 해결합니다" | 단서, 출처 확보 · 미검증 | 이것은 Rockwell 자체 권고(PN1550)의 문구입니다 — "When properly deployed, CIP Security remediates this vulnerability... does not make use of any hardcoded keys" — 실제 Logix 하드웨어로 독립적으로 확인한 것이 아닙니다. 우리는 해당 권고가 설명하는 원칙을 테스트했지, 정확한 와이어 레벨 구현을 테스트한 것은 아닙니다. |