Bit-Manipulation Primitives
Using kernel bitmap functions (RtlSetBit, RtlClearBit, RtlClearAllBits, RtlSetAllBits) as kCFG-compliant exploitation primitives to modify kernel data structures.
Description
The Windows kernel exports bitmap manipulation functions that are valid kCFG targets. After gaining control of an indirect call (e.g., UAF callback, corrupted function pointer), execution can be redirected to one of these functions. By controlling the RTL_BITMAP structure pointer passed as the first argument, individual bits at arbitrary kernel addresses can be set or cleared.
These functions pass CFG validation at every indirect call site — no bypass needed. Modifying individual bits is enough to enable token privilege bits, flip feature flags, or corrupt DACL permission bits, and is less likely to BSOD than writing entire words. Multiple callbacks can be chained sequentially, each targeting a different bit or region.
RTL_BITMAP Structure
typedef struct _RTL_BITMAP {
ULONG SizeOfBitMap; // Number of bits in the bitmap
PULONG Buffer; // Pointer to the bitmap buffer
} RTL_BITMAP, *PRTL_BITMAP;
A fake RTL_BITMAP is placed in controlled memory (sprayed pool object, user-mapped page) with:
SizeOfBitMaplarge enough to cover the target bit indexBufferpointing to the target kernel address (ULONG-aligned)
Patterns
RtlSetBit — Enable a specific bit
// Kernel function signature
VOID RtlSetBit(PRTL_BITMAP BitMapHeader, ULONG BitNumber);
// Attacker crafts:
RTL_BITMAP fakeBitmap;
fakeBitmap.SizeOfBitMap = 256;
fakeBitmap.Buffer = (PULONG)target_kernel_address; // e.g., &token->Privileges.Enabled
// When callback fires with fakeBitmap as arg1 and BitNumber as arg2:
// Effect: sets bit BitNumber at target_kernel_address
// Example: RtlSetBit(&fakeBitmap, 20) enables SeDebugPrivilege
RtlClearAllBits — Zero an entire region
// Kernel function signature
VOID RtlClearAllBits(PRTL_BITMAP BitMapHeader);
// Attacker crafts:
RTL_BITMAP fakeBitmap;
fakeBitmap.SizeOfBitMap = 512; // 512 bits = 64 bytes
fakeBitmap.Buffer = (PULONG)target_dacl_address;
// When callback fires:
// Effect: zeros out SizeOfBitMap/8 bytes starting at Buffer
// Example: zeroing a DACL grants everyone full access
RtlClearBit — Disable a specific bit
// Kernel function signature
VOID RtlClearBit(PRTL_BITMAP BitMapHeader, ULONG BitNumber);
// Attacker crafts similar to RtlSetBit but clears the bit instead
// Useful for: disabling integrity checks, clearing deny ACEs
Exploitation Targets
| Target | Function | Effect |
|---|---|---|
_TOKEN.Privileges.Enabled |
RtlSetBit |
Enable SeDebugPrivilege (bit 20), SeImpersonatePrivilege, etc. |
SepMediumDaclSd DACL |
RtlClearAllBits |
Zero the DACL, removing NtQuerySystemInformation restrictions |
| WIL feature flag state | RtlSetBit |
Flip Feature_RestrictKernelAddressLeaks to disable KASLR hardening |
_EPROCESS.Protection |
RtlClearBit |
Remove PPL protection from a target process |
| ETW provider enable bits | RtlClearBit |
Disable specific ETW providers to blind defenders |
RtlSetAllBits — Enable all bits in a region
// Kernel function signature
VOID RtlSetAllBits(PRTL_BITMAP BitMapHeader);
// Attacker crafts:
RTL_BITMAP fakeBitmap;
fakeBitmap.SizeOfBitMap = 64; // 64 bits = 8 bytes
fakeBitmap.Buffer = (PULONG)&token->Privileges.Enabled;
// When callback fires:
// Effect: sets all SizeOfBitMap bits starting at Buffer
// Example: enables ALL privileges in a token at once
Used in the Devcore CVE-2024-35250 writeup (angelboy) for token privilege escalation — enables every privilege in a single call, less precise than RtlSetBit but faster when multiple privileges are needed.
Delivery Mechanisms
These functions must be called through a controlled indirect call:
_IO_MINI_COMPLETION_PACKET_USERcallbacks: TheApcContextfield is called as a function pointer during I/O completion. PlaceRtlSetBit's address here and control arguments through surrounding structure fields. The completion dispatch site is a valid kCFG indirect call.- Work item callbacks:
_WORK_QUEUE_ITEM.WorkerRoutineset toRtlSetBit, withParameterpointing to a fakeRTL_BITMAP. - Timer DPC routines:
KTIMERDPC routine field redirected to a bitmap function. - IRP completion routines: Corrupted
IoCompletionpointer in an_IRPor_IO_STACK_LOCATION.
Related CVEs
| CVE | Driver | Description |
|---|---|---|
| CVE-2026-21241 | afd.sys |
UAF in notification path → NPNX spray → RtlClearAllBits/RtlSetBit for DACL corruption and privilege escalation |
AutoPiff Detection
spinlock_acquisition_added— Detects patches that extend lock coverage to prevent UAF conditions that enable callback hijackingadded_refcount_guard— Detects lifetime management fixes that close the callback-abuse window
Mitigations
- Kernel Control-flow Enforcement Technology (kCET): Hardware shadow stacks prevent return address corruption but do not block forward-edge abuse via valid CFG targets. kCET alone does not mitigate this.
- kCFG with strict target validation: Current kCFG validates that the target is a valid function entry, but
RtlSetBitqualifies. Type-based CFI would restrict which functions can be called from specific call sites. - Kernel Data Protection (KDP): VBS-backed read-only protection for critical structures (tokens, security descriptors) would prevent bit-manipulation writes. Not yet applied to all targets.
- Secure Pool: Allocating sensitive structures in VBS-protected secure pool regions prevents direct memory corruption.
See Also
- Pool Spray / Feng Shui — required to reclaim UAF slot with controlled data containing fake RTL_BITMAP
- ACL / SD Manipulation — primary target for RtlClearAllBits in KASLR bypass chains
- Token Manipulation — RtlSetBit enables individual privilege bits in token
- Token Swapping — alternative privilege escalation approach (replaces entire token pointer)
- KASLR — WIL feature flag bypass via RtlSetBit