Skip to content

PipeAttribute kernel address leak (FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE)

Named-pipe connection attribute'ları bir non-paged-pool attribute list'inde saklanır ve FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE üzerinden olduğu gibi geri okunur; bir "ghost chunk" örtüşmesiyle birleştiğinde bu, freed bir pool chunk'ının Flink'ini (bir kernel pointer) user mode'a yankılar.

Mechanism

npfs.sys, bir named-pipe server'ının bir connection'a arbitrary adlandırılmış attribute'lar iliştirmesine izin verir. Bunlar NpSetAttributeInList() ile yazılır (client PID/session/computer-name'i saklayan aynı makine) ve undocumented control code FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE (yani GetNamedPipeClientProcessId()'nin arkasındaki motor) ile byte byte geri okunur.

Note

Leak primitive'i iki gerçeğe dayanır. (1) Olduğu gibi yankı: bir attribute bir pool allocation'ında saklanır ve FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE saklanan byte'ları değişmeden döndürür — dolayısıyla o pool memory'sini her ne işgal ediyorsa user mode'a açığa çıkar. (2) Kontrol edilebilir allocation size'ı: attribute değerinin uzunluğu pool chunk size'ını belirler, dolayısıyla bir attacker attribute storage'ının belirli bir Dynamic Lookaside / pool bucket'ına düşmesini sağlayabilir. "ghost chunk" hilesi sonra bir örtüşme mühendisler: LIST_ENTRY.Flink/Blink'i hâlâ kernel address'leri tutan freed bir pool chunk'ı (bir "ghost"), yeniden-spray'lenmiş bir pipe'ın data bölgesiyle fiziksel olarak çakıştırılır. Attribute'u okumak (ya da PeekNamedPipe) o stale Flink byte'larını döndürür — kernel-ASLR'ı yenen ve bir pool-corruption exploit'ini bootstrap eden bir kernel-pointer infoleak.

PID-spoofing varyantı (Project Zero) aynı mekanizmanın write tarafını suistimal eder; kernel-address-leak varyantı pool içeriğini exfiltrate etmek için read tarafını suistimal eder.

Walkthrough

Kavramsal dizi (Pwn2Own cldflt.sys chain'inde kullanıldığı gibi):

// 1. Create a named pipe whose data/attribute allocation lands in the target
//    pool bucket (e.g. a 0x1D0-byte write needs a 0x210 block).
HANDLE hServer = CreateNamedPipe(L"\\\\.\\pipe\\x", PIPE_ACCESS_DUPLEX, ...);

// 2. Free a "ghost" chunk of the SAME size so it is popped from the Dynamic
//    Lookaside and handed back to the next same-size allocation...

// 3. ...re-spray a pipe so its data region OVERLAPS the freed ghost's
//    DQE (its LIST_ENTRY still contains a kernel Flink pointer).

// 4. Read it back: the stale Flink (a kernel address) is returned to user mode.
DWORD pid;                          // GetNamedPipeClientProcessId path, or:
DeviceIoControl(hServer, FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,
                attrName, nameLen, outBuf, outLen, &ret, NULL);
// outBuf now contains leaked kernel-pool bytes -> a kernel pointer.
Boyut hesabı neden önemli

"Creating a Named Pipe with 0x1D0 bytes of data requires a 0x210 block, so the ghost chunk is popped from the Dynamic Lookaside and returned. The DQE of this ghost pipe physically overlaps with the data region of the respray pipe. When PeekNamedPipe is called on the respray pipe, the Flink value of the ghost DQE (a kernel address) is leaked to user mode." Sızdırılan pointer, KASLR'ı kırmak ve sonraki write primitive'i için hedefleri hesaplamak üzere kullanılır.

Warning

Sızdırılan Flink, sabit bir image base'i değil pool'un içini gösterir — exploit base'i/istenen object'i ondan türetmek zorundadır, dolayısıyla leak groom ettiği pool layout bilgisiyle eşlenir.

Detection

  • Hızla birçok aynı-boyutlu named pipe oluşturup/free eden ve ardından FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE/PeekNamedPipe çağıran process'ler şüphelidir (bir grooming + leak loop'u).
  • Pool corruption telemetrisi / Special Pool örtüşmeyi yüzeye çıkarabilir.

Mitigation

  • Segment Heap pool randomization ve Low-Fragmentation-Heap randomization, ghost örtüşmesinin gerektirdiği öngörülebilir adjacency'yi azaltır.
  • Kernel-ASLR artı npfs.sys attribute işlemenin genel hardening'i; KCFG/HVCI sızdırılan bir pointer'ın downstream'de neyi mümkün kıldığını sınırlar.

References