Posts Finding TeamViewer 0days - Part III

   

Post
Cancel

Finding TeamViewer 0days - Part III

Finding TeamViewer 0days. Part 3: Putting it all together. PARTY TIME :)!

Now comes the interesting part. I am sorry about the two last lazy parts, but I wanted to explain the whole process :).

Because I had spoiled you, we already know that TV is not filtering the parameter sent by the client to ask for the driver installation nor signature check, etc.

So the idea that we will review in this part is: we will spoof a TV client an asks for a VPN Driver installation but indicating another INF. I reutilized the same original INF of TeamViewer but in another (non-privileged) path renaming the “bad” driver to teamviewervpn.sys, as this is the driver name being targeted by the original INF.

First of all, you can find the project here:

IMPORTANT NOTE

This bypasses also TeamViewer option Changes require administrative rights on this computer.

This check is only effective via the GUI, as TeamViewer options is disabled when clicking the button with an unprivileged user. But it is possible to connect to the socket and perform the arbitrary driver load.

IMPORTANT NOTE II

The exploit is version dependant because of the IPC message where the client specified its PID and another data among the version. The version of the client must match the version of the SYSTEM service. The exploit must be modified (lines 140 to 143) in Main.cpp to the TeamViewer_service.exe version that is being targeted.

Coding the Exploit

We will start by defining the structures of the IPC messages involved.

We will use it to send the necessary messages over the sockets using the TV IPC protocol.

We also will need the MD5 implementation, which I will skip. I have also used the following hpp for hexadecimal output printing.

  • https://github.com/zmb3/hexdump/blob/master/Hexdump.hpp

First of all, we will start connecting to the socket.

I decided to not use Completion I/O Port nor Overlapped IO. Technically, TV is listening like any other socket, so I will just connect normally.

One we have connected to 5939/tcp, we need to send the first message, which is the first authentication one where the client sends it challenge.

IPC_CLIENTE_CHALLENGE_AUTH ipcClientAuth1 = { { 0x08,0x00,0x01,0x00,0x1d,0x00,0x00,0x00,0x2d,0x02,0x09,0x10,0x00,0x00,0x00 }, {0xb7,0x48,0x77,0x26,0x8a,0x72,0xb8,0xf0,0xfe,0x57,0x04,0x03,0xfc,0x64,0x2e,0xb0}, {0xfe,0x01,0x00,0x00,0x00,0x01} };

We can always same the same challenge, it does not matter.

Then, we will receive the response from the server containing its challenge plus the response to our. We can just ignore the response and calculate the correct response for its challenge.

And then send the calculated response in an Authentication Message.

Now it is time to send the Control IPC message indicating the PID of the process. As I stated in the first part, I have not reversed the rest of the fields, but just indicating the correct PID and a correct identifier at the end is sufficient.

After that the service start to sends us some messages about configuration, it tries to sync some config. We just need to read all this packets, but it is not necessary to do anything with this information.

After that then comes the most interesting part. We are ready to send the Driver Install request.

IMPORTANT NOTE

I do not know why because I have not analyzed it, but it appears that not all paths works. At first I thought it was the length, but then tried different lengths and ones worked while others not. I think that maybe I got the service a bit crazy with so many tests. I ended up using the following path, which can be created by a non privileged user by default in Windows.

  • C:\Not Program F\aaaaaaaaaa\bbb\AnotherThingg.inf

The length in the IPC message is just the length of the body data, does not take into account the header. Also, it does not take into account the two bytes of the NULL BYTE (two bytes because is wide string). The IPC message does not null-terminate the strings.

So we need to calculate the current length taking that into account.

Then we are ready to send the magic :).

Elevating to Kernel

At first I thought that we could use the INF to create an arbitrary service running as SYSTEM and elevate privileges that way. But the helper program of TV ends calling UpdateDriverForPlugAndPlayDevicesA without verification of the signature (Catalog File).

  • https://learn.microsoft.com/en-us/windows/win32/api/newdev/nf-newdev-updatedriverforplugandplaydevicesa

This function updates the INF for an existing hardware based on the hardware ID. I have not found a way to perform the arbitrary service creation. Nevertheless, here is and example INF file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
; ExampleService.inf
; INF file to create a service that executes a binary as SYSTEM

[Version]
Signature="$WINDOWS NT$"
Class=Service
ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}
Provider=%ProviderName%
DriverVer=06/16/2024,1.0.0.0

[DestinationDirs]
DefaultDestDir = 12 ; DIRID_DRIVERS

[SourceDisksNames]
1 = %DiskName%,,,""

[SourceDisksFiles]
ExampleService.exe = 1

[Manufacturer]
%ManufacturerName%=Example,NTx86,NTamd64

[Example.NTx86]
%ServiceName%=ExampleService_Install, Root\LEGACY_ExampleService

[Example.NTamd64]
%ServiceName%=ExampleService_Install, Root\LEGACY_ExampleService

[ExampleService_Install]
CopyFiles = ExampleService_CopyFiles
AddService = ExampleService, 0x00000002, ExampleService_Service_Inst

[ExampleService_CopyFiles]
ExampleService.exe

[ExampleService_Service_Inst]
DisplayName    = %ServiceName%
ServiceType    = 0x10 ; SERVICE_WIN32_OWN_PROCESS
StartType      = 2    ; SERVICE_AUTO_START
ErrorControl   = 1    ; SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\ExampleService.exe
StartName      = LocalSystem

[Strings]
ProviderName="Example Provider"
ManufacturerName="Example Manufacturer"
ServiceName="Example Service"
DiskName="Example Installation Disk"

It is necessary to generate the CAT with makecat.

  • https://learn.microsoft.com/en-us/windows/win32/seccrypto/makecat

Finally, I ended up using a easier approach. Let’s use BYOVD, Bring You Own Vulnerable Driver with the tool BYOVDKit:

  • https://github.com/Hagrid29/BYOVDKit

I just re-used the same INF and CAT of original TeamViewer but replace teamviewervpn.sys with the driver we want to load and rename or copy the original INF, in this case *AnotherThingg.inf.

We then launch our exploit and the driver gets loaded.

We can then leverage the vulnerable driver to elevate privileges.

We will copy the Primary Access Token of PID 4, i.e, the SYSTEM process.

NICE, WE ARE SYSTEM :D

USER TO KERNEL.

If you want to test and load another driver do not remember to delete the one we have installed from the Windows CAT Store.

  • C:\Windows\system32>pnputil -enum-drivers

  • C:\Windows\system32>pnputil -delete-driver oem13.inf -force -uninstall

This post is licensed under CC BY 4.0 by the author.