# CVE-2023-36906 — Windows KSP `ncryptprov.dll` Out-of-Bounds Read via an Un-terminated "Use Context" Provider Property

---

## Summary

| | |
|---|---|
| **Product** | Microsoft Windows — `ncryptprov.dll` (Microsoft Software Key Storage Provider / KSP) |
| **CVE ID** | CVE-2023-36906 |
| **Impact** | Information Disclosure (kernel/service heap leak; sandbox-escape enabler) |
| **MSRC severity** | Important |
| **CWE** | CWE-170: Improper Null Termination → out-of-bounds read |
| **Patch Date** | August 8, 2023 |
| **Pre-patch binary** | `ncryptprov.dll` 10.0.22621.1928 (Jun–Jul 2023) — SHA256 `879a649afbbd2c83519a0308d06178ae1b9e2a2c7ed236e4a4368a7761270beb` |
| **Post-patch binary** | `ncryptprov.dll` 10.0.22621.2134 (Aug 8 2023 fix) — SHA256 `9072392ae7ff191ed806eda9f46822326fded010a204b80a8beb6d5b86bfec61` |
| **Fix gating** | **None** — unconditional (no CFR/KIR flag) |

---

## Product Description

`ncryptprov.dll` is the **Microsoft Software Key Storage Provider**, the default
CNG KSP that stores and operates on private keys. It is driven through the CNG
Key Isolation service (`keyiso.dll`, hosted in **lsass**), whose RPC surface —
including `SrvCryptGetProviderProperty` / `SrvCryptSetProviderProperty` — is
reachable from **AppContainer** integrity-level processes (browser and Adobe
Reader renderer sandboxes). That reachability is why an info-leak here is a
sandbox-escape *enabler*: the analysis chained it with the CNG UAF
(CVE-2023-28229) to defeat lsass ASLR/CFG and load a DLL into lsass.

A provider carries a property bag. The **"Use Context"** property is
client-defined: the caller supplies its size and full content, `ncryptprov`
stores it, and a later query returns it.

---

## Vulnerability Summary

`SPCryptSetProviderProperty` stored the "Use Context" buffer at exactly the
client-supplied length, **with no null terminator**. `SPCryptGetProviderProperty`
read it back as a **wide string** — scanning for a `L'\0'` terminator to compute
the length, then copying that many bytes to the caller:

```c
// SPCryptGetProviderProperty (ncryptprov.dll) — the read side (from the analysis)
v17 = *(QWORD *)(provider + 0x20);          // stored "Use Context" buffer
v13 = 0;
do { ++v13; } while (*(WORD *)(v17 + 2*v13));  // *** scans for a NUL — no bound ***
v16 = 2*v13 + 2;
memcpy(a3, v17, v16);                        // returns v16 bytes to the caller
```

If the stored property contains **no embedded null**, the `while` scan walks off
the end of the allocation and `memcpy` returns the buffer plus **adjacent heap**
to the (sandboxed) caller — an out-of-bounds read / information disclosure. The
caller controls the property's size and content, so it can size the property to
land next to a target object and leak it. It was placed beside a
memory-buffer object to leak a **provider-object pointer**, the ASLR break that
made CVE-2023-28229 exploitable.

---

## Prerequisites and Constraints

- **Local, from inside a sandbox.** Reachable from an AppContainer / restricted
  token via the CNG Key Isolation RPC interface → KSP. No elevated rights.
- The attacker controls the "Use Context" property size and bytes (hence both the
  over-read length and the heap grooming around it).
- Primitive is an out-of-bounds **read**: disclosure of adjacent
  process-heap memory in **lsass** (the KSP host), not a write. Its value is as an
  ASLR/CFG-defeating leak that chains into a separate EoP.

---

## Vulnerability Details

### Call Chain

```
Sandboxed (AppContainer) process:
  NCryptSetProperty(provider, "Use Context", buf[N])   // store, no terminator
  NCryptGetProperty(provider, "Use Context", ...)      // read back
        ↓  RPC to CNG Key Isolation (lsass)
  keyiso!SrvCryptSetProviderProperty / SrvCryptGetProviderProperty
        ↓  KSP
  ncryptprov!SPCryptSetProviderProperty                // stores buf, unterminated  (BUG SOURCE)
  ncryptprov!SPCryptGetProviderProperty                // NUL-scan over-reads        (LEAK SITE)
```

### Root Cause

The store and the read disagree about termination. The property is stored as raw
bytes of a client-chosen length, but read back as a NUL-terminated wide string.
With no guaranteed terminator, the read's length computation runs past the
allocation (CWE-170 → out-of-bounds read).

### The patch (confirmed — diff, .1928 → .2134)

The August build fixes it on the **store** side: `SPCryptSetProviderProperty`
now over-allocates by one WCHAR, bounds-checks the size, and writes an explicit
terminator so the buffer is always NUL-terminated:

```c
// SPCryptSetProviderProperty (ncryptprov.dll 10.0.22621.2134) — PATCHED, from our diff
if ((param_3 == NULL) || (0x7ffffffd < uVar3)) goto error;   // new upper bound (leave room for NUL)
...
buf = RtlAllocateHeap(heap, 0, _Size + 2);                   // *** +2 bytes for a WCHAR terminator ***
*(WORD *)(buf + (param_4 & 0xfffffffe)) = 0;                 // *** write L'\0' at the end ***
memcpy(buf, param_3, _Size);                                 // then copy the client content
```

Because the stored "Use Context" property is now always NUL-terminated, the
`SPCryptGetProviderProperty` scan terminates inside the allocation and the
over-read is gone. `SPCryptSetKeyProperty` receives the same hardening (heavily
rewritten — 5% match), covering the key-property store path as well.

### Patch Completeness Assessment

**Unconditional fix — no Controlled Feature Rollout flag or Known Issue
Rollback toggle** (no `Feature_*` gate in the diff). As with the other 2022–2023
fixes in this corpus (npfs CVE-2022-22715, DHCPv6 CVE-2023-28231), the
remediation is always-on and patch state is determined by file version. Note the
fix is on the **store** side (`Set…Property`); the read side
(`SPCryptGetProviderProperty`) is unchanged, which is why a `keyiso.dll`-only or
read-side-only search misses it.

---

## Detection Guidance

**Behavioural.** A sandboxed (AppContainer) process driving the CNG Key Isolation
RPC to set a "Use Context" provider property whose content has **no embedded
null** and then immediately querying it back — especially repeatedly with sizes
tuned to sit beside other allocations. Legitimate callers store terminated,
modest context blobs.

**Host.** Anomalous CNG KSP activity from renderer-class processes; correlate KSP
property set/get bursts with the process's integrity level. Because the leak
lands in **lsass**, pair with lsass-integrity monitoring — this info-leak is
typically the first stage of an lsass code-execution chain (see CVE-2023-28229).

**Config.** File-version check is sufficient (fix not feature-gated): a patched
`ncryptprov.dll` (≥ Aug 2023 build for the branch) is not vulnerable.

---

## References

- k0shl (Kunlun Lab) — *Isolate me from sandbox: Explore elevation of privilege
  of CNG Key Isolation* (covers CVE-2023-28229 UAF and CVE-2023-36906 info leak).
  `whereisk0shl.top`
- MSRC advisory — CVE-2023-36906 (Windows Cryptographic Services Information Disclosure)
- Full binary diff: `/data/patch_diffs/ncryptprov_dll-cve-2023-36906-ghidriff.md`
- Chained with: CVE-2023-28229 (CNG Key Isolation UAF, keyiso.dll)
