
HikCentral Professional - Pre-Auth License ActiveCode Leak
Before downloading anything, what's already public:
| Source | What it tells us |
|---|---|
| Hikvision security advisory | "Missing authentication checks on API endpoints", advice to upgrade to V2.6.3 / V3.0.1 |
| NVD CVE-2025-39247 | CVSS metrics; vector is network, no auth, scope-changed, confidentiality-high |
| Wiz, ZeroPath, SentinelOne, OffSeq, gbhackers, cybersecuritynews summaries | All restate the advisory; no technical detail, no PoC, no affected endpoint named |
| GitHub PoC aggregators (poc-in-github, 0xMarcio/cve, etc.) | No PoC indexed |
| Forums (ipcamtalk, cctvforum, reddit), torrent indexers | No PoC, no leaked installers; ipcamtalk has a HikCentral usage thread but nothing exploit-related |
So as of analysis date, no public technical write-up exposes the bug. Any reproduction starts from binary diffing.
After CVE-2025-39247 was published the V2.6.2 download page was delisted, but the file on the CDN was never purged. The filename can be recovered from a third-party mirror that indexed the page before delisting (FileHorse — published filename and MD5). With that filename, a plain GET to Hikvision's CDN — using only a normal browser User-Agent and a matching Referer header — still serves it.
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0" \
-H "Referer: https://www.hikvision.com/en/support/download/software/hikcentral-professional-v2-6-2/" \
-O \
"https://www.hikvision.com/content/dam/hikvision/en/support/download/vms/hcp-2-6-2/HikCentral-Professional_Full-Pack_V2.6.2.202501211507_Win_x64_Installer.exe"
Result:
76d42e7cb16dc0e177b9a35d0fed7ced — matches the FileHorse-published value, confirming the genuine Hikvision-signed installer (not a third-party rebundle)HTTP/2 200, content-type: application/x-msdownload, eo-cache-status: HIT, age: 2520395 (≈ 29 days in the Tencent EdgeOne edge cache without eviction)Side observation worth reporting to Hikvision PSIRT: the "delisting" of the V2.6.2 page is cosmetic. The orphaned file is reachable on the CDN with no auth and no signed-URL gate. V2.5.1 and V2.6.0 Full Packs respond the same way.
Currently linked from the V2.6.3 download page; same retrieval method:
https://www.hikvision.com/content/dam/hikvision/en/support/download/vms/hcp-2-6-3/HikCentral-Professional_Base-Pack_V2.6.3.202508280142_Win_x64_Installer.exe
Still linked from the V2.6.2 download page (Hikvision want users to apply it):
https://www.hikvision.com/content/dam/hikvision/en/support/download/vms/cve-2025-39247-security-vulnerability-patch/HikCentral-Professional_CVE-2025-39247_FixPack_V2.3.1-V2.6.2V3.0.0_20250904.exe
All three are InstallShield-style PE wrappers. 7z peels them in two passes:
# pass 1 — extract PE resources
7z x -o./extracted/v262/pe downloads/<v2.6.2 installer>
7z x -o./extracted/v263/pe downloads/<v2.6.3 installer>
# pass 2 — extract the nested 7-Zip streams hiding in PE resources
# (note: the resource-type label says "ZIP" but the byte signature is 7-Zip)
for ver in v262 v263; do
for z in extracted/$ver/pe/.rsrc/2052/ZIP/*; do
sz=$(stat -c %s "$z"); [ "$sz" -lt 1048576 ] && continue
7z x -o"extracted/$ver/payload/$(basename $z)" "$z"
done
done
Both installers expand into roughly two dozen named payload archives. The top-level dirs reveal the architecture:
| Archive | Contents |
|---|---|
246/Nginx + 246/www | Nginx web tier (the front door) and the SPA web UI |
244/bin | Native C++ service binaries + certs |
240 | Bundled PostgreSQL + DB init scripts |
238 | Bee* runtime (BeeAgent, BeeGuard, …) |
282 | Application services and addons (the bulk of the C++ backend code) |
281, 283-284, 396, 398-399, 513, 520, 538-541, 573 | Smaller addons, plugins, upgrade/uninstall stubs |
Crucially, there are no Java JARs/WARs anywhere. The backend is C++ on Nginx — important because it tells you up front that any auth flaw will be in compiled binaries, not in WAR/JAR bytecode where decompilation is trivial.
# Build inventories
for ver in v262 v263: find . -type f -print0 | xargs -0 md5sum | sort -k2 > inv_$ver.txt
# Sets: common-path + different MD5 → the patched files
v262 = {ln[34:]: ln[:32] for ln in open("inv_v262.txt")}
v263 = {ln[34:]: ln[:32] for ln in open("inv_v263.txt")}
common = set(v262) & set(v263)
changed = [p for p in common if v262[p] != v263[p]]
Result: 239 changed files in common paths. Distribution:
| Bucket | Count | Comment |
|---|---|---|
246/www/*.js (Web UI chunks) | ~200 | Mostly version-bumped asset hashes; ignore |
246/Nginx/conf/nginx_location.conf | 1 | Single-file Nginx config delta — start here |
246/Nginx*/install.bat | 6 | Install scripts, unrelated |
244/bin/*.{exe,dll} | 6 | Native binaries (DistributionFilter.dll, FilterChain.dll, media tools) |
282/*.{exe,dll} | 55 | Application services (the largest cluster — platform.dll, PersonCredential.dll, baseacs.*, …) |
240/bin/pg_* | 6 | Postgres rebuild, unrelated |
284/hplugin/dahua_plugin/* | 4 | Vendor SDK refresh (+10.97 MB) — unrelated |
284/hplugin/onvif_plugin/* | 4 | Vendor SDK refresh (+0.99 MB) — unrelated |
| upgrade/uninstall stubs, crash reporters | ~30 | Same-size PE timestamp rebuilds, ignore |
After filtering out vendor-SDK refresh, build-system timestamp drift, and pure cosmetic asset bumps, the actual security-relevant deltas reduce to:
282/ (most prominently platform.dll, the HCMP backend service, +57 KB)diff -u nginx_location.conf between V2.6.2 and V2.6.3 produces exactly one hunk: a brand-new location = block in V2.6.3.
#禁止非127.0.0.1和::1的重置密码 ← "Forbid non-127.0.0.1/::1 password reset"
location = /ISAPI/Bumblebee/Platform/V0/Permission/ChangeDefaultUserPassword {
if ($remote_addr ~ ^(127\.0\.0\.1|::1)$) { set $allowed 1; }
if ($allowed != "1") { return 403; }
if ($scheme = "http") { proxy_pass http://http_backend; }
if ($scheme = "https") { proxy_pass http://http2_backend; }
}
That single 21-line addition is the entire CVE-2025-39247 fix at the front-door tier, and it tells you everything:
PUT /ISAPI/Bumblebee/Platform/V0/Permission/ChangeDefaultUserPassword/ISAPI/Bumblebee/Platform/V0/* proxy directive to the backend with no remote-address restriction and no Nginx-level authentication check.The Chinese comment matters: it translates literally to "Forbid password reset from non-127.0.0.1/::1".
The Web UI JavaScript (minified, in 246/www/Portal/*.js) calls the endpoint as: