
CVE-2026-11374 탐지 스크립트
CVE-2026-11374의 익스플로잇 선행 조건을 탐지하는 스크립트입니다. 이 취약점은 예측 가능한 SSO 티켓 결함으로, ManageEngine AD360 제품군 전반에서 비인증 계정 탈취로 이어집니다. 범위 내 4개 제품은 공통으로 ManageEngineADSFramework를 사용합니다:
| 제품 | 영향을 받는 빌드 | 수정 빌드 |
|---|---|---|
| ADSelfService Plus | ≤ 6528 | 6529 |
| RecoveryManager Plus | ≤ 6320 | 6321 |
| M365 Manager Plus | ≤ 4816 | 4817 |
| ADAudit Plus | ≤ 8702 | 8703 |
영향을 받는 빌드에서 SSO 티켓은 피해자 로그인 시점에 샘플링된 System.currentTimeMillis()(예측 가능한 타임스탬프)일 뿐이므로, CUSTOM_SSO_TICKET 쿠키를 통해 재생하여 해당 세션을 탈취할 수 있습니다. 이 수정은 티켓을 UUID.randomUUID()(충분히 무작위한 식별자)로 대체합니다. 재생 경로는 제품이 AD360과 통합된 경우에만 도달할 수 있습니다. ADSFilter가 isProductIntegrated()를 기준으로 이를 통제합니다. 이 통제 조건이 바로 이 도구가 확인하는 선행 조건입니다.
참고: 이 탐지기는 취약점 자체가 아니라 선행 조건을 확인합니다.
POTENTIALLY_AFFECTED결과는 취약함이 확인된 판정이 아닙니다. 자세한 내용은 아래를 참조하세요.
예. 운영 환경 및 평가 용도로 제작되었습니다.
1700000000000, 캐시에 상주할 수 없을 만큼 충분히 과거의 밀리초 값)을 전송하므로 어떤 세션도 복구되지 않습니다. 서버는 우리가 보낸 쿠키를 삭제하라고 알려줄 뿐입니다.GET이며, 영향을 받는 유일한 쿠키는 도구가 보내는 일회성 쿠키뿐입니다.CVE-2026-11374의 패치는 티켓 생성 방식(밀리초 → UUID)만 변경했으며, 이 프로브가 사용하는 쿠키 재생 경로는 변경하지 않았습니다. 그 결과, 패치된 설치본은 인증되지 않은 요청에 대해 취약한 설치본과 바이트 단위로 동일하게 응답합니다.
이 도구가 비인증·비파괴적으로 할 수 있는 작업:
할 수 없는 작업:
POTENTIALLY_AFFECTED 결과는 선행 조건이 충족되었음을 의미하며, 호스트가 취약함이 확인되었다는 뜻이 아니라 패치 수준을 검증해야 한다는 뜻입니다.conf/product.conf 읽기, 또는 활성 티켓을 능동적으로 복원(실제 익스플로잇이며 의도적으로 구현하지 않음)이 필요합니다.?build=는 실제 빌드인 경우도 있고 수정 빌드보다 낮게 나오는 고정된 자리 표시자인 경우도 있어서, 수정 빌드보다 낮은 값은 모호하며 도구는 이를 불확정으로 표시합니다. 수정 빌드 이상의 값은 여전히 신뢰할 만한 패치 신호입니다. 자리 표시자는 항상 너무 낮아 그 값에 도달할 수 없기 때문입니다.requests 라이브러리. pip install requests로 설치하세요.# single host (prefer a URL or host:port; ports differ per product)
./cve_2026_11374_check.py https://adssp.example.com:8888
# multiple hosts (scheme optional: https is tried first, then http)
./cve_2026_11374_check.py host-a:8081 host-b:8365
# scan a list, one target per line ('#' comments allowed), compact output
./cve_2026_11374_check.py -f targets.txt --brief
# machine-readable output for pipelines
./cve_2026_11374_check.py -f targets.txt --json > results.json
기본 포트는 제품마다 다릅니다(ADSelfService Plus 8888, ADAudit Plus 8081, M365 Manager Plus 8365, RecoveryManager Plus 8090). 따라서 URL 또는 host:port를 전달하세요. 호스트만 지정하면 기본값 8888이 적용됩니다.
| 플래그 | 설명 |
|---|---|
targets | 하나 이상의 host, host:port, 또는 https://host:port |
-f, --targets-file FILE | 파일에서 대상 읽기(줄당 하나, #은 주석) |
--brief | 대상별 정렬된 한 줄 출력, 많은 호스트를 스캔할 때 유용 |
--json | 구조화된 JSON 결과 출력 |
--timeout SECS | 요청별 타임아웃(기본값: 15) |
--no-build | 긍정 결과에서 추가 빌드 번호 요청 생략 |
--no-color | 색상 출력 비활성화(NO_COLOR 및 비-TTY 환경도 인식) |
AD360 통합 콘솔(자세한 출력, 기본값). 두 번째 줄은 이것이 선행 조건이지 취약 판정이 아님을 명시하며, 세 번째 줄은 빌드에 대한 최선의 힌트입니다:
$ ./cve_2026_11374_check.py https://adssp.example.com:8888
[!] https://adssp.example.com:8888: POTENTIALLY_AFFECTED
ADSelfService Plus: AD360-integrated, CustomSSO replay path active - precondition met. Not confirmed vulnerable; verify patch level (fixed build 6529).
build: 6519 (below fixed 6529 - inconclusive: ?build= may be a stale placeholder or a hotfix)
재생 경로가 활성화되지 않은 동일 제품의 독립형 설치본:
$ ./cve_2026_11374_check.py https://adssp.example.com:8888
[+] https://adssp.example.com:8888: UNAFFECTED
ADSelfService Plus: standalone / not AD360-integrated (no cleanup), so the replay path isn't reachable here. Verify build >= 6529 regardless.
리스트를 호스트당 정렬된 한 줄로 스캔(--brief). 호스트 중 하나라도 POTENTIALLY_AFFECTED이면 종료 상태는 1, 그렇지 않으면 0이며, 스크립트에서 유용합니다. 각 줄의 끝부분에는 식별된 제품이 표시되며, 긍정 결과일 때는 빌드 번호도 함께 표시됩니다:
$ ./cve_2026_11374_check.py -f targets.txt --brief; echo "exit: $?"
POTENTIALLY_AFFECTED https://host-a:8888 ADSelfService Plus 6519
POTENTIALLY_AFFECTED http://host-b:8081 ADAudit Plus 8530
UNAFFECTED http://host-c:8365 M365 Manager Plus
UNAFFECTED https://host-d:443
INCONCLUSIVE http://host-e:8888 ADSelfService Plus
ERROR host-f:8888 timeout
exit: 1
기계가 읽을 수 있는 출력(--json). 각 결과에는 verdict와 그 뒤에 있는 state 및 detail, 식별된 product, 그리고 발견 시 build 객체가 포함됩니다: build는 발견된 번호, fixed_build는 해당 제품의 기준값, patch_hint는 방향성 판단(수정 빌드 이상이면 likely_patched, 그렇지 않으면 inconclusive), note는 간단한 설명입니다:
$ ./cve_2026_11374_check.py https://host-b:8081 --json
[
{
"target": "https://host-b:8081",
"state": "potentially_affected",
"detail": "ADAudit Plus: AD360-integrated, CustomSSO replay path active - precondition met ...",
"product": "ADAudit Plus",
"build": { "build": "8530", "fixed_build": "8703", "patch_hint": "inconclusive", "note": "below fixed 8703 - inconclusive: may be a hotfix" },
"verdict": "POTENTIALLY_AFFECTED"
}
]
| 판정 | 의미 |
|---|---|
POTENTIALLY_AFFECTED | AD360과 통합된 범위 내 제품. CustomSSO 쿠키 재생 경로가 활성화되어 CVE-2026-11374 익스플로잇 선행 조건이 충족됨. 취약함이 확인된 판정이 아니므로 패치 수준을 검증하세요(다음 단계 참조). |
UNAFFECTED | 재생 경로에 도달할 수 없음. 다음 중 하나: 범위 내 제품의 독립형 설치본(AD360 미통합 — 나중에 통합되면 도달 가능해지므로 빌드는 어쨌든 검증할 것), 범위 내 4개 제품이 아닌 ManageEngine ADS 프레임워크 제품, 또는 응답에 범위 내 제품이 전혀 없는 경우(CVE-2026-11374 대상 4개 제품이 아니거나 세션 쿠키를 제거하는 프록시). |
INCONCLUSIVE | HTTP 400 — 신호를 가리는 IAM 속도 제한 잠금일 가능성이 높음. 약 60초 후 재시도. |
ERROR | 연결/타임아웃/TLS 실패. |
| 코드 | 의미 |
|---|---|
0 | 어떤 대상도 POTENTIALLY_AFFECTED를 반환하지 않음 |
1 | 하나 이상의 대상이 POTENTIALLY_AFFECTED |
2 | 사용법 오류(잘못된 인수 / 읽을 수 없는 대상 파일) |
유효하지 않은 티켓과 앱 태그를 임의의 CustomSSO URL(*.do)에 전송합니다:
GET /AppsHome.do
Cookie: CUSTOM_SSO_TICKET=1700000000000; CUSTOM_SSO_APP_TAG_NAME=AD360
AD360 통합 설치본에서는 ADSFilter → CustomSSOFilter → CookieSSOImpl 체인이 해석 분기를 실행하고(태그가 다른 제품을 가리키므로 appName != prodName), 가짜 티켓 해석에 실패하여 쿠키 정리 응답 헤더를 출력합니다:
Set-Cookie: CUSTOM_SSO_TICKET=removed; Max-Age=0; ...
Set-Cookie: CUSTOM_SSO_APP_NAME=removed; Max-Age=0; ...
Set-Cookie: CUSTOM_SSO_APP_TAG_NAME=removed; Max-Age=0; ...
독립형 설치본은 해당 경로를 실행하지 않으므로 정리 동작이 없습니다. 제품은 모든 응답에 설정되는 제품별 고정 Tomcat 세션 쿠키(ADSelfService Plus의 경우 JSESSIONIDADSSP 등)로 식별됩니다. 통합된 ADSSP는 302를 반환하는 반면 ADAudit, M365, RMP는 동일한 프로브에 200을 반환하므로, 검사는 상태 코드가 아닌 헤더를 기준으로 합니다.
| 프로브 응답 | 판정 |
|---|---|
| 정리 헤더 및 알려진 범위 내 제품 쿠키 | POTENTIALLY_AFFECTED |
| 제품 쿠키, 정리 없음, 상태 ≠ 400 | UNAFFECTED (독립형 / 미통합) |
| 범위 내 제품 쿠키 없음, 상태 ≠ 400 | UNAFFECTED (4개 제품 중 하나가 아님) |
| 정리 헤더가 있지만 인식되지 않는 제품 쿠키 | UNAFFECTED (ManageEngine이지만 범위 밖) |
HTTP 400 | INCONCLUSIVE (IAM 속도 제한 잠금일 가능성 높음. 제한 사항 참조) |