Thursday, August 6, 2015

avast! Shatter Attack EoP

Here is another issue in avast!, in the GUI AvastUI.exe. It allowed arbitrary code execution within the context of that trusted process, and as such EoP, self-protection bypass, etc. Exploit is provided. It was fixed about a year ago by the avast! crew.

Summary

Bug type: arbitrary function call
Vector: window message to asw_av_tray_icon_wndclass
Impact: untrusted code execution within the trusted AvastUI.exe process
Verified on: avast! Free AvastUI.exe v9.0.2018.391

Foreword

It's been a while since I had used a shatter attack for an interesting purpose! Trendy about 10 years ago (according to Wikipedia), they allowed privilege escalation thanks to core components of Windows like with MS02-071. They are mostly extinct due to Windows now restricting the messages sent to more privileged processes, or isolation of services in session 0. An old but very good presentation of the excellent Brett Moore explains them in detail.

But the problem resurfaces when a process attempts to introduce home-made integrity levels, while functioning as the current logged in user (and at the same IL). This new security boundary can be shattered thanks to Windows messages.

Description

Since we are running in the same context as AvastUI.exe, we can pretty much send any window message to its windows. This appears to be something that the developers didn't think about. For example, the window corresponding to the window class asw_av_tray_icon_wndclass accepts quite a bit of user messages. The following piece of code handles the message 0x83fd:

.text:00551BC0 kk_CWndWM83FDh  proc near               ; DATA XREF: .rdata:00677314 o
.text:00551BC0
.text:00551BC0 wParam          = dword ptr  8
.text:00551BC0 lParam          = dword ptr  0Ch
.text:00551BC0
.text:00551BC0                 push    ebp
.text:00551BC1                 mov     ebp, esp
.text:00551BC3                 mov     eax, [ebp+wParam]
.text:00551BC6                 test    eax, eax
.text:00551BC8                 jz      short loc_551BD3
.text:00551BCA                 push    [ebp+lParam]
.text:00551BCD                 call    eax
.text:00551BCF                 pop     ebp
.text:00551BD0                 retn    8
.text:00551BD3 ; ---------------------------------------------------------------------------
.text:00551BD3
.text:00551BD3 loc_551BD3:                             ; CODE XREF: kk_CWndWM83FDh+8 j
.text:00551BD3                 xor     eax, eax
.text:00551BD5                 pop     ebp
.text:00551BD6                 retn    8
.text:00551BD6 kk_CWndWM83FDh  endp

As you can see, this handler will interpret wParam as a function pointer and lParam as its first and only argument and call it. This obviously becomes an issue when the message is sent by a 3rd party application as it pretty much guarantees code execution within the AvastUI.exe process.

This call primitive is ideal to execute a function like LoadLibrary. We have to make the first parameter point to a string locating the DLL on the drive. Given that we are local, and that Windows doesn't do per-process randomization of DLLs, we already know the address of LoadLibraryA.

But one has to be a bit imaginative to know how to place the string into the AvastUI.exe process memory at a known location. One of the solutions that I found (that restricts the path to the DLL to *44* bytes), is to use a functionality that would put memory under our control at a known offset into
the .data section of AvastUI.exe. This requires some interaction with the named pipe \\.\pipe\snx_sdesktop_pipe. The process AvastUI.exe creates 10 of those, and reads from them in the following code:

.text:0054E159                 mov     ecx, [ebp+var_30]
.text:0054E15C                 push    0               ; lpOverlapped
.text:0054E15E                 shl     ecx, 4
.text:0054E161                 add     ecx, [ebp+var_30]
.text:0054E164                 lea     eax, [ebp+var_8]
.text:0054E167                 push    eax             ; lpNumberOfBytesRead
.text:0054E168                 push    44              ; nNumberOfBytesToRead
.text:0054E16A                 lea     eax, (g_NamedPipeStructures+4)[ecx*4]
.text:0054E171                 push    eax             ; lpBuffer
.text:0054E172                 push    g_NamedPipeStructures[ecx*4] ; hFile
.text:0054E179                 call    ds:ReadFile

What I called g_NamedPipeStructures is located in the .data section of AvastUI.exe and is an array of 10 structures containing the handle to the pipes followed by a 44 byte array receiving the information read from the pipe.

In order to know where this structure is located in AvastUI.exe, we load the binary within our process and locate the structure thanks to a code signature. If there is no address space collision that would trigger a remapping elsewhere, that address will be the same in the remote process. We then open the 10 named pipes and write the DLL path to them to make sure all the structures will be filled with our data. Then we locate the window, and send it the window message with LoadLibraryA as wParam and the 1st structure address as lParam. This will load the DLL within the AvastUI.exe process.



In my exploit, the DLL in question will spawn a cmd.exe and call the IOCTL to make it trusted. Obviously raising a cmd.exe to trusted doesn't make much sense in a real world exploitation scenario, this is just more of a visual example.


No comments: