Active Directory Certificate Services (ADCS) has emerged as one of the most significant and under-monitored attack surfaces in enterprise Windows environments, as documented by SpecterOps. After observing certificate-based privilege escalation techniques being actively exploited in several cases that the GuidePoint Security DFIR (Digital Forensics and Incident Response) team has worked, specifically the abuse of misconfigured certificate templates to impersonate privileged identities, we decided to investigate what detection opportunities existed at the source: the Certificate Authority (CA) server itself.
In August 2026, CISA published Advisory AA26-237A, describing red team assessments where the ESC1 issue described in this post was used to compromise a domain. As CISA put it:
“The red team also queried the organization’s Active Directory Certificate Service (ADCS) certificate templates. Misconfigured ADCS templates are common and can allow low-privileged accounts to request a certificate on behalf of other users and computers, including highly privileged accounts. The team identified multiple templates with an ESC1 misconfiguration, which allows any user to request certificates for all users and computer accounts.”
CISA’s advice is to disable this feature, tighten who can enroll in these templates and clean up unnecessary permissions. What we described allows you to monitor/detect this type of abuse.
TL;DR – Though often overlooked as a forensic data source, the ADCS CA database stores evidence of privilege escalation requests. However, retrieving that data requires a fix to a timestamp parsing bug in the go-ese library.
The core question we wanted to answer was simple: if an attacker requests a certificate they are not entitled to, does the CA keep a record of that? The answer is yes and more importantly, it keeps a record even when the request fails or is denied. Every certificate request, successful or otherwise, is permanently logged in the CA database. This makes the CA a valuable forensic source that is often overlooked in favor of network or endpoint telemetry.
Our approach was to go directly to that CA database and read it forensically. Without relying on the CA service itself. Without installing additional logging agents. And without requiring any changes to the CA configuration. We wanted something that could be deployed rapidly across multiple CA servers during an incident or as a routine hunt, returning actionable data that an analyst could immediately use to identify suspicious activity.
What seemed like a simple data collection task turned into a bigger technical problem. The tool we used had an unknown bug that made all timestamps in the CA databases unusable. To fix it, we had to patch the underlying library and rebuild the tool from source. In the end, we produced a reliable artifact that shows the complete certificate request history directly from the CA database, including the identity the attacker tried to impersonate, which is the key detail for investigating privilege escalation through certificate abuse.
Velociraptor is an open-source digital forensics and incident response platform that gives analysts the ability to write precise, repeatable collection logic that runs directly on endpoints; reading raw files, executing recovery utilities and joining data across multiple sources in a single artifact execution. Its Velociraptor Query Language (VQL) makes it well suited for exactly this kind of targeted forensic collection and its ability to access locked files through a raw NTFS (New Technology File System) accessor was a critical capability for this work given that the CA database is held open exclusively by the certificate service at all times.
The specific target is the ADCS CA database, an ESE (Extensible Storage Engine) database file located at C:\Windows\System32\CertLog\ by default on the Windows Certificate Authority server. This database contains the complete history of every certificate request the CA has ever processed, across four tables which are relevant for detection:
By reading this database directly from disk and replaying the ESE transaction log to capture any uncommitted recent activity, we can reconstruct a complete, timestamped record of certificate request attempts without touching the CA service. This includes modifying any configuration or relying on Windows Event Log entries, which are frequently incomplete or disabled in practice.
To safely extract data from the ADCS CA database and reconstruct the information required for analysis, we developed a custom VQL artifact for use with Velociraptor.
When we first ran the artifact against a live CA database, everything appeared to be working. Records were returned, requester names and certificate subjects were correct, but every single timestamp field showed 1899-12-30T00:00:00Z. This affected all DateTime columns across the Requests and Certificates tables: submission time, resolution time, revocation time, certificate validity start and certificate validity end. Without accurate timestamps, the artifact was effectively useless for any time-based analysis or correlation.
Our first assumption was that we were applying the wrong conversion in the VQL query. The Velociraptor parse_ese plugin returns DateTime columns as Go time.Time objects and we had been wrapping them in various timestamp conversion functions. We tried timestamp(winfiletime=…), timestamp(epoch=…) and passing the value through directly. None of these changed the output. The date remained 1899 regardless of what conversion was applied.
In order to understand this better, we decided to replicate the attack pattern in a lab environment to generate some of these events.
The test scenario consists of a threat actor having access to a compromised system as a normal Domain User.
Through the misconfigured template, a new certificate was requested by specifying the administrator user as the subject.
By importing the ticket in the current process, we are then able to move laterally to other hosts on the domain.
The issue was in the go-ese library, not our VQL. The library was misreading Windows FILETIME bytes as OLE variant doubles because of a metadata flag set to zero in the ADCS database schema. Direct binary analysis of the database pages confirmed the bytes on disk were correct FILETIMEs all along. A blanket fix broke other databases that legitimately use OLE doubles, so the final solution makes use of the fact that the two encodings produce completely different values, allowing the correct decoder to be selected automatically by inspecting the value itself.
All existing test fixtures continued to pass and the ADCS timestamps decoded correctly.
A pull-request was opened for the fix to the official Velocidex repository of go-ese and it was approved and merged into the codebase.
A portion of the technical work described in this post was carried out with the assistance of an AI coding agent. Tasks that would traditionally require hours of manual effort, like reading and cross-referencing library source code across multiple repositories, performing binary analysis of undocumented database page structures and identifying the root cause of a subtle encoding bug buried in a third-party Go library were completed in a fraction of the time. This allowed our team to significantly reduce the time required to identify the underlying issue, implement a fix for it and create a working VQL artifact.
The VQL artifact developed to look for this behavior is available at the following gist:
https://gist.github.com/sec-pc/a134c4c0441c2e9c66d61488b1402459
The pull request for the DateTime decoder fix has been merged into the official go-ese repository and the Velociraptor go.mod has already been updated to reference the fixed version. This means anyone building Velociraptor from source right now will automatically get the corrected behavior with no additional steps required. The Go toolchain resolves the dependency at build time and the fix is compiled directly into the binary.
For users running the official pre-compiled Velociraptor releases, version 0.76.6 is confirmed to contain the updated go-ese module through which the VQL artifact runs correctly.
All previous versions of the published binaries were built before the go.mod update landed and will not include the fix. These binaries will continue to return 1899-12-30T00:00:00Z for all DateTime fields when parsing ADCS CA databases.
With the underlying timestamp parsing issue now resolved, a pull request was created on the official Velociraptor Artifact Exchange repository:
https://github.com/Velocidex/velociraptor-docs/pull/1275
Once approved, this will allow investigators to directly leverage Velociraptor to detect, hunt for and analyze suspicious certificate request activity within ADCS environments, without requiring any manual installation or custom tooling.
Learn more about how GuidePoint Security can help you detect certificate-based attacks and improve threat hunting and incident response.
