CVE-2019-13382: Local Privilege Escalation in SnagIt

Version: Snagit 2019.1.2 Build 3596
Operating System tested on: Windows 10 1803 (x64)
Vulnerability: SnagIt Relay Classic Recorder Local Privilege Escalation through insecure file move

This vulnerability was found in conjunction with Marcus Sailler, Rick Romo and Gary Muller of Capital Group’s Security Testing Team

Vulnerability Overview
Every 30-60 seconds, the TechSmith Uploader Service (UploaderService.exe) checks the folder “C:\ProgramData\Techsmith\TechSmith Recorder\QueuedPresentations” for any presentation files in the “*.xml” format. If an invalid one is found, the service moves that file to “C:\ProgramData\Techsmith\TechSmith Recorder\InvalidPresentations” as SYSTEM.

Since a low privileged user has full control over the QueuedPresentations and InvalidPresentations folders, it is possible to create an invalid presentation in the QueuedPresentations folder and then place a symbolic link for that file name in the InvalidPresentations folder that points to a privileged location.

When the service checks for presentations, it will move the file out of the QueuedPresentations folder and into the InvalidPresentations folder. When it does so, the service will hit the symbolic link and write the new file into a protected location with permissions that allow the low privileged user full control over the contents, resulting in Elevation of Privilege to NT AUTHORITY\SYSTEM.

Identification and Exploitation
When assessing software for privilege escalation vulnerabilities, finding a starting point can often be overwhelming as there are many different primitives and vulnerability classes that exist. My approach often includes starting with the basics and working my way up in complexity. This process typically involves running a tool such as PowerUp, which will identify various trivial (yet common) misconfigurations.

If nothing interesting is returned, the next step is often looking for logical vulnerabilities; specifically abusing symlink/mountpoint/hardlink primitives. In order to quickly identify potential vulnerabilities that could be exploited with the linking primitives, we need to identify locations on the OS where a privileged process (often SYSTEM) is interacting with a folder or file that a low privileged user has control over. This logic is true in most logical vulnerabilities in that interesting attack surface is linked to a privileged process utilizing a resource a low privileged user controls.

When hunting for such bugs, I often start with running Process Monitor with a filter on SYSTEM processes and commonly abused filesystem locations, such as C:\ProgramData, C:\Windows\Temp and C:\Users\<username>\AppData. Such a filter might look like so:

 

When applying the Process Monitor and watching the output for a few minutes, it became apparent that “UploaderService.exe” was querying the “C:\ProgramData\Techsmith\TechSmith Recorder\QueuedPresentations” directory for any XML files:

Looking at the DACL on that folder, it also stood out that that “BUILTIN\Users” had write access:

This is particularly interesting in that a privileged SYSTEM process (UploaderService.exe) is looking for files in a directory that low privileged users have read/write access. With this information, the next step was to give “UploaderService.exe” an XML file to find and see what happens.

As expected, “UploaderService.exe” checks “C:\ProgramData\Techsmith\TechSmith Recorder\QueuedPresentations” for any XML files and finds the one we created:

The next question was, what does “UploaderService.exe” do with our XML file? Does it read it in and ingest the contents? Does it place it someplace else?

Looking at the rest of the Process Monitor output answers that question for us. In this case, “UploaderService.exe” takes any XML files in “C:\ProgramData\Techsmith\TechSmith Recorder\QueuedPresentations” and determines if the XML presentation file is valid. Since we simply echoed “1” into our XML file, the service executable determines that “1.xml” is an invalid presentation and moves it to “C:\ProgramData\Techsmith\TechSmith Recorder\InvalidPresentations\1.xml”:

Looking at the “C:\ProgramData\Techsmith\TechSmith Recorder\InvalidPresentations” directory, “BUILTIN\Users” also have read/write access:

At this point, we have identified that a SYSTEM process (UploaderService.exe) is checking a user-controlled directory for any XML files. When found, the privileged process takes the attacker supplied XML file and moves it from the QueuedPresentations folder to the InvalidPresentations folder while retaining the original file name.

Why is this interesting? This presents the opportunity to use Symbolic Links during the move file operation to accomplish a privileged file write. How you might ask? The workflow would be like so:

  • Create a Symbolic Link on “C:\ProgramData\Techsmith\TechSmith Recorder\InvalidPresentations\1.xml” that points to “C:\Windows\System32\ualapi.dll”
    • It should be noted that “C:\Windows\System32\ualapi.dll” doesn’t exist. This is a DLL we are planting to get code-execution as SYSTEM
    • Since the process is privileged “SYSTEM”, it will have the correct permissions to write this file.
  • Write a dummy xml file to “C:\ProgramData\Techsmith\TechSmith Recorder\QueuedPresentations\1.xml”
  • When “UploaderService.exe” checks “C:\ProgramData\Techsmith\TechSmith Recorder\QueuedPresentations” for any XML files, it will find “1.xml” and move it to “C:\ProgramData\Techsmith\TechSmith Recorder\InvalidPresentations\1.xml”. While doing so, it will hit our Symbolic Link and instead move the file to “C:\Windows\System32\ualapi.dll” (while retaining the original DACL)

In theory, this should work. Let’s test it out! For the Symbolic Link, I used “CreateSymlink.exe” from James Forshaw’s Symbolic Link Testing Tools repo. All we need to do is place a symbolic link on “C:\ProgramData\Techsmith\TechSmith Recorder\InvalidPresentations\1.xml” that points to “C:\Windows\System32\ualapi.dll” and then create “C:\ProgramData\Techsmith\TechSmith Recorder\QueuedPresentations\1.xml”:

With the symlink created and our dummy XML file created, we wait 60 seconds for “UploaderService.exe” to check the QueuedPresentations folder. When it does, it finds our “1.xml” file and tries to move it to “C:\ProgramData\TechSmith\TechSmith Recorder\InvalidPresentations\1.xml”. When it does so, it hits our symbolic link on “C:\ProgramData\TechSmith\TechSmith Recorder\InvalidPresentations\1.xml” and instead writes it to “C:\Windows\System32\ualapi.dll”:

We can then confirm the existence of “C:\Windows\System32\ualapi.dll”:

This is great and all, but shouldn’t the newly created “ualapi.dll” file simply inherit the permissions of the parent folder (C:\Windows\System32) and prevent a low privileged user from writing to it? That was my thought at first (before checking the DACL on the file), but “UploaderService.exe” uses MoveFileW(). According to the documentation, MoveFileW() retains the original DACL when moving the file on the same volume:

While not explicitly stated, it can be inferred that if the file is not moved across volumes, it is moved with the DACL intact. This means that when “UploaderService.exe” hits the symbolic link on “C:\ProgramData\TechSmith\TechSmith Recorder\InvalidPresentations\1.xml” and tries to move the original file to “C:\Windows\System32\ualapi.dll”, it keeps the original DACL for “1.xml”.  Since it was created by a low privileged user, it has a DACL that has the low privileged user as the Owner with “FullControl” rights:

At this point, we now have “C:\Windows\System32\ualapi.dll” that allows our low privileged user to write to it. This means we can simply copy over the newly created ualapi.dll file with a payload of our choosing. In this case, the payload starts cmd.exe when loaded.

We now have a payload sitting in C:\Windows\System32\ualapi.dll. This DLL gets loaded when the spooler service starts. For the PoC, all that is left is to reboot the host in order to get the spooler service to restart. Additionally, one could use the CollectorService to load the DLL without a reboot. Since this is a PoC, that is an exercise left up to the reader.

Once the host is rebooted, “spoolsv.exe” will load our payload from C:\Windows\System32\ualapi.dll as SYSTEM, resulting in privilege escalation:

A video of exploitation can be found here: https://www.youtube.com/watch?v=V90JRwlaHRY&feature=youtu.be

This vulnerability has been fixed in SnagIt versions 2019.1.3, 2018.2.4 and 13.1.7 with CVE-2019-13382. The fixed involved using _time64 when moving the file combined with a check for reparse points (FSCTL_GET_REPARSE_POINT). If a reparse point exists, it is removed.

 

Disclosure Timeline

As committed as SpecterOps is to transparency, we acknowledge the speed at which attackers adopt new offensive techniques once they are made public. This is why prior to publicization of a new bug or offensive technique, we regularly inform the respective vendor of the issue, supply ample time to mitigate the issue, and notify select, trusted vendors in order to ensure that detections can be delivered to their customers as quickly as possible.

  • June 19th, 2019: Vulnerability identified in conjunction with Capital Group’s Security Testing Team
  • June 20th, 2019: Joint disclosure with Capital Group began. Support case opened with a request for contact information for the security team at TechSmith
  • June 21st, 2019: Case assigned to a handler, new comment stated that the details can be uploaded to the current case and they will be forwarded to the security team
  • June 21st, 2019: Full write-up, PoC code and a demonstration video was uploaded to the open support case
  • June 25th, 2019: TechSmith confirmed the vulnerability and offered temporary remediation advice. TechSmith also requested notice before public disclosure.
  • June 25th, 2019: Informed TechSmith that public disclosure would be 90 days after the initial report with a note that an extension would be considered if needed.
  • July 2nd, 2019: TechSmith stated a fixed build is done and set to be deployed before the end of July with a note asking if we would verify the fix
  • July 2nd, 2019: Informed TechSmith that I would verify the fix
  • July 3rd, 2019: TechSmith provided a private fixed build
  • July 9th, 2019: Informed SnagIt that based on testing, the fix seemed sufficient 
  • July 23rd, 2019: Patch released, issue publicly disclosed

CVE-2019-13142: Razer Surround 1.1.63.0 EoP

Version: Razer Surround 1.1.63.0
Operating System tested on: Windows 10 1803 (x64)
Vulnerability: Razer Surround Elevation of Privilege through Insecure folder/file permissions

Purpose
I hope that this post serves as a motivator for folks who see vulnerability research as an intimidating area to get started in. While this bug can be considered simple, the primary purpose of this post is to outline the methodology behind how to get started and what to look for. Additionally, I’d like it to serve as a reminder to not discount the low hanging fruit, no matter how large the organization.

Brief Description:
Razer Surround installs a service named “RzSurroundVADStreamingService” that runs as SYSTEM. This service runs “RzSurroundVADStreamingService.exe” out of “C:\ProgramData\Razer\Synapse\Devices\Razer Surround\Driver”. The permissions on  RzSurroundVADStreamingService.exe and “C:\ProgramData\Razer\Synapse\Devices\Razer Surround\Driver” allow for overwriting the service binary with a malicious one, resulting in elevation of privilege to SYSTEM.

Identification and Exploitation
When doing vulnerability research, picking a target to go after can be challenging. Hunting for bugs in large software platforms can be intimidating as there is an assumption that all vulnerabilities are complex and take a special skill set to identify. I’d like to use this vulnerability as an example as to why the act of hunting for vulnerabilities isn’t as hard as it sounds.

You may ask, why Razer? How do you identify a piece of software to begin hunting for vulnerabilities in? The answer is simple: Investigate what interests you. In this case, I own various Razer products. It is hard to ignore the urge to look when you use a product and the software associated with it every day.

When looking for vulnerabilities, there is often a common workflow that I follow once the software of interest is installed. This stage involves analyzing the potential attack surface that the target software has exposed. I typically start with the basics and then resort to dynamic/static analysis if needed. The things I typically look for initially are:

  1. Installed services (both the service permissions and the service executable/path permission)
  2. Named pipes (and their ACLs)
  3. Log file permissions in folders like C:\ProgramData
  4. Network sockets
  5. DCOM servers and hosted interfaces

As far as tooling goes, I mostly stick to Process Monitor and James Forshaw’s NTObjectManager project.

In the instance of Razer Surround, I began by checking what privileged processes the software uses by looking at the process list. This revealed that “RzSurroundVADStreamingService.exe” was running as “NT AUTHORITY\SYSTEM”. The next step was to figure out how that process was being started. Given the name of the process has “service” in it, that is a good starting point. To verify, it was easy enough to do “Get-Service *Rz*” in Powershell, which returned all of the services with “Rz” in the name. This led me to the “RzSurroundVadStreamingService” system service with the ImagePath set to the executable of interest. After dumping the ImagePath, the location of the service executable stood out as it was running out of “C:\ProgramData\Razer\Synapse\Devices\Razer Surround\Driver\”

Why is this interesting? By default, “BUILTIN\Users” have “GenericWrite” access to C:\ProgramData:

A very common error that software developers make is not properly locking down the permissions of any created subfolders in C:\ProgramData. If an installer simply creates a folder in C:\ProgramData, that folder and any subfolders will have inherited permissions of C:\ProgramData, which include the “GenericWrite” access right for “BUILTIN\Users”.

Improper file and folder permissions were the culprit in this case as “Everyone” was eventually granted “FullControl” over any files in “C:\ProgramData\Razer\Synapse\Devices\Razer Surround\Driver”

As previously noted, this path is where the “RzSurroundVADStreamingService” ImagePath for the service executable was pointing to. Given a low privileged user has “FullControl” over the folder and included files, it is possible to just replace the service executable for the “RzSurroundVADStreamingService” system service:

Once the payload is copied, rebooting the host will cause the service to start the new executable as SYSTEM. In this instance, the new service executable will start cmd.exe as SYSTEM:

Razer fixed this vulnerability by moving “RzSurroundVADStreamingService.exe” and the associated dependencies to a secured location in “C:\Program Files (x86)\Razer”.

Disclosure Timeline
As committed as SpecterOps is to transparency, we acknowledge the speed at which attackers adopt new offensive techniques once they are made public. This is why prior to publicization of a new bug or offensive technique, we regularly inform the respective vendor of the issue, supply ample time to mitigate the issue, and notify select, trusted vendors in order to ensure that detections can be delivered to their customers as quickly as possible.

  • March 20th, 2019 — Initial report sent to Razer
  • March 21st, 2019  — Report acknowledgement received from Razer
  • April 30th, 2019 —  30 days after initial report
  • May 2nd, 2019  —  Razer provided a fixed build to test
  • May 2nd, 2019 —  Fix was verified
  • May 20th, 2019 —  60 days after initial report
  • June 6th, 2019 —  Reached out to Razer for a timeframe regarding a public fix
  • June 6th, 2019 —  Razer informed me a fix should be live, but verification from the development team was needed
  • June 7th, 2019 —  Informed Razer that a fix wasn’t available on the site or via Surround’s update mechanism
  • June 10th, 2019 —  Razer informed me that there had been some internal confusion and that a fix was going live the end of June
  • June 11th, 2019 —  Informed Razer I would hold off on disclosure until the fix is live
  • June 20th, 2019 —  90 days after initial report, extension granted
  • July 1st, 2019 —  Razer informed me that a note is out to the development team regarding when the fix would be pushed live
  • July 5th, 2019 —  Fix published

-Matt N.