
Implementazione di Beacon Object File per il bypass UAC tramite deserializzazione di Event Viewer
Questo è un'implementazione in Beacon Object File del bypass UAC tramite deserializzazione di Event Viewer scoperto da @orange_8361 e del POC messo insieme da CsEnox.

Testato su x64 Win10/Win11
Questo bypass UAC esegue le seguenti azioni che dovrebbero essere considerate in riferimento all'OPSEC:
-1. Scrive un file binario in %LOCALAPPDATA%\Microsoft\Event Viewer\RecentViews
-2. Chiama ShellExecute() per avviare mmc.exe / Event Viewer
--A. Event Viewer si aprirà nella GUI!
--B. Event Viewer chiamerà cmd.exe
---a. Cmd.exe chiamerà Taskkill per chiudere mmc.exe
---b. Cmd.exe stamperà un messaggio di errore nella finestra della console a volte aperta, con l'intento di far credere all'utente che non ci sia nulla di sbagliato
---c. Cmd.exe eseguirà qualsiasi altro comando fornito dall'utente
-3. Il file binario viene cancellato da %LOCALAPPDATA%\Microsoft\Event Viewer\RecentViews
Seguendo la dimostrazione originale e il POC di CsEnox, ysoserial è stato utilizzato per creare un payload iniziale:

ysoserial.exe -o raw -f BinaryFormatter -g TextFormattingRunProperties -c "taskkill /f /im mmc.exe >nul && echo Windows has Recovered from an Unexpected Error. You may Close this Window. &&" > cmd.bin
Questo bypass UAC funziona invocando mmc.exe, che si apre sullo schermo e deve essere chiuso. Purtroppo non ho trovato un modo per avviare mmc.exe senza che la GUI si apra; ho esaminato CreateProcess() e il flag CREATE_NO_WINDOW, ma CreateProcess() non funziona bene con UAC. I post su StackOverflow su questo argomento mi hanno indirizzato all'API ShellExecuteA() che ha il flag SW_HIDE (e altri), ma ciò non ha dato frutti. Il lampeggio di Mmc.exe sullo schermo sembra inevitabile.
Ysoserial chiama cmd.exe /c, quindi questo viene usato per chiamare taskkill al fine di chiudere mmc.exe. && viene usato per concatenare comandi in modo che l'azione desiderata da eseguire come Amministratore possa essere eseguita. Durante i test ho scoperto che in alcuni casi quell'azione teneva aperto il prompt cmd.exe generato da mmc.exe; questo accade quando si chiamano payload Local Injector (normali), come il payload eseguibile predefinito di Cobalt Strike. Per risolvere questo problema, ho inviato l'output del comando taskkill (che in precedenza veniva stampato nel cmd.exe tenuto aperto) a /dev/null, e ho stampato a schermo un messaggio riguardante un errore che è stato gestito, nel tentativo di far sì che questo comportamento sospetto non allarmi un utente inesperto.
Payload che generano un processo, vi iniettano e poi escono non tengono aperta la finestra cmd.exe, quindi il messaggio non è necessario. Allo stesso modo, comandi che eseguono e escono (ad esempio, net user Administrator nuova_password) non tengono aperta la finestra.
Puoi eseguire comandi powershell codificati tramite questo BOF:



Il comando taskkill e il messaggio per l'utente sono incorporati nel comando ysoserial. Se si volesse alterare questo comportamento, bisognerebbe eseguire il proprio comando ysoserial e seguire la dimostrazione qui sotto di come è stato creato il codice.
Utilizzando uno strumento personalizzato, il file binario è stato acquisito e stampato come hex:

Copiando questo nel Blocco note e cercando '&' in hex si individuano i byte desiderati (nota che ci sono diversi set di questi, abbiamo bisogno dell'ultimo):

Il payload viene diviso in due parti subito dopo questi byte:

La lunghezza di ogni parte viene calcolata e annotata per dopo.
Qui le cose si complicano.
A dire il vero non so molto sulla deserializzazione o su ysoserial, ma ho scoperto che c'è un set di byte nel payload che rappresenta la lunghezza della parte 'importante' del payload, inclusa la definizione del comando utente. Questo può essere visto nel seguente screenshot di un dump hex affiancato di due diversi payload creati da ysoserial, ciascuno contenente un comando diverso da eseguire:

Per ragioni che non posso spiegare, questi byte riflettono la lunghezza del payload in base-128; lo 0x05 viene moltiplicato per 128 per dare 640; questo viene aggiunto al valore dell'altro byte (0xb0 o 0xd4) meno 128; ho scoperto che quando il secondo byte (0x05) raggiunge il limite (0x06), il primo byte ricomincia da 0x80 invece che da 0x00 come ci si potrebbe aspettare.
Il payload utilizzato in questo strumento appare così:

Convertendo tutti i valori in decimale, il calcolo appare così:
(6 x 128) + (180-128) = 820
La dimensione del file è 1042; nei test ho scoperto che (con questo gadget di ysoserial, comunque) c'è sempre una differenza di 222 byte tra la dimensione del file e la lunghezza riflessa in questo set di byte. Questi 222 byte sembrano essere l' 'intestazione' del payload.
Entrambe le parti del payload vengono copiate in main.c, dove anche la lunghezza originale di 820 viene impostata come variabile. Viene calcolata la lunghezza del comando utente e questo valore viene aggiunto all'820 originale (oltre a un singolo byte extra per uno spazio che deve essere inserito) per calcolare il valore finale che deve essere rappresentato in questo set di byte. Il secondo byte viene calcolato dividendo LenBytes per 128, e il primo byte viene calcolato trovando il resto di LenBytes e aggiungendo 128 (per adattarsi a come inizia da 0x80).

Una volta impostati questi byte, vengono copiati nel buffer Before nel posto appropriato per impostare la lunghezza del payload al valore corretto dato il contenuto. Il buffer finale viene quindi assemblato:

Il payload finalizzato viene quindi scritto su disco e mmc.exe viene chiamato per eseguirlo. Successivamente il payload viene pulito.
x86_64-w64-mingw32-gcc -o EventViewerUAC.x64.o -Os -c main.c -DBOF
Ysoserial offre un'opzione --rawcmd con cui puoi invocare un eseguibile diverso da cmd.exe, ma non puoi fornire alcun argomento. Questo apre la possibilità di invocare direttamente il tuo payload senza chiamare cmd.exe e quindi senza lasciare aperta la finestra della console; tuttavia in questo caso non ci sarebbe nulla per chiudere mmc.exe. Si potrebbe scrivere i propri payload per determinare il processo padre del payload e se è mmc.exe, uccidere mmc.exe per pulire dopo questo bypass UAC. Questo è molto possibile, ma non mi sono preso la briga di farlo poiché questo è solo uno dei tanti bypass UAC là fuori, e non tutti stanno creando i propri payload personalizzati in quel modo. Potrei incorporarlo nei miei runner personali.