[PL] HEVD Stack Buffer Overflow #6 - Post-scriptum
W tym poście zamieszczam informacje, które uznałem za mniej istotne, niezasługujące na znalezienie się w postach głównych.
Dlaczego to nie działa?
Udało nam się podwyższyć przywileje z poziomu użytkownika do poziomu SYSTEM na najnowszym obrazie (w momencie pisania tego bloga) Windowsa 10. Czy to oznacza, że możemy załadować sterownik na dowolnym komputerze by ominąć zabezpieczenia windowsa? Nie
- Zaczynając od Windowsa 10 wersji 1607, każdy sterownik musi być podpisany aby zostać wczytany do systemu. Jedynym powodem dla którego mogłem wczytać ten sterownik bezproblemowo jest fakt, że przy używaniu narzędzia WinDbg, Windows znajdował się w stanie Test Mode który pozwala na wczytywanie sterowników bez zweryfikowanego podpisu cyfrowego. Nie miałem także włączonej funkcji Core Isolation / Memory Integrity.
- Wczytanie sterownika wymaga przywilejów. Skrypt wczytujący musi być uruchamiany z poziomu administratora, stąd aby zwiększyć uprawnienia z poziomu użytkownika, sterownik musiałby być wcześniej wczytany
- Sprawdziłem zakładkę Core Isolation na mojej maszynie z Windowsem 11 i znalazłem ciekawy toggle.
Ze strony supportu Microsoft LINK
Hardware enforced stack protection works by preventing attacks that modify return addresses in kernel-mode memory to launch malicious code. This security feature requires a CPU that contains the ability to verify the return addresses of running code. When executing code in kernel-mode, return addresses on the kernel-mode stack can be corrupted by malicious programs or drivers in order to redirect normal code execution to malicious code. On supported CPUs, the CPU maintains a second copy of valid return addresses on a read-only shadow stack that drivers cannot modify. If a return address on the regular stack has been modified, the CPU can detect this discrepancy by checking the copy of the return address on the shadow stack. When this discrepancy occurs, the computer prompts a stop error, sometimes known as a blue screen, to prevent the malicious code from executing.
Po włączeniu tej funkcji na hoście - exploit w VM przestał działać! Otrzymujemy ten sam kod co w przypadku skutecznej ochrony SMEP - UNEXPECTED_KERNEL_MODE_TRAP
Jako że jest to rozwiązanie hardware’owe (Control-Flow Enforcement Technology dla Intela lub Shadow Stack dla AMD), może być bardzo ciężkie do obejścia.
Alternatywny powrót
W przygotowanej implementacji zastosowaliśmy powrót bezpośrednio do user-landu przy pomocy sysretq. Wspomniałem również o alternatywnej metodzie kontynuacji poprawnego działania sterownika. Potencjalną możliwością byłby powrót rozkazem ret wykorzystując adres powrotu handlera - BufferOverflowStackIoCtlHandler.
Jako że znajduje się on 40 bajtów nad adresem powrotu naszej funkcji. Jest to opcja jak najbardziej dostępna.
Problemem są natomiast nadpisane rejestry. Potencjalną możliwością obejścia napisywania rejestrów znajdujących się w shadow space nad adresem powrotu wywoływanej funkcji jest znaczące zmniejszenie wartości RSP przy pierwszym gadżecie. Jeżeli udałoby nam się znaleźć gadżety typu sub rsp, XX. add rsp, -XX, xchg rsp, xxx, pop rsp, moglibyśmy wykonywać kolejne skoki ze “środka” stosu, tym samym zachowując wartości rejestrów RBX, RSI, RDI. Nie jestem świadomy żadnego sposobu na zachowanie wartości rejestrów R12, R14, R15, które znajdują się pod adresem powrotu.
Odnoszę się do obrazu stosu przed funkcją memcpy. Artykuł 1
Więcej o KVA Shadow
Na moment o KVA Shadow wspomniałem w Artykule 4.
KVA Shadow to fix dla podatności Meltdown / Spectre zweryfikowanych dla procesorów Intela i niektórych ARM-ów. Często nazywany również KPTI (implementacja linuxowa). Polega on na odseparowaniu przestrzeni adresowej użytkownika od przestrzeni adresowej kernela. Dzieje się tak poprzez stosowanie oddzielnych wartości rejestru CR3. Jedna dla wykonywania user-mode, druga dla wykonywania rozkazów kernel-mode.
W skrócie:
- Gdy przestrzeń adresowa jest w trybie user, jedyny widoczny dla nas kod kernelowy to ten potrzebny do przejścia w tryb adresowania kernel
- Gdy przestrzeń adresowa jest w trybie kernel, widzimy zarówno struktury kernelowe, jak i te programu.
Tutaj znajduje się dużo informacji prosto ze “źródła”: LINK
Posiada on również inne swoje ‘quirki’ m.in. pamięć użytkownika jest oznaczana jako niewykonywalna.
Użytkownikowi mdanilor udało się to zabezpieczenie obejść. Link do jego bloga
Aby wiedzieć czy nasza maszyna korzysta z funkcji KVA Shadow przy przechodzeniu do kernel-mode, możemy sprawdzić gdzie prowadzi zawartość rejestru LSTAR która ładowana jest do rejestru RIP przy rozkazie syscall.
Linki do bardzo merytorycznych materiałów i innych przydatości:
- https://kristal-g.github.io/2021/05/08/SYSRET_Shellcode.html
- https://idafchev.github.io/blog/wrmsr/#4-kernel-page-table-isolation
- https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation
- https://vuln.dev/windows-kernel-exploitation-hevd-x64-stackoverflow/
- Książka windows system internals 7th edition part 1 “Chapter 6 I/O System”
- https://www.vergiliusproject.com/
- https://zerosum0x0.blogspot.com/2019/11/fixing-remote-windows-kernel-payloads-meltdown.html#kva_kva
- https://www.coresecurity.com/sites/default/files/2020-06/Windows%20SMEP%20bypass%20U%20equals%20S_0.pdf
- https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170

