Over the past few months, Adobe has patched several remote code execution bugs in Adobe Acrobat and Reader that were reported by researcher Mark Vincent Yason (@MarkYason) through our program. Two of these bugs, in particular, CVE-2021-28632 and CVE-2021-39840, are related Use-After-Free bugs even though they were patched months apart. Mark has graciously provided this detailed write-up of these vulnerabilities and their root cause.
This blog post describes two Adobe Reader use-after-free vulnerabilities that I submitted to ZDI: One from the June 2021 patch (CVE-2021-28632) and one from the September 2021 patch (CVE-2021-39840). An interesting aspect about these two bugs is that they are related – the first bug was discovered via fuzzing and the second bug was discovered by reverse engineering and then bypassing the patch for the first bug.
CVE-2021-28632: Understanding Field Locks
One early morning while doing my routine crash analysis, one Adobe Reader crash caught my attention:
After a couple of hours minimizing and cleaning up the fuzzer-generated PDF file, the resulting simplified proof-of-concept (PoC) was as follows:
PDF portion (important parts only):
JavaScript portion:
The crash involved a use-after-free of CPDField objects. CPDField objects are internal AcroForm.api C++ objects that represent text fields, button fields, etc. in interactive forms.
In the PDF portion above, two CPDField objects are created to represent the two text fields named fieldParent and fieldChild. Note that the created objects have the type CTextField, a subclass of CPDField, which is used for text fields. To simplify the discussion, they will be referred to as CPDField objects.
An important component for triggering the bug is that fieldChild should be a descendant of fieldParent by specifying it in the /Kids key of the fieldParent PDF object dictionary (see [A] above) as documented in the PDF file format specification:
Another important concept relating to the bug is that to prevent a CPDField object from being freed while it is in use, an internal property named LockFieldProp is used. Internal properties of CPDField objects are stored via a C++ map member variable.
If LockFieldProp is not zero, it means that the CPDField object is locked and can't be freed; if it is zero or is not set, it means that the CPDField object is unlocked and can be freed. Below is the visual representation of the two CPDField objects in the PoC before the field locking code (discussed later) is called: fieldParent is unlocked (LockFieldProp is 0) and is in green, and fieldChild is also unlocked (LockFieldProp is not set) and is also in green:
On the JavaScript portion of the PoC, the code sets up a JavaScript callback so that when the “Format” event is triggered for fieldParent, a custom JavaScript function callback() will be executed [2]. The JavaScript code then triggers a “Format” event by setting the textSize property of fieldParent[3]. Internally, this executes the textSize property setter of JavaScript Field objects in AcroForm.api.
One of the first actions of the textSize property setter in AcroForm.api is to call the following field locking code against fieldParent:
The above code locks the CPDField object passed to it by setting its LockFieldProp property to 1[AA].
After executing the field locking code, the lock state of fieldParent (locked: in red) and fieldChild (unlocked: in green) are as follows:
Note that in the later versions of Adobe Reader, the value of LockFieldProp is a pointer to a counter instead of being set with the value 1 or 0.
Next, the textSize property setter in AcroForm.api calls the following recursive CPDField method where the use-after-free occurs:
On the first call to the above method, the this pointer points to the locked fieldParentCPDField object. Because it has no associated widget [aa], the method performs a recursive call [cc] with the this pointer pointing to each of fieldParent's children [bb].
Therefore, on the second call to the above method, the this pointer points to the fieldChildCPDField object, and since it has an associated widget (see [B] in the PDF portion of the PoC), a notification will be triggered [dd] that results in the custom JavaScript callback() function to be executed. As shown in the previous illustration, the locking code only locked fieldParent while fieldChild is left unlocked. Because fieldChild is unlocked, the removeField("fieldChild") call in the custom JavaScript callback() function (see [1] in the JavaScript portion of the PoC) succeeds in freeing the fieldChildCPDField object. This leads to the this pointer in the recursive method to become a dangling pointer after the call in [dd]. The dangling this pointer is later dereferenced resulting in the crash.
This first vulnerability was patched in June 2021 by Adobe and assigned CVE-2021-28632.
CVE-2021-39840: Reversing Patch and Bypassing Locks
I was curious to see how Adobe patched CVE-2021-28632, so after the patch was released, I decided to look at the updated AcroForm.api.
Upon reversing the updated field locking code, I noticed an addition of a call to a method that locks the passed field’s immediate descendants:
With the added code, both fieldParent and fieldChild will be locked and the PoC for the first bug will fail in freeing fieldChild:
While assessing the updated code and thinking, I arrived at a thought: since the locking code only additionally locks the immediate descendants of the field, what if the field has a non-immediate descendant?... a grandchild field! I quickly modified the PoC for CVE-2021-28632 to the following:
PDF portion (important parts only):
JavaScript portion:
And then loaded the updated PoC in Adobe Reader under a debugger, hit go... and crash!
The patch was bypassed, and Adobe Reader crashed at the same location in the previously discussed recursive method where the use-after-free originally occurred.
Upon further analysis, I confirmed that the illustration below was the state of the field locks when the recursive method was called. Notice that fieldGrandChild is unlocked, and therefore, can be freed:
The recursive CPDField method started with the this pointer pointing to fieldParent, and then called itself with the this pointer pointing to fieldChild, and then called itself again with the this pointer pointing to fieldGrandChild. Since fieldGrandChild has an attached widget, the JavaScript callback() function that frees fieldGrandChild was executed, effectively making the this pointer a dangling pointer.
This second vulnerability was patched in September 2021 by Adobe and assigned CVE-2021-39840.
Controlling Field Objects
Control of the freed CPDField object is straightforward via JavaScript: after the CPDField object is freed via the removeField() call, the JavaScript code can spray the heap with similarly sized data or an object to replace the contents of the freed CPDField object.
When I submitted my reports to ZDI, I included a second PoC that demonstrates full control of the CPDField object and then dereferences a controlled, virtual function table pointer:
Conclusion
Implementation of object trees, particularly those in applications where the objects can be controlled and destroyed arbitrarily, is prone to use-after-free vulnerabilities. For developers, special attention must be made to the implementation of object reference tracking and object locking. For vulnerability researchers, they represent opportunities for uncovering interesting vulnerabilities.
Thanks again to Mark for providing this thorough write-up. He has contributed many bugs to the ZDI program over the last few years, and we certainly hope to see more submissions from him in the future. Until then, follow the team for the latest in exploit techniques and security patches.
CVE-2021-28632 & CVE-2021-39840: Bypassing Locks in Adobe Reader
In this installment of our MindShaRE series, ZDI vulnerability researcher Michael DePlante describes how he uses the IO Ninja tool for reverse engineering and software analysis. According to its website, IO Ninja provides an “all-in-one terminal emulator, sniffer, and protocol analyzer.” The tool provides many options for researchers but can leave new users confused about where to begin. This blog provides a starting point for some of the most commonly used features.
Looking at a new target can almost feel like meeting up with someone who’s selling their old car. I’m the type of person who would want to inspect the car for rust, rot, modifications, and other red flags before I waste the owner’s or my own time with a test drive. If the car isn’t super old, having an OBD reader (on-board diagnostics) may save you some time and money. After the initial inspection, a test drive can be critical to your decision.
Much like checking out a used car, taking software for test drives as a researcher with the right tools is a wonderful way to find issues. In this blog post, I would like to highlight a tool that I have found incredibly handy to have in my lab – IO Ninja.
Lately, I have been interested in antivirus products, mainly looking for local privilege escalation vulnerabilities. After looking at several vendors including Avira, Bitdefender, ESET, Panda Security, Trend Micro, McAfee, and more, I started to notice that almost all of them utilize the Named Pipe Filesystem (NPFS). Furthermore, NPFS is used in many other product categories including virtualization, SCADA, license managers/updaters, etc.
I began doing some research and realized there were not many tools that let you locally sniff and connect to these named pipes easily in Windows. The Sysinternals suite has a tool called Pipelist and it works exactly as advertised. Pipelist can enumerate open pipes at runtime but can leave you in the dark about pipe connections that are opening and closing frequently. Another tool also in the Sysinternals suite called Process Explorer allows you to view open pipes but only shows them when you are actively monitoring a given process. IO Ninja fills the void with two great plugins it offers.
An Introduction to IO Ninja
When you fire up IO Ninja and start a new session, you’re presented with an expansive list of plugins as shown below. I will be focusing on two of the plugins under the “File Systems” section in this blog: Pipe Monitor and Pipe Server.
Before starting a new session, you may need to check the “Run as Administrator” box if the pipes you want to interact with require elevated privileges to read or write. You can inspect the permissions on a given pipe with the accesschk tool from the Sysinternals Suite:
The powerful Pipe Monitor plugin in IO Ninja allows you to record communication, as well as apply filters to the log. The Pipe Server plugin allows you to connect to the client side of a pipe.
IO Ninja: Pipe Monitor
The following screenshot provides a look at the Pipe Monitor plugin that comes by default with IO Ninja.
In the above screenshot, I added a process filter (*chrome*) and started recording before I opened the application. You can also filter on a filename ( name of the pipe), PID, or file ID. After starting Chrome, data started flowing between several pipe instances. This is a terrific way to dynamically gather an understanding of what data is going through each pipe and when those pipes are opened and closed. I found this helpful when interacting with antivirus agents and wanted to know what pipes were being opened or closed based on certain actions from the user, such as performing a system scan or update. It can also be interesting to see the content going across the pipe, especially if it contains sensitive data and the pipe has a weak ACL.
It can also help a developer debug an application and find issues in real-time like unanswered pipe connections or permission issues as shown below.
Using IO Ninja’s find text/bin feature to search for “cannot find”, I was able to identify several connections in the log below where the client side of a connection could not find the server side. In my experience, many applications make these unanswered connections out of the box.
What made this interesting was that the process updatesrv.exe, running as NT AUTHORITY\SYSTEM, tried to open the client side of a named pipe but failed with ERROR_FILE_NOT_FOUND. We can fill the void by creating our own server with the name it is looking for and then triggering the client connection by initiating an update within the user interface.
As a low privileged user, I am now able to send arbitrary data to a highly privileged process using the Pipe Server plugin. This could potentially result in a privilege escalation vulnerability, depending on how the privileged process handles the data I am sending it.
IO Ninja: Pipe Server
The Pipe Server plugin is powerful as it allows you to send data to specific client connections from the server side of a pipe. The GUI in IO Ninja allows you to select which conversation you’d like to interact with by selecting from a drop-down list of Client IDs. Just like with the Pipe Monitor plugin, you can apply filters to clean up the log. Below you’ll find a visual from the Pipe Server plugin after starting the server end of a pipe and getting a few client connections.
In the bottom right of the previous image, you can see the handy packet library. Other related IO Ninja features include a built-in hex editor, file- and script-based transmission, and packet templating via the packet template editor.
The packet template editor allows you to create packet fields and script custom actions using the Jancy scripting language. Fields are visualized in the property grid as shown above on the bottom left-hand side of the image, where they can be edited. This feature makes it significantly easier to create and modify packets when compared to just using a hex editor.
Conclusion
This post only scratches the surface of what IO Ninja can do by highlighting just two of the plugins offered. The tool is scriptable and provides an IDE that encourages users to build, extend or modify existing plugins. The plugins are open source and available in a link listed at the end of the blog. I hope that this post inspires you to take a closer look at NPFS as well as the IO Ninja tool and the other plugins it offers.
Keep an eye out for future blogs where I will go into more detail on vulnerabilities I have found in this area. Until then, you can follow me @izobashi and the team @thezdi on Twitter for the latest in exploit techniques and security patches.
Additional information about IO Ninja can be found on their website. All of IO Ninja’s plugins are open source and available here.
Additional References
If you are interested in learning more you can also check out the following resources which I found helpful.
What do you do when you’ve found an arbitrary file delete as NT AUTHORITY\SYSTEM? Probably just sigh and call it a DoS. Well, no more. In this article, we’ll show you some great techniques for getting much more out of your arbitrary file deletes, arbitrary folder deletes, and other seemingly low-impact filesystem-based exploit primitives.
The Trouble with Arbitrary File Deletes
When you consider how to leverage an arbitrary file delete on Windows, two great obstacles present themselves:
Most critical Windows OS files are locked down with DACLs that prevent modification even by SYSTEM. Instead, most OS files are owned by TrustedInstaller, and only that account has permission to modify them. (Exercise for the reader: Find the critical Windows OS files that can still be deleted or overwritten by SYSTEM!)
Even if you find a file that you can delete as SYSTEM, it needs to be something that causes a “fail-open” (degradation of security) if deleted.
A third problem that can arise is that some critical system files are inaccessible at all times due to sharing violations.
Experience shows that finding a file to delete that meets all the above criteria is very hard. When looking in the usual places, which would be within C:\Windows, C:\Program Files or C:\Program Data, we’re not aware of anything that fits the bill. There is some prior work that involves exploiting antivirus and other products, but this is dependent on vulnerable behavior in those products.
The Solution is Found Elsewhere: Windows Installer
In March of 2021, we received a vulnerability report from researcher Abdelhamid Naceri (halov). The vulnerability he reported was an arbitrary file delete in the User Profile service, running as SYSTEM. Remarkably, his submission also included a technique to parlay this file delete into an escalation of privilege (EoP), resulting in a command prompt running as SYSTEM. The EoP works by deleting a file, but not in any of the locations you would usually think of.
To understand the route to privilege escalation, we need to explain a bit about the operation of the Windows Installer service. The following explanation is simplified somewhat.
The Windows Installer service is responsible for performing installations of applications. An application author supplies an .msi file, which is a database defining the changes that must be made to install the application: folders to be created, files to be copied, registry keys to be modified, custom actions to be executed, and so forth.
To ensure that system integrity is maintained when an installation cannot be completed, and to make it possible to revert an installation cleanly, the Windows Installer service enforces transactionality. Each time it makes a change to the system, Windows Installer makes a record of the change, and each time it overwrites an existing file on the system with a newer version from the package being installed, it retains a copy of the older version. In case the install needs to be rolled back, these records allow the Windows Installer service to restore the system to its original state. In the simplest scenario, the location for these records is a folder named C:\Config.Msi.
During an installation, the Windows Installer service creates a folder named C:\Config.Msi and populates it with rollback information. Whenever the install process makes a change to the system, Windows Installer records the change in a file of type .rbs (rollback script) within C:\Config.Msi. Additionally, whenever the install overwrites an older version of some file with a newer version, Windows Installer will place a copy of the original file within C:\Config.Msi. This type of a file will be given the .rbf (rollback file) extension. In case an incomplete install needs to be rolled back, the service will read the .rbs and .rbf files and use them to revert the system to the state that existed before the install.
This mechanism must be protected against tampering. If a malicious user were able to alter the .rbs and/or .rbf files before they are read, arbitrary changes to the state of the system could occur during rollback. Therefore, Windows Installer sets a strong DACL on C:\Config.Msi and the enclosed files.
Here is where an opening arises, though: What if an attacker has an arbitrary folder delete vulnerability? They can use it to completely remove C:\Config.Msi immediately after Windows Installer creates it. The attacker can then recreate C:\Config.Msi with a weak DACL (note that ordinary users are allowed to create folders at the root of C:\). Once Windows Installer creates its rollback files within C:\Config.Msi, the attacker will be able to replace C:\Config.Msi with a fraudulent version that contains attacker-specified .rbs and .rbf files. Then, upon rollback, Windows Installer will make arbitrary changes to the system, as specified in the malicious rollback scripts.
Note that the only required exploit primitive here is the ability to delete an empty folder. Moving or renaming the folder works equally well.
From Arbitrary Folder Delete/Move/Rename to SYSTEM EoP
In conjunction with this article, we are releasing source code for Abdelhamid Naceri’s privilege escalation technique. This exploit has wide applicability in cases where you have a primitive for deleting, moving, or renaming an arbitrary empty folder in the context of SYSTEM or an administrator. The exploit should be built in the Release configuration for either x64 or x86 to match the architecture of the target system. Upon running the exploit, it will prompt you to initiate a delete of C:\Config.Msi. You can do this by triggering an arbitrary folder delete vulnerability, or, for testing purposes, you can simply run rmdir C:\Config.Msi from an elevated command prompt. Upon a successful run, the exploit will drop a file to C:\Program Files\Common Files\microsoft shared\ink\HID.DLL. You can then get a SYSTEM command prompt by starting the On-Screen Keyboard osk.exe and then switching to the Secure Desktop, for example by pressing Ctrl-Alt-Delete.
The exploit contains an .msi file. The main thing that’s special about this .msi is that it contains two custom actions: one that produces a short delay, and a second that throws an error. When the Windows Installer service tries to install this .msi, the installation will halt midway and rollback. By the time the rollback begins, the exploit will have replaced the contents of C:\Config.Msi with a malicious .rbs and .rbf. The .rbf contains the bits of the malicious HID.DLL, and the .rbs instructs Windows Installer to “restore” it to our desired location (C:\Program Files\Common Files\microsoft shared\ink\).
The full mechanism of the EoP exploit is as follows:
The EoP creates a dummy C:\Config.Msi and sets an oplock.
The attacker triggers the folder delete vulnerability to delete C:\Config.Msi (or move C:\Config.Msi elsewhere) in the context of SYSTEM (or admin). Due to the oplock, the SYSTEM process is forced to wait.
Within the EoP, the oplock callback is invoked. The following several steps take place within the callback.
The EoP moves the dummy C:\Config.Msi elsewhere. This is done so that the oplock remains in place and the vulnerable process is forced to continue waiting, while the filesystem location C:\Config.Msi becomes available for other purposes (see further).
The EoP spawns a new thread that invokes the Windows Installer service to install the .msi, with UI disabled.
The callback thread of the EoP continues and begins polling for the existence of C:\Config.Msi. For reasons that are not clear to me, Windows Installer will create C:\Config.Msi, use it briefly for a temp file, delete it, and then create it a second time to use for rollback scripts. The callback thread polls C:\Config.Msi to wait for each of these actions to take place.
As soon as the EoP detects that Windows Installer has created C:\Config.Msi for the second time, the callback thread exits, releasing the oplock. This allows the vulnerable process to proceed and delete (or move, or rename) the C:\Config.Msi created by Windows Installer.
The EoP main thread resumes. It repeatedly attempts to create C:\Config.Msi with a weak DACL. As soon as the vulnerable process deletes (or moves, or renames) C:\Config.Msi, the EoP’s create operation succeeds.
The EoP watches the contents of C:\Config.Msi and waits for Windows Installer to create an .rbs file there.
The EoP repeatedly attempts to move C:\Config.Msi elsewhere. As soon as Windows Installer closes its handle to the .rbs, the move succeeds, and the EoP proceeds.
The EoP creates C:\Config.Msi one final time. Within it, it places a malicious .rbs file having the same name as the original .rbs. Together with the .rbs, it writes a malicious .rbf.
After the delay and the error action specified in the .msi, Windows Installer performs a rollback. It consumes the malicious .rbs and .rbf, dropping the DLL.
Note that at step 7, there is a race condition that sometimes causes problems. If the vulnerable process does not immediately awaken and delete C:\Config.Msi, the window of opportunity may be lost because Windows Installer will soon open a handle to C:\Config.Msi and begin writing an .rbs there. At that point, deleting C:\Config.Msi will no longer work, because it is not an empty folder. To avoid this, it is recommended to run the EoP on a system with a minimum of 4 processor cores. A quiet system, where not much other activity is taking place, is probably ideal. If you do experience a failure, it will be necessary to retry the EoP and trigger the vulnerability a second time.
From Arbitrary File Delete to SYSTEM EoP
The technique described above assumes a primitive that deletes an arbitrary empty folder. Often, though, one has a file delete primitive as opposed to a folder delete primitive. That was the case with Abdelhamid Naceri’s User Profile bug. To achieve SYSTEM EoP in this case, his exploit used one additional trick, which we will now explain.
In NTFS, the metadata (index data) associated with a folder is stored in an alternate data stream on that folder. If the folder is named C:\MyFolder, then the index data is found in a stream referred to as C:\MyFolder::$INDEX_ALLOCATION. Some implementation details can be found here. For our purposes, though, what we need to know is this: deleting the ::$INDEX_ALLOCATION stream of a folder effectively deletes the folder from the filesystem, and a stream name, such as C:\MyFolder::$INDEX_ALLOCATION, can be passed to APIs that expect the name of a file, including DeleteFileW.
So, if you are able to get a process running as SYSTEM or admin to pass an arbitrary string to DeleteFileW, then you can use it not only as a file delete primitive but also as a folder delete primitive. From there, you can get a SYSTEM EoP using the exploit technique discussed above. In our case, the string you want to pass is C:\Config.Msi::$INDEX_ALLOCATION.
Be advised that success depends on the particular code present in the vulnerable process. If the vulnerable process simply calls DeleteFileA/DeleteFileW, you should be fine. In other cases, though, the privileged process performs other associated actions, such as checking the attributes of the specified file. This is why you cannot test this scenario from the command prompt by running del C:\Config.Msi::$INDEX_ALLOCATION.
From Folder Contents Delete to SYSTEM EoP
Leveling up once more, let us suppose that the vulnerable SYSTEM process does not allow us to specify an arbitrary folder or file to be deleted, but we can get it to delete the contents of an arbitrary folder, or alternatively, to recursively delete files from an attacker-writable folder. Can this also be used for EoP? Researcher Abdelhamid Naceri demonstrated this as well, in a subsequent submission in July 2021. In this submission he detailed a vulnerability in the SilentCleanup scheduled task, running as SYSTEM. This task iterates over the contents of a temp folder and deletes each file it finds there. His technique was as follows:
Create a subfolder, temp\folder1.
Create a file, temp\folder1\file1.txt.
Set an oplock on temp\folder1\file1.txt.
Wait for the vulnerable process to enumerate the contents of temp\folder1 and try to delete the file file1.txt it finds there. This will trigger the oplock.
When the oplock triggers, perform the following in the callback: a. Move file1.txt elsewhere, so that temp\folder1 is empty and can be deleted. We move file1.txt as opposed to just deleting it because deleting it would require us to first release the oplock. This way, we maintain the oplock so that the vulnerable process continues to wait, while we perform the next step. b. Recreate temp\folder1 as a junction to the ‘\RPC Controlfolder of the object namespace.
c. Create a symlink at\RPC Control\file1.txtpointing toC:\Config.Msi::$INDEX_ALLOCATION`.
When the callback completes, the oplock is released and the vulnerable process continues execution. The delete of file1.txt becomes a delete of C:\Config.Msi.
Readers may recognize the symlink technique involving \RPC Control from James Forshaw’s symboliclink-testing-tools. Note, though, that it’s not sufficient to set up the junction from temp\folder1 to \RPC Control and then let the arbitrary file delete vulnerability do its thing. That’s because \RPC Control is not an enumerable file system location, so the vulnerable process would not be able to find \RPC Control\file1.txt via enumeration. Instead, we must start off by creating temp\folder1\file1.txt as a bona fide file, allowing the vulnerable process to find it through enumeration. Only afterward, just as the vulnerable process attempts to open the file for deletion, we turn temp\folder1 into a junction pointing into the object namespace.
For working exploit code, see project FolderContentsDeleteToFolderDelete. Note that the built-in malware detection in Windows will flag this process and shut it down. I recommend adding a “Process” exclusion for FolderContentsDeleteToFolderDelete.exe.
You can chain these two exploits together. To begin, run FolderOrFileDeleteToSystem and wait for it to prompt you to trigger privileged deletion of Config.Msi. Then, run FolderContentsDeleteToFolderDelete /target C:\Config.Msi. It will prompt you to trigger privileged deletion of the contents of C:\test1. If necessary for your exploit primitive, you can customize this location using the /initial command-line switch. For testing purposes, you can simulate the privileged folder contents deletion primitive by running del /q C:\test1\* from an elevated command prompt. FolderContentsDeleteToFolderDelete will turn this into a delete of C:\Config.Msi, and this will enable FolderOrFileDeleteToSystem to drop the HID.DLL. Finally, open the On-Screen Keyboard and hit Ctrl-Alt-Delete for your SYSTEM shell.
From Arbitrary Folder Create to Permanent DoS
Before closing, we’d like to share one more technique we learned from this same researcher. Suppose you have an exploit primitive for creating an arbitrary folder as SYSTEM or admin. Unless the folder is created with a weak DACL, it doesn’t sound like this would be something that could have any security impact at all. Surprisingly, though, it does: it can be used for a powerful denial of service. The trick is to create a folder such as this one:
C:\Windows\System32\cng.sys
Normally there is no file or folder by that name. If an attacker name squats on that filesystem location with an extraneous file or even an empty folder, the Windows boot process is disrupted. The exact mechanism is a bit of a mystery. It would appear that Windows attempts to load the cng.sys kernel module from the improper location and fails, and there is no retry logic that allows it to continue and locate the proper driver. The result is a complete inability to boot the system. Other drivers can be used as well for the same effect.
Depending on the vulnerability at hand, this DoS exploit could even be a remote DoS, as nothing is required besides the ability to drop a single folder or file.
Conclusion
The techniques we’ve presented here show how some rather weak exploit primitives can be used for great effect. We have learned that:
• An arbitrary folder delete/move/rename (even of an empty folder), as SYSTEM or admin, can be used to escalate to SYSTEM. • An arbitrary file delete, as SYSTEM or admin, can usually be used to escalate to SYSTEM. • A delete of contents of an arbitrary folder, as SYSTEM or admin, can be used to escalate to SYSTEM. • A recursive delete, as SYSTEM or admin, of contents of a fixed but attacker-writable folder (such as a temp folder), can be used to escalate to SYSTEM. • An arbitrary folder create, as SYSTEM or admin, can be used for a permanent system denial-of-service. • An arbitrary file delete or overwrite, as SYSTEM or admin, even if there is no control of contents, can be used for a permanent system denial-of-service.
We would like to thank researcher Abdelhamid Naceri for his great work in developing these exploit techniques, as well as for the vulnerabilities he has been reporting to our program. We look forward to seeing more from him in the future. Until then, you can find me on Twitter at @HexKitchen, and follow the team for the latest in exploit techniques and security patches.
Abusing Arbitrary File Deletes to Escalate Privilege and Other Great Tricks
So you’ve heard of Pwn2Own and think you are up to the challenge of competing in the world’s most prestigious hacking competition. Great! We would love to have you! However, there are a few things you should know before we get started. With Pwn2Own Vancouver just around the corner, here are 10 things you need to know before participating in Pwn2Own.
1. You need to register before the contest.
We try to make this as apparent as possible in the rules, but we still have people walk into the room on the first day of the contest hoping to participate. There are a lot of logistics around Pwn2Own, so we need everyone to complete their registration before the contest starts. We can’t support anyone who wants to join on the first day of the competition.
2. You need to answer the vetting email.
Again, the logistics of running the Pwn2Own competition can be daunting. One way we prepare is by vetting all entries before registration closes. We need to understand the nature of your exploit to ensure it fits within the rules and to ensure we have everything we need on hand to run the attempt. For example, we need to know how you plan on demonstrating if the exploit is successful. If you answer, “Our exploit will provide a root shell when it has succeeded” – we know you have a solid plan and that it is within the rules. If you tell us you need to start as an admin user and require four reboots, your entry is unlikely to qualify. We’ll also ask for things like other user interactions or the need for a Man-in-the-Middle (MitM). These could disqualify the entry – or it could be fine. It depends on the target and details, which is why we want to know before the competition. It’s not fair to any of the contestants to have them think their exploit is a winner just to be disqualified during the contest.
3. What should we call you?
We know people enter Pwn2Own to win cash and prizes, but they want recognition, too. We’re more than happy to include your Twitter handle, your company name, or just about anything else. Just let us know. We try to pre-stage a lot of our communications, so an omission or misspelling could take a bit to get fixed, and we want to give contestants the attention they deserve. You’d be surprised how many people wait until during or after the event to clarify how they wish to be mentioned.
4. Will you be participating locally or remotely?
This is a newer question but opening up the contest to remote participation has allowed many to participate that otherwise would not. However, remote contestants have a few extra hurdles the on-site participants do not. For remote participants, all artifacts must be submitted to the ZDI prior to registration closing. This includes things like the white paper, the exploit, and any further details needed for the entry. Contestants competing in person have until the contest begins to have these deliverables ready.
5. Are you aware a white paper is required for each entry?
This is one aspect that many don’t realize. Each entry in Pwn2Own needs an accompanying white paper describing the vulnerabilities used during the attempt. These white papers are critical in the judging of the competition, especially if exploits from different contestants seem similar. For example, if two groups both use a use-after-free bug against a target, is it the same bug? Maybe. Maybe not. A clearly written white paper will help us understand your research and identify whether it is unique or a bug collision. It also helps the vendor pinpoint the exact place to look at when they start working on the fix.
6. Ask questions before the competition.
There can be a lot of nuances in exploiting targets at Pwn2Own. How will we judge certain scenarios? How will the targets be configured? Does this type of exploit qualify for this bonus? Is the target in this configuration or that configuration? Is this software completely in the default configuration, or is this commonly applied setting used? There are a lot of very reasonable questions to ask before the contest, and we try to answer every one of them the best we can. If you are thinking about participating but have a specific configuration or rule-related questions, please e-mail us. Questions asked over Twitter or other means may not be answered in a timely manner. It might seem archaic to some, but e-mail makes it easier to track inquiries and ensure they get responses.
7. Be prepared for things to go wrong.
Five minutes seems like plenty of time – until you’re on stage at Pwn2Own and there’s a clock counting down. If your first attempt fails, do you have a plan? What are you going to check? Can you adjust your exploit in a meaningful way within the allotted time? Certain types of exploits work better at Pwn2Own than others. For example, timing attacks and race conditions might not be the best choice to use at Pwn2Own. Yes, your exploit may work 100% of the time before you arrive at the contest, but what if it doesn’t when you’re on stage? Make a plan B, and probably a plan C and D as well.
8. Are you participating as an individual, a part of a team, or representing a company?
While we do want maximum participation in each contest, we also need to place some restrictions on how that participation occurs. For example, if you are representing a company, you can’t also participate as an individual. If you are a part of a small team, you can’t also represent a company. This restriction helps keep the contest fair to everyone involved and prevents bug sharing meant to skew the overall results.
9. When you arrive at the contest, take a minute to confirm the target versions.
Before the contest begins – even before we do the drawing for order – we allow contestants to verify configurations and software versions of the targets. We always use the latest and greatest versions of available software as Pwn2Own targets, and vendors are known to release patches right before the competition in a last-ditch attempt to thwart contestants. It’s a good idea to take a minute and double-check the versions in the contest are the same versions you were testing back home. We will communicate the versions before the contest, so you will know what to target.
10. Rub a rabbit’s foot, grab a four-leafed clover, or do whatever else brings you luck.
Thanks to the drawing for order at the beginning of each contest, there is a degree of randomness to the competition. You could end up with a great spot in the schedule, or you could end up late in the contest when the chances for bug collisions are higher. But you can’t rely on luck, either. Some teams will just move on to a new target as soon as they find a bug to try to get as many entries in as possible and hope for a good draw - even if their bugs are low-hanging fruit. However, the teams that really want to compete for Master of Pwn spend a lot of time going deep and finding bugs other teams may miss. Pwn2Own is certainly a competition of skill but having a little luck (at least good luck) never hurts either.
Of course, there’s a lot more to participating in Pwn2Own than just these 10 things, but these will definitely help you prepare for the competition and, hopefully, increase your chances of winning. We really do root for all of the contestants, and we want to do all we can to increase your chances of success. Still, we need to adjudicate the contest fairly for all competitors. If you are on the fence about participating in Pwn2Own, I hope this guidance helps you find the right path to joining us. We celebrate the 15th anniversary of the contest this year in Vancouver, and we’d love to see you there.
What to Expect when Exploiting: A Guide to Pwn2Own Participation
Today at the Black Hat USA conference, we announced some new disclosure timelines. Our standard 120-day disclosure timeline for most vulnerabilities remains, but for bug reports that result from faulty or incomplete patches, we will use a shorter timeline. Moving forward, the ZDI will adopt a tiered approach based on the severity of the bug and the efficacy of the original fix. The first tier will be a 30-day timeframe for most Critical-rated cases where exploitation is detected or expected. The second level will be a 60-day interval for Critical- and High-severity bugs where the patch offers some protections. Finally, there will be a 90-day period for other severities where no imminent exploitation is expected. As with our normal timelines, extensions will be limited and granted on a case-by-case basis.
Since 2005, the ZDI has disclosed more than 10,000 vulnerabilities to countless vendors. These bug reports and subsequent patches allow us to speak from vast experience when it comes to the topic of bug disclosure. Over the last few years, we’ve noticed a disturbing trend – a decrease in patch quality and a reduction in communications surrounding the patch. This has resulted in enterprises losing their ability to accurately estimate the risk to their systems. It’s also costing them money and resources as bad patches get re-released and thus re-applied.
Adjusting our disclosure timelines is one of the few areas that we as a disclosure wholesaler can control, and it’s something we have used in the past with positive results. For example, our disclosure timeline used to be 180 days. However, based on data we tracked through vulnerability disclosure and patch release, we were able to lower that to 120 days, which helped reduce the vendor’s overall time-to-fix. Moving forward, we will be tracking failed patches more closely and will make future policy adjustments based on the data we collect.
Another thing we announced today is the creation of a new Twitter handle: @thezdibugs. This feed will only tweet out published advisories that are either a high CVSS, 0-day, or resulting from Pwn2Own. If you’re interested in those types of bug reports, we ask that you give it a follow. We’re also now on Instagram, and you can follow us there if you prefer that platform over Twitter.
Looking at our published and upcoming bug reports, we are on track for our busiest year ever – for the third year in a row. That also means we’ll have plenty of data to look at as we track incomplete or otherwise faulty patches, and we’ll use this data to adjust these timelines as needed based on what we are seeing across the industry. Other groups may have different timelines, but this is our starting point. With an estimated 1,700 disclosures this year alone, we should be able to gather plenty of metrics. Hopefully, we will see improvements as time goes on.
Until then, stay tuned to this blog for updates, subscribe to our YouTube channel, and follow us on Twitter for the latest news and research from the ZDI.
New Disclosure Timelines for Bugs Resulting from Incomplete Patches
Vulnerabilities and exploits in common targets like browsers are often associated with memory safety issues. Typically this involves either a direct error in memory management or a way to corrupt internal object state in the JavaScript engine. One way to eliminate such memory safety issues is to use a memory-safe language such as Rust or even JavaScript itself. At Pwn2Own Vancouver 2022, Manfred Paul compromised the Mozilla Firefox browser using a full chain exploit that broke the mold. Although his exploit used some memory corruptions, the vulnerable code was written in a memory-safe programming language: JavaScript! In fact, both vulnerabilities used in the chain were related to one rather notorious language aspect of JavaScript – prototypes. In this blog, we will look at the first vulnerability in the chain, which was used to compromise the Mozilla Firefox renderer process. This vulnerability, known as CVE-2022-1802, is a prototype pollution vulnerability in the await implementation. You can find more information about this vulnerability on the Zero Day Initiative advisory page tracked as ZDI-22-799. Mozilla fixed this vulnerability in Firefox 100.0.2 via Mozilla Foundation Security Advisory 2022-19.
Note: this blog series is heavily reliant on the details provided by Manfred Paul at the Pwn2Own competition.
Compromising The Renderer Process
Modern JavaScript features the module syntax, which allows developers to split code into individual files. An even newer feature is the support of asynchronous modules, or, more precisely, the feature known as top level await. In Firefox’s JavaScript engine, SpiderMonkey, large parts of this feature are implemented using built-in JavaScript code. Consider the following function from the SpiderMonkey codebase, in /js/src/builtin/Module.js:
There are three facts we must note the code shown above:
1 -- This function runs in the same JavaScript context as the user’s code. This is true for most JavaScript-based functions in Firefox. This means that global state, including prototypes of global objects, is shared between this built-in code and untrusted website code.
2 -- The function has a default argument of execList = []. In practice, the function is called without specifying this argument (except for the recursive call in the function itself). Therefore, a new empty array object is constructed and used for this argument. Like any other ordinary array, this array object has the unique object Array.prototype as its prototype.
3 -- The function invokes std_Array_push on this array object. The std_Array_push function leads to a call to the Array.prototype.push JavaScript method. While the usage of std_Array_push function instead of Array.prototype.push helps prevent side effects up to a certain point, the function still can interact with the object’s prototype. (Note that in various other places within this same built-in JavaScript file /js/src/builtin/Module.js, a different function is used to assign array values: DefineDataProperty. In contrast to std_Array_push, DefineDataProperty is safe and will not interact in any way with the object’s prototype.)
The semantics of Array.prototype.push with a single argument are very roughly equivalent to the following:
Notably, the assignment is not just the definition of a data property on the object itself. Instead, it searches the object’s prototype chain for existing properties as per usual JavaScript semantics. If the imported module defines a getter/setter for property 0 on the Array prototype (Array.prototype), this assignment operation will trigger the setter function. This call technically violates the ECMAScript specification that defines GatherAsyncParentCompletions in terms of abstract lists and not actual JavaScript arrays. Crucially, this has yet another effect: it leaks the value that is assigned to our setter, so we recover the value “m” representing a module! This object is not the same as the module namespace returned by import(), but rather, it is an internal type of the JavaScript engine not meant to be accessible to untrusted script. It exposes some unsafe methods via its prototype, such as GatherAsyncParentCompletions. Calling GatherAsyncParentCompletions results in a call to the UnsafeSetReservedSlot method, which can be used to achieve memory corruption if we pass in a non-module object.
Triggering The Vulnerability
It is easy to trigger the vulnerability and obtain a Module object:
As described, we simply need to attach a setter to the 0 property of Array.prototype and wait for it to be called. Note that this snippet will only work when imported as a module from another file. The last line exists solely to mark the module as asynchronous, which is needed to trigger the bug.
Achieving Memory Corruption
To achieve memory corruption, we can now call mod.gatherAsyncParentCompletions with an object of the form {asyncParentModules:[obj]}, resulting in a call to UnsafeSetReservedSlot . This will attempt to write the value obj.pendingAsyncDependencies-1 to the internal object slot with number MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT=20. In SpiderMonkey, objects have space for up to 16 so-called fixed slots which are for internal use only. This number is defined by the MAX_FIXED_SLOTS constant. Slots with a higher index are indexed from an array pointed to by the slots_ field. This means our write will be directed to the array pointed to by slots_. No bounds checking exists to make sure that the slots_ array is large enough to accommodate the specified index, because the UnsafeSetReservedSlot function assumes, as the name implies, that the caller will pass only suitable objects.
The general idea now is to:
1 -- Create a new array object.
2 -- Set some named properties of the object to force the allocation of a slots_ array for the object. Among these properties, we should create one with the name pendingAsyncDependencies.
3 -- Write to a few numbered elements of the object to ensure the allocation of elements_ (the backing store for array elements).
By getting the alignment right, slots_[4] will then point to the capacity value of elements_, which we can then overwrite. This is not trivial. Fortunately, the heap allocator is very simple and deterministic. All of the allocations so far will take place in the nursery heap, which is a special area for small short-lived objects. Memory in that area will be allocated by a simple bump allocator. After increasing the capacity, we can write out-of-bounds of the object’s elements_ array and corrupt other nearby objects. From here, arbitrary read and write primitives are easily constructed by overwriting the data pointer of a typed array. Note that corruption in objects in the nursery heap cannot be used for very long since the objects created there will be soon moved to the tenured heap. The best way to proceed is to use corruption in the nursery heap as a first stage only, and immediately use it to produce corruption in the tenured heap. For example, this can be done by corrupting ArrayBuffer objects.
Executing Shellcode
Firefox uses W^X JIT, which means all JIT-produced executable pages are non-writable. This prevents us from overwriting executable JIT code with our shellcode. There is an already well-known method to force JIT to emit arbitrary ROP gadgets by embedding chosen floating-point constants into a JIT-compiled JavaScript function. This results in the appearance of arbitrary short byte sequences in an executable page. Manfred Paul further enhanced this technique. Now it does not even need ROP at all! Instead of using a JavaScript function, the floating-point constants are embedded into a WebAssembly method, so they are compiled into consecutive memory in order of appearance. This makes it possible to insert not just ROP gadgets, but even somewhat longer stretches of shellcode by encoding them in the floating-point constants. There are still some restrictions, though: no 8-byte block may appear twice, or the constant will only be emitted once. Also, due to ambiguity in representation, byte sequences that are equal to NaN might not be encoded correctly. Therefore, Manfred Paul opted for a minimal first-stage shellcode that offers just the following two pieces of functionality:
1 -- The ability to read a pointer from the Windows PEB structure.
2 -- The ability to invoke a function given the function’s address.
The attacker, from ordinary JavaScript, triggers execution of the shellcode’s first function to leak a value from the PEB. Next, the JavaScript uses this value together with the arbitrary read primitive to locate kernel32.dll and its functions in memory. Once it has located the address for VirtualProtect, it invokes the shellcode’s second function to mark the backing store of an ArrayBuffer object as executable, making it possible to run a second-stage shellcode without constraints and compromise the renderer process.
Now that we have code execution inside the renderer, it is time to prepare to attack the sandbox. This will be covered in the second blog, coming next week.
Final Notes
For a long time, developers have tried to fight memory corruption vulnerabilities by introducing various mitigations, and they have succeeded in making it more difficult for attackers to fully compromise applications. However, attackers have also come up with their own creative methods to bypass mitigations. Using a memory-safe programming language is a critical move. If the introduction of memory corruption vulnerabilities can be avoided in the first place, it would not be necessary to rely upon the strength of mitigations. This post looked at a great vulnerability demonstrating that even if you replace existing code with JavaScript, you could still be prone to memory corruption.
Stay tuned to this blog for part two of this series coming next week. Until then, you can find me on Twitter at @hosselot and follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
But You Told Me You Were Safe: Attacking the Mozilla Firefox Renderer (Part 1)
In the first part of this series, we reviewed how Pwn2Own contestant Manfred Paul was able to compromise the Mozilla Firefox renderer process via a prototype pollution vulnerability in the await implementation. In modern browser architecture design, compromising the renderer gets us just half the way there, since the sandbox prevents further damage. In this blog post, we discuss a second prototype pollution vulnerability that allowed the execution of attacker-controlled JavaScript in the privileged parent process, escaping the sandbox. This vulnerability is known as CVE-2022-1529 and is tracked as ZDI-22-798 on the Zero Day Initiative advisory page. Mozilla fixed this vulnerability along with the first one in Firefox 100.0.2 via Mozilla Foundation Security Advisory 2022-19.
Root Cause
As described in the previous post, the exploit compromised the renderer by leveraging a prototype pollution vulnerability in some built-in JavaScript code that executes in the renderer process. For the sandbox escape part of the exploit, the researcher used a second prototype pollution vulnerability. This second vulnerability exists in built-in JavaScript code that runs in the fully privileged parent process, also known as the chrome process (not to be confused with Google’s Chrome browser).
How can the sandboxed renderer process affect JavaScript running in the chrome process? The answer is that the renderer can communicate with the chrome process via various interfaces. In fact, some of these interfaces can be reached directly from JavaScript when running in a “privileged” JavaScript context (not to be confused with any OS-level concept of privilege). As we will see, achieving “privileged” JavaScript execution will be the exploit’s first step.
After achieving privileged JavaScript execution, the exploit can reach out to various endpoints for communication with the chrome process. One of the endpoints is called NotificationDB. It is implemented almost entirely in JavaScript. It processes various messages, which it receives via the content process message manager. In the case of a “Notification:Save” message, a “save” task is queued:
After the “save” task is put on the queue, it is handled in the chrome process, in the “taskSave” function:
At [1], both origin and notification.id are taken directly from the message data sent by the renderer, without any validation. This means we can set either of these to any serializable JavaScript value. More specifically, we can set them to any values supported by the structured clone algorithm, since this is the algorithm used to marshal data from the renderer to the chrome process. If we set origin to the string "__proto__", then this.notifications[origin] will not access a normal data property. Instead, it will access the object’s prototype. This prototype is Object.prototype, since this.notifications is a plain Object. This gives us a prototype pollution primitive. It allows us to write any serializable JavaScript value to any property of Object.prototype with only one restriction: the value we write must have an id property that matches the property name we are writing to.
Using this prototype pollution, we can corrupt the global JavaScript state in the chrome process. This affects all JavaScript that runs in the chrome process, far beyond NotificationDB.jsm itself. Since JavaScript execution contexts are largely shared, all chrome-level JavaScript modules are now exposed to unexpected properties in Object.prototype. The exploit will use this corruption to gain chrome-level XSS during tab restoration, leading to native code execution outside the sandbox.
Now that we have a complete picture of what we want to do, let’s begin.
Achieving Privileged JavaScript Execution
As mentioned above, before we can invoke NotificationDB, we need to access a privileged JavaScript context. In particular, what we need is access to an object called components. This is a different object than a much more limited object confusingly also named Components, which is intended to be exposed to untrusted script.
To gain access to components, the attacker script performs the following steps. Note that all this is made possible because the attacker script has already gained full native code execution within the renderer sandbox, as detailed in part one of this series:
1 -- Mark the current JavaScript compartment as system by setting the corresponding flag in memory. 2 -- Patch CanCreateWrapper to always return NS_OK. This prevents further security checks on the calling context. 3 -- Call the GetComponents method to add the components object to the scope.
Triggering the Prototype Pollution Primitive
Once we have obtained the components object, we are nearly ready to trigger the prototype pollution. One obstacle remains: due to the details of Firefox's “cross-compartment” handling of JavaScript objects, the ContentProcessMessageManager object we want to access is hidden behind an opaque proxy object. This can be circumvented by reading the proxy’s underlying object pointer and using a “fakeObj” to convert it to a JavaScript object. We can now call the vulnerable NotificationDB interface:
Remember that a limitation applies to the way that we can overwrite properties of Object.prototype: we can set any property name to any value val, but val.id must equal name. For our purposes, the exact value of val will not matter. Only its string representation is important (more precisely, the result of running the ECMAScript ToString algorithm). The loose type system of JavaScript helps us here. Consider the following array object:
This object has its id property set to the arbitrary string "foo", but ToString will represent the object by just the string "bar". Therefore, as long as we only care about the string representation, we can set any property of Object.prototype to any value we desire.
Leveraging the Prototype Pollution for Sandbox Escape
Note that a for ... in loop will traverse all properties found in the prototype chain, and not only the properties found on the object itself. Therefore, by invoking the code shown above after we have polluted Object.prototype, we can cause tab.setAttribute to be called with arbitrary parameters. This will set an arbitrary HTML (technically XUL) attribute of a tab.
How can we cause this function to run? It turns out that the only time it is called is during the restoration of tabs. There are multiple ways to trigger this functionality:
1 -- Session restoration after restarting the browser. 2 -- Use of the “reopen closed tab” feature (Ctrl+Shift+T). 3 -- Reactivating a tab after “Tab Unloading”, which occurs when Firefox starts to run out of memory. 4 -- Automatically restoring a tab after it has crashed.
The first choice is not an option, since restarting the browser would not preserve the polluted prototype. In the real world, waiting for option #2 might work, but it requires user interaction, making it unsuitable for Pwn2Own. It’s also possible to force option #3 by allocating large chunks of memory. However, by default, it takes at least 10 minutes of inactivity before unloading will happen, which exceeds the Pwn2Own time constraint. This leaves just option #4. Fortunately, crashing the renderer process is trivial: we have already achieved memory corruption, and we can simply write to an invalid address to force a segmentation fault.
So far, the sandbox escape exploit proceeds as follows:
1 -- Trigger the prototype pollution, adding a property and value to Object.prototype in the chrome process. The name/value pair we add corresponds to the parameters we want to pass to tab.setAttribute. For example, if we add a property named "a" with string value "b", then tab.setAttribute will ultimately be invoked with parameters ("a", "b"). 2 -- Open a new background tab. Note that a simple window.open method call without prior user interaction is blocked by the popup blocker. However, the check is entirely renderer-side, and the services.ww.openWindow API obtained from the components object has no such restriction. 3 -- In this background tab, crash the renderer. The chrome process will immediately restore the background tab. The polluted prototype will cause the tab restoration logic to set our chosen attribute on the tab.
Next, we must consider: what parameters do we want to pass to tab.setAttribute? As the browser UI that contains the tab element is written not in HTML but rather the similar XUL markup language, attributes such as “onload” or “onerror” that are commonly used for XSS do not seem to work. Going through a list of XUL event handlers, there are only two that seem to work without any direct user interaction: “onoverflow” and “onunderflow”. These are triggered when the tab’s title text starts to exceed or no longer exceeds the available space. We can trigger the former by setting a style attribute with the value text-indent: 500px.
Once we have achieved JavaScript execution within the chrome process, there are many ways to complete the sandbox escape. For example, we could disable all sandboxing in the future by setting a preference:
Afterward, the exploit could run script in a new tab, which will be created without any sandbox protections. Alternatively, it could run script directly in the chrome process. Either way, the file and process APIs that are available in chrome-level JavaScript can be used to gain native code execution not constrained by any sandbox:
Here is a short video demonstrating running the full exploit against Mozilla Firefox 100.0.1 (64-bit):
Final Notes
Modern browsers process large volumes of data coming from numerous untrusted sources. Modern browser architecture goes a long way towards containing damage in cases where the renderer process is compromised. However, there remain multiple security checks that are performed on the renderer side. We have seen how these checks could be bypassed, ultimately leading to full compromise of the main browser process. In general, it is wise to reduce renderer-side security checks and move them to the main process wherever it is practical.
You can find me on Twitter at @hosselot and follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
But You Told Me You Were Safe: Attacking the Mozilla Firefox Sandbox (Part 2)
Contest Rule Updates: September 2: Due to sourcing issues with the original model, we are adding the Lexmark MC3224i printer as a target. October 21: Due to continued sourcing issues, the Lexmark MC3224adwe printer has been removed from the competition. November 29: Added Google Nest Audio to the smart speaker category and announced Google as an event sponsor.
If you just want to read the rules, you can find them here.
Our Fall Pwn2Own event has become a bit of a nomad, having gone from Amsterdam to Tokyo to Austin. This year, we’re heading to Toronto to celebrate the 10th anniversary of the contest formerly known as Mobile Pwn2Own. Since 2012, we’ve expanded the contest to include devices beyond phones. This year is no different, with devices typically found in homes and home offices.
Pwn2Own Toronto will be held at our Toronto office on December 6-8, 2022. While this year’s contest isn’t being held in conjunction with a conference, we still want contestants to attend in person. In fact, we want them there so much that we’re going to put our money where our mouth is by reimbursing $3,000 for travel expenses for teams that participate in Toronto. We’re also going to try to have some sort of audience there as well, but we’re not offering cash just to watch. If you are a former Pwn2Own winner and would like more information about this program, you know how to get in touch with us.
If you can’t be in Toronto due to travel restrictions or travel safety concerns, you can opt to compete remotely. You will still need to register before the contest deadline (December 2, 2022) and submit a detailed whitepaper completely explaining your exploit chain and instructions on how to run the entry by December 5, 2022. A member of the ZDI staff in Toronto will run your exploit for you. All attempts will be filmed and available for viewing by the contestant and the vendor. As in the past, we will work with remote contestants to monitor the attempt in real-time via a phone call or video chat. Please note that since you are not in person, changes to exploits/scripts/etc. will not be possible, which could lower your chance of winning should something unexpected occur.
As for the contest itself, we’re pleased to welcome back Synology as a co-sponsor of the competition. We’re also happy to have Google co-sponsor the event. We’re also excited to announce a special challenge for this year’s contest we’re calling the “SOHO Smashup” (as in Small Office/Home Office). This is a real-world scenario of how a threat actor would exploit a home office, so we wanted to include it here, too. It works like this; a contestant picks a router and begins by exploiting the WAN interface. They must then pivot into the LAN to their choice of second target – one of the other devices in the contest. For example, you could pick the TP-Link router and the HP printer. If you compromise both, you’ll win $100,000 and 10 Master of Pwn points.
Beyond that, the contest remains largely the same as in previous years. We will have a random drawing to determine the schedule of attempts on the first day of the contest, and we will proceed from there. Our intention with allowing remote participation is to provide as many people as possible with the benefits of participating in Pwn2Own while still treating all contestants as equally as possible. As always, if you have questions, please contact us at [email protected]. We will be happy to address your issues or concerns directly.
Now on to the specific target categories. We’ll have seven different categories for this year’s event:
Let’s take a look at each category in more detail, starting with mobile phones.
The Target Phones
Back when this version of Pwn2Own started in 2012, it was called Mobile Pwn2Own, and phones are still at the heart of our fall event. As always, these phones will be running the latest version of their respective operating systems with all available updates installed. We’ve increased the rewards on these targets to add further incentives to these handsets.
In this category, contestants must compromise the device by browsing to content in the default browser for the target under test or by communicating with the following short-distance protocols: near field communication (NFC), Wi-Fi, or Bluetooth. The awards for this category are:
The Google and Apple devices in this category also include an add-on bonus. If your exploit payload executes with kernel-level privileges, you earn an additional $50,000 and 5 more Master of Pwn points. That means a full exploit chain for the iPhone or Pixel that includes kernel-level access will earn $250,000.
You connect to the world through your local wireless router, and the world has the opportunity to reach back to you. In the past, successful demonstrations included some flair by having the LED lights flash in different patterns. In addition to the home office routers, we have some devices typically used by SMBs as well. An attempt in this category must be launched against the target’s exposed network services from the contestant’s device within the contest network.
As people add smart devices to their homes, they tend to add a hub to centralize control of all of those devices. From lights, to locks, to thermostats, cameras, and more, all can be accessed through a home automation hub. Of course, that means a threat actor could potentially access them as well. Three of the most popular smart hubs are included in this year’s event.
Exploits involving printing capabilities have made quite a bit of news over the last couple of years, with ransomware gangs incorporating PrintNightmare bugs in their exploit kits. In last year’s contest, one printer was turned into a jukebox playing classic rock. It will be interesting to see what exploits the contestants come up with this year.
Smart speakers continue to play a large part in our daily interactions with music, news, and more. They also offer an attack surface for threat actors to target. For this event, Pwn2Own Toronto has three targets available in this category.
NAS devices make their return to Pwn2Own, and both Synology and Western Digital have returned as targets with their latest offerings. Last year’s event exposed some industry-wide Netatalk bugs. Time will tell if this year’s event has a similar impact. An attempt in this category must be launched against the target’s exposed network services from the contestant’s laptop within the contest network.
With more and more people working from home, many enterprises have found their network perimeter move to the home office as well. Threat actors who exploit home routers and consumer devices can use these as a launch point for lateral movements into enterprise resources. We wanted to demonstrate this during the contest, so we’re introducing the SOHO Smashup category to show how this could happen. Contestants will need to first compromise the WAN port on a selected router. Once they accomplish that, they will need to pivot to one of the other devices and compromise it as well. The contestant is free to select any combination of router and home automation hub, smart speaker, printer, or network attached storage device during the registration process. If they get both devices within 30 minutes, they earn $100,000 and 10 Master of Pwn points. We’re hopeful several contestants will use this category to choose their own (mis)adventure.
No Pwn2Own contest would be complete without crowning a Master of Pwn, which signifies the overall winner of the competition. Earning the title results in a slick trophy, a different sort of wearable, and brings with it an additional 65,000 ZDI reward points (instant Platinum status in 2023).
For those not familiar with how it works, points are accumulated for each successful attempt. While only the first demonstration in a category wins the full cash award, each successful entry claims the full number of Master of Pwn points. Since the order of attempts is determined by a random draw, those who receive later slots can still claim the Master of Pwn title – even if they earn a lower cash payout. As with previous contests, there are penalties for withdrawing from an attempt once you register for it. If the contestant decides to remove an Add-on Bonus during their attempt, the Master of Pwn points for that Add-on Bonus will be deducted from the final point total for that attempt. For example, someone registers for the Apple iPhone 13 with the Kernel Bonus Add-on. During the attempt, the contestant drops the Kernel Bonus Add-on but completes the attempt. The final point total will be 15 Master of Pwn points.
The Complete Details
The full set of rules for Pwn2Own Toronto 2022 can be found here. They may be changed at any time without notice. We highly encourage potential entrants to read the rules thoroughly and completely should they choose to participate. We also encourage contestants to read this blog covering what to expect when participating in Pwn2Own.
Registration is required to ensure we have sufficient resources on hand at the event. Please contact ZDI at [email protected] to begin the registration process. (Email only, please; queries via Twitter, blog post, or other means will not be acknowledged or answered.) If we receive more than one registration for any category, we’ll hold a random drawing to determine the contest order. Registration closes at 5:00 p.m. Eastern Daylight Time on December 2, 2022.
The Results
We’ll be blogging and tweeting results in real-time throughout the competition. Be sure to keep an eye on the blog for the latest information. Follow us on Twitter at @thezdi and @trendmicro, and keep an eye on the #P2OToronto hashtag for continuing coverage.
We look forward to seeing everyone in Toronto and online, and we look forward to seeing what new exploits and attack techniques they bring with them.
With special thanks to our Pwn2Own Toronto 2022 sponsors, Synology and Google, for providing their assistance and technology.
In this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, Quintin Crist and Dusan Stevanovic of the Trend Micro Research Team detail a recently patched remote code execution vulnerability in the Microsoft Windows operating system, originally discovered and reported by the researcher known as Arimura. The bug is the result of a dynamically allocated buffer created by an NFS function and is present only on Windows Server 2022. An unauthenticated attacker could exploit this bug to execute arbitrary code in the context of SYSTEM. This is the third such NFS vulnerability in as many months. The following is a portion of their write-up covering CVE-2022-34715, with a few minimal modifications.
A remote code execution vulnerability exists in Windows Network File System. The vulnerability is due to incorrect validation of fields within an NFS request. A remote attacker can exploit this vulnerability by sending malicious RPC calls to a target server. Successful exploitation results in arbitrary code execution in the context of SYSTEM. Unsuccessful exploitation may result in a crash of the target system.
The Vulnerability
Microsoft Windows ships with several network features designed to communicate and interact with non-Windows file shares. One of these modules is called Network File System (NFS).
NFS is a protocol originally developed by Sun Microsystems in 1984. Version 2 is documented in RFC 1094. Version 3 is documented in RFC 1813. Version 4 was developed by the IETF and is documented in RFC 3010 (released December 2000) and revised in RFC 3530 (released April 2003) and RFC 7530 (released March 2015). NFS allows users to access remote file shares in the same way that the local file system is accessed. Different access levels and permissions can be set on shares, such as read-write and read-only. Additionally, IP/UID/GID/Kerberos security can be used. NFS uses Open Network Computing (ONC) Remote Procedure Call (RPC) to exchange control messages. ONC RPC was originally developed by Sun Microsystems and can also be referred to as Sun RPC.
When ONC RPC messages are transferred over TCP, they are prepended with a Fragment header structure (as illustrated in the following table) that specifies the length of the message. This allows the receiver to distinguish multiple messages sent over a single TCP session. Other protocols such as UDP do not use this field. Note that all multi-byte values are encoded in big-endian byte order.
The structure of ONC RPC request messages, in general, is as follows:
The Credentials structure in a Sun-RPC message has the following structure:
The Flavor field in the above structure serves as a type identifier of the Contents data. Security flavors have been called authentication flavors for historical reasons. There are multiple security flavors defined in the RPC specification, such as AUTH_NONE(0), AUTH_SYS(1), AUTH_SHORT(2), AUTH_DH(3), and RPCSEC_GSS(6).
The Contents field for the flavor RPCSEC_GSS has the following structure:
There are four types defined for the GSS Procedure field: RPCSEC_GSS_DATA(0), RPCSEC_GSS_INIT(1), RPCSEC_GSS_CONTINUE_INIT(2), and RPCSEC_GSS_DESTROY(3). Also, for the GSS Service field, there are three types: rpc_gss_svc_none(1), rpc_gss_svc_integrity(2), and rpc_gss_svc_privacy(3). When using RPCSEC_GSS to authenticate RPC clients, a security context must be created by using RPCSEC_GSS_INIT and RPCSEC_GSS_CONTINUE_INIT RPC messages. First, the RPC client sends an RPCSEC_GSS_INIT message to start the creation of the context. Then, the RPC server decides whether it needs another token for the creation. If so, the server replies with a GSS_S_CONTINUE_NEEDED message, and the client needs to send an RPCSEC_GSS_CONTINUE_INIT message to continue.
If the GSS Service field is set to 2 (rpc_gss_svc_integrity), the Program-specific data field is prefixed with the following structure:
If the GSS Service field is set to 3 (rpc_gss_svc_privacy), the Program-specific data field is encrypted.
When the Program field is set to 100003 (NFS) and the Procedure field is set to 1 (Compound), the Program-specific data field has the following structure:
In the request data, for each operation in the message:
Attributes Data (fattr4) has the following format:
Attributes Data for ACL ( Bit12, 0x1000 ):
A buffer overflow vulnerability exists in the Windows implementation of NFS. The vulnerability is due to incorrect validation of the of the ACE_Count field when processing ACL attribute data in Nfs4SrvAclBuildWindowsAclsFromNfsAcl.
This function is only vulnerable when setting ACL attribute data using opcodes 6, 18, 34.
The server allocates a response buffer of size (ACE_Count << 5). This size is stored as a uint64_t in Nfs4SrvAclBuildWindowsAclsFromNfsAcl. A buffer of this size is created using NfsMemMgrBufferAllocate. However, NfsMemMgrBufferAllocate only takes a uint32_t for the buffer size, so the upper 32 bits of the requested size is ignored.
This allows an attacker to specify an ACE_Count such that (ACE_Count << 5) & 0xFFFFFFFF < ACE_Count. This will result in a buffer overflow later in the function when the buffer is used.
In particular, ACE_Count values above 0x8000000 will trigger this vulnerability.
Note that ACE_Count = 0x8000000 itself is not vulnerable since NfsMemMgrBufferAllocate will error when the requested length is zero.
An attacker can use this vulnerability to overflow a heap buffer. Successful exploitation may result in arbitrary code execution in the context of SYSTEM. Unsuccessful exploitation will result in a crash of the target system.
Source Code Walkthrough
The following code snippet was taken from nfssvr.sys version 10.0.20348.825. Comments have been added by Trend Micro researchers.
Detecting Attacks
The detection device needs to check if the Program field in an RPC request message has the value 100003 (NFS), Procedure field has the value 1 (COMPOUND), and Program Version field has the value 4 (NFS4). If found, the device must inspect the Program-specific data in the ONC RPC messages.
The detection device should check for the vulnerable opcodes (6, 18, 34) in each operation. If present the device should check the operation for ACL attribute data. If ACL attribute data is present, the device should check for an ACE_Count field above 0x8000000.
There is no fixed offset into the message that can be used to ignore non-vulnerable opcodes since NFS operations do not consistently contain a length of the operation data. The full message must be processed to determine if there is any ACL attribute data.
If the ACE_Count field is greater than 0x8000000, the traffic should be considered suspicious; an attack exploiting this vulnerability is likely underway.
Conclusion
This bug was patched by Microsoft in August 2022 and assigned CVE-2022-34715. Their advisory lists the vulnerability as not requiring authentication. However, all known exploitation paths require file creation or modification privileges. In their write-up, they also list disabling NFSv4.1 as a method to mitigate attacks. However, this could lead to a loss of functionality. Applying the NFS-related updates is the best method to fully address the multiple NFS bugs patched in recent months.
Special thanks to Quintin Crist and Dusan Stevanovic of the Trend Micro Research Team for providing such a thorough analysis of this vulnerability. For an overview of Trend Micro Research services please visit http://go.trendmicro.com/tis/.
The threat research team will be back with other great vulnerability analysis reports in the future. Until then, follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
CVE-2022-34715: More Microsoft Windows NFS v4 Remote Code Execution
In my first blog post covering bugs in Ivanti Avalanche, I covered how I reversed the Avalanche custom InfoRail protocol, which allowed me to communicate with multiple services deployed within this product. This allowed me to find multiple vulnerabilities in the popular mobile device management (MDM) tool. If you aren’t familiar with it, Ivanti Avalanche allows enterprises to manage mobile device and supply chain mobility solutions. That’s why the bugs discussed here could be used by threat actors to disrupt centrally managed Android, iOS and Windows devices. To refresh your memory, the following vulnerabilities were presented in the previous post:
· Five XStream insecure deserialization issues, where deserialization was performed on the level of message handling. · A race condition leading to authentication bypass, wherein I abused a weakness in the protocol and the communication between services.
This post is a continuation of that research. By understanding the expanded attack surface exposed by the InfoRail protocol, I was able to discover an additional 20 critical and high severity vulnerabilities. This blog post takes a detailed look at three of my favorite vulnerabilities, two of which have a rating of CVSS 9.8:
· CVE-2022-36971 – Insecure deserialization. · CVE-2021-42133 – Arbitrary file write/read through the SMB server. · CVE-2022-36981 – Path traversal, delivered with a fun authentication bypass.
Each of these three vulnerabilities leads to remote code execution as SYSTEM.
CVE-2022-36971: A Tricky Insecure Deserialization
I discovered the first vulnerability when I came across an interesting class named JwtTokenUtility, which defines a non-default constructor that could be a potential target:
At [1], the function base64-decodes one of the arguments.
At [2], it checks if the publicOnly argument is true.
If not, it deserializes the base64 decoded argument at [3].
This looks like a possible insecure deserialization sink. In addition, it is invoked from many locations within the codebase. The following screenshot illustrates several instances where it is invoked with the first argument set to false:
Figure 1 - Example invocations of JwtTokenUtility non-default constructor
It turned out that most of these potential vectors require control over the SQL database. The serialized object is retrieved from the database, and I found no direct way to modify this value. Luckily, there are two services with a more direct attack vector: the Printer Device Server and the Smart Device Server. The exploitation of both services is almost identical. We will focus on the Printer Device Server (PDS).
Let’s have a look at the PDS AmcConfigDirector.createAccessTokenGenerator method:
At [1], it uses acctApi.getGlobal to retrieve an object that implements IGlobal.
At [2], it retrieves the pkk string by calling global.getAccessKeyPair.
At [3], it decrypts the pkk string by calling PasswordUtils.decryptPassword. We are not going to analyze this decryption routine. This decryption function implements a fixed algorithm with a hardcoded key, thus the attacker can easily perform the encryption or decryption on their own.
At [4], it invokes the vulnerable JwtTokenUtility constructor, passing the pkk string as an argument.
At this point, we are aware that there is potential for abusing the non-default JwtTokenUtility constructor. However, we are missing two things:
-- How can we control the pkk string? -- How can we reach createAccessTokenGenerator?
Let’s start with the control of the pkk string.
Controlling the value of pkk
To begin, we know that:
-- The code retrieves an object to assign to the global variable. This object implements IGlobal. -- It calls the global.getAccessKeyPair getter to retrieve pkk.
There is a Global class that appears to control the PDS service global settings. It implements the IGlobal interface and both the getter and the setter for the accessKeyPair member, so this is probably the class we’re looking for.
Next, we must look for corresponding setAccessKeyPair setter calls. Such a call can be found in the AmcConfigDirector.processServerProfile method.
At [1], processServerProfile accepts the config argument, which is of type PrinterAgentConfig.
At [2], it retrieves a list of PropertyPayload objects by calling config.getPayload.
At [3], the code iterates over the list of PropertyPayload objects.
At [4], there is a switch statement based on the property.name field.
At [5], the code checks to see if property.name is equal to the string "webfs.ac.ppk".
If so, it calls setAccessKeyPair at [6].
So, the AmcConfigDirector.processServerProfile method can be used to control the pkk value. Finally, we note that this method can be invoked remotely through a ServerConfigHandler InfoRail message:
At [1], we see that this message type can be accessed through the subcategory 1000000 (see first blog post - Message Processing and Subcategories section).
At [2], the main processMessage method is defined. It will be called during message handling.
At [3], the code retrieves the message payload.
At [4], it calls the second processMessage method.
At [5], it deserializes the payload and casts it to the PrinterAgentConfig type.
At [6], it calls processServerProfile and provides the deserialized config object as an argument.
Success! We can now deliver our own configuration through the ServerConfigHandler method of the PDS server. This method can be invoked through the InfoRail protocol. Next, we need to get familiar with the PrinterAgentConfig class to prepare the appropriate serialized object.
It has a member called payload, which is of type List<PropertyPayload>.
PropertyPayload has two members that are interesting for us: name and value. Recall that the processServerProfile method does the following:
-- Iterates through the list of PropertyPayload objects with a for loop. -- Executes switch statement based on PropertyPayload.name. -- Sets values based on PropertyPayload.value.
With this in mind, we can understand how to deliver a serialized object and control the pkk variable. We have to prepare an appropriate gadget (we can use the Ysoserial C3P0 or CommonsBeanutils1 gadgets), encrypt it (decryption will be handled by the PasswordUtils.decryptPassword method) and deliver through the InfoRail protocol.
The properties of the InfoRail message should be as follows:
-- Message subcategory: 1000000. -- InfoRail distribution list address: 255.3.5.15 (PDS server).
Here is an example payload:
The first step of the exploitation is completed. Next, we must find a way to call the createAccessTokenGenerator function.
Triggering the Deserialization
Because the full flow that leads to the invocation of createAccessTokenGenerator is extensive, I will omit some of the more tedious details. We will instead focus on the InfoRail message that allows us to trigger the deserialization via the needFullConfigSync function. Be aware that the PDS server frequently performs synchronization operations, but typically does not perform a synchronization of the full configuration. By calling needFullConfigSync, a full synchronization will be performed, leading to execution of doPostDeploymentCleanup:
At [1], the code invokes our target method, createAccessTokenGenerator.
The following snippet presents the NotificationHandler message, which calls the needFullConfigSync method:
At [1], the message subcategory is defined as 2200.
At [2], the main processMessage method is defined.
At [3], the payload is deserialized and casted to the NotifyUpdate type (variable nu).
At [4], the code iterates through the entries of the NotifyUpdateEntry object that was obtained from nu.getEntries.
At [5], [6], and [7], the code checks to see if entry.ObjectType is equal to 61, 64, or 59.
If one of the conditions is true, the code sets the universalDeployment variable to true value at [8], [9], or [10], so that needFullConfigSync will be called at [11].
The last step is to create an appropriate serialized message object. An example payload is presented below. Here, the objectType field is equal to 61.
The attacker must send this payload through a message with the following properties:
-- Message subcategory: 2200. -- InfoRail distribution list address: 255.3.5.15 (PDS server).
To summarize, we must send two different InfoRail messages to exploit this deserialization issue. The first message is to invoke ServerConfigHandler, which delivers a serialized pkk string. The second message is to invoke NotificationHandler, to trigger the insecure deserialization of the pkk value. The final result is a nice pre-auth remote code execution as SYSTEM.
CVE-2021-42133: One Vuln to Rule Them All - Arbitrary File Read and Write
Ivanti Avalanche has a File Store functionality, which can be used to upload files of various types. This functionality has been already abused in the past, in CVE-2021-42125, where an administrative user could:
-- Use the web application to change the location of the File Storage and point it to the web root. -- Upload a file of any extension, such as a JSP webshell, through the web-based functionality. -- Use the webshell to get code execution.
The File Store configuration operations are performed through the Enterprise Server, and they can be invoked through InfoRail messages. I quickly discovered three interesting properties of the File Store:
It supports Samba shares. Therefore, it is possible to connect it to any reachable SMB server. The attacker can set the File Store path pointing to his server by specifying a UNC path.
Whenever the File Store path is changed, Avalanche copies all files from the previous File Store directory to the new one. If a file of the same name already exists in the new location, it will be overwritten.
The File Store path can also be set to any location in the local file system.
These properties allow an attacker to freely exchange files between their SMB server and the Ivanti Avalanche local file system. In order to modify the File Store configuration, the attacker needs to send a SetFileStoreConfig message:
At [1], the subcategory is defined as 1501.
At [2], the standard Enterprise Server processMessage method is defined. The implementation of message processing is a little bit different in the Enterprise Server, although the underlying idea is the same as in previous examples.
At [3] and [4], the method saves the new configuration values.
The only thing that we must know about the saveConfig method is that it overwrites all the properties with the new ones provided in the serialized payload. Moreover, some of the properties, such as the username and password for the SMB share, are encrypted in the same manner as in the previously described deserialization vulnerability.
To sum up this part, we must send an InfoRail message with the following properties:
--Message subcategory: 1501. --Message distribution list: 255.3.2.5 (Enterprise Server).
Below is a fragment of an example payload, which sets the File Store path to an attacker-controlled SMB server:
Arbitrary File Read Scenario
The whole Arbitrary File Read scenario can be summarized in the following picture:
Figure 2 - Example scenario for the Arbitrary File Read exploitation
The attacker points the File Store to a non-existent SMB share. This step is optional, but makes the exploit cleaner by ensuring that files from the current File Store location will not be copied to the location where the attacker wants to retrieve the files.
The attacker points the File Store to a desired local file system path from which he wants to disclose files.
The attacker points the File Store to his SMB share.
Files from the previous File Store path (local file system) are transferred to the attacker’s SMB share.
The following screenshot presents an example exploitation of this scenario:
Figure 3 - Exploitation of the Arbitrary File Read scenario
As shown, the exploit is targeting the main Ivanti Avalanche directory: C:\Program Files\Wavelink\Avalanche.
The following screenshot presents the exploitation results. Files from the Avalanche main directory were gradually copied to the attacker’s server:
Figure 4 - Exploitation of the Arbitrary File Read scenario - results
Arbitrary File Write Scenario
The following screenshot presents the Arbitrary File Write scenario:
Figure 5 - Example scenario for the Arbitrary File Write scenario
The attacker creates an SMB share that contains the JSP webshell.
The attacker points the File Store to a non-existent SMB share. This step is optional, but makes the exploit cleaner by ensuring that files from the current File Store location will not be copied to the Avalanche webroot.
The attacker points the File Store to the SMB share containing the webshell file.
The attacker points the File Store to the Ivanti Avalanche webroot directory.
Avalanche copies the webshell to the webroot.
The attacker executes code through the webshell.
The following screenshot presents an example exploitation attempt. It uploads a file named poc-upload.jsp to C:\Program Files\Wavelink\Avalanche\Web\webapps\ROOT:
Figure 6 - Exploitation of the Arbitrary File Write scenario
Finally, one can use the uploaded webshell to execute arbitrary commands.
Figure 7 - Executing arbitrary code via the webshell
CVE-2022-36981: Path Traversal in File Upload, Plus Authentication Bypass
We made it to the final vulnerability we will discuss today. This time, we will exploit a path traversal vulnerability in the Avalanche Smart Device Server, which listens on port TCP 8888 by default. However, InfoRail will play a role during the authentication bypass that allows us to reach the vulnerable code.
Path Traversal in File Upload
Our analysis begins with examining the uploadFile method.
At [1], the endpoint path is defined. The path contains two arguments: uuid and targetbasename.
At [2], the doUploadFile method is called.
Let’s start with the second part of the doUploadFile method, as I want to save the authentication analysis for later in this section.
At [1], the uploadPath string is obtained by calling getUploadFilePath. This method accepts two controllable input arguments: uuid and baseFileName.
At [2], the method instantiates a File object based on uploadPath.
At [3], the method invokes writeToFile, passing the attacker-controlled input stream together with the File object.
We will now analyze the crucial getUploadFilePath method, as this is the method that composes the destination path.
At [1], it constructs deviceRoot as an object of type File. The parameters passed to the constructor are the hardcoded path obtained from getCachePath() and the attacker-controllable uuid value. As shown above, uuid is not subjected to any validation, so we can perform path traversal here.
At [2], the code verifies that the deviceRoot directory exists. From here we see that uuid is intended to specify a directory. If the directory does not exist, the code creates it at [3].
At [4], it validates the attacker-controlled baseFileName against a regular expression. If the validation fails, baseFileName is reassigned at [5].
At [6], it creates a new filename fn, based on the current datetime, an integer value, and baseFileName.
At [7], it instantiates a new object of type File. The path for this File object is composed from uuid and fn.
After ensuring that the file does not already exist, the file path is returned at [8].
After analyzing this method, we can draw two conclusions:
-- The uuid parameter is not validated to guard against path traversal sequences. An attacker can use this to escape to a different directory. -- The extension of baseFileName is not validated. An attacker can use this to upload a file with any extension, though the filename will be prepended with a datetime and an integer.
Ultimately, when doUploadFile calls writeToFile, it will create a new file with this name and write the attacker-controlled input stream to the file. This makes it seem that we can exploit this as a path traversal vulnerability and write an arbitrary file to the filesystem. However, there are two major obstacles that will be presented in the next section.
Authentication and Additional UUID Verification
Now that we’ve covered the second part, let’s go back and analyze the first part of the doUploadFile method.
At [1], the code retrieves the mysterious testFlags.
At [2], it validates the length of the uuid, to ensure it is at least 5 characters long.
At [3], it performs an authorization check (perhaps better thought of as an authentication check) by calling isAuthorized. This method accepts uuid, credentials (authorization), and testFlags.
At [4], the code retrieves the deviceId based on the provided uuid.
At [5], the code checks to see if any device was retrieved. If not, it checks for a specific value in testFlags at [6]. If this second check is also not successful, the code raises an exception.
At [7], it calls allowUpload to perform one additional check. However, this final check has nothing to do with validating uuid. It only verifies the amount of available disk space, and this should not pose any difficulties for us.
We can spot two potential roadblocks:
-- There is an authentication check. -- There is a check on the value of uuid, in that it must map to a known deviceId. However, we can bypass this check if we could get control over testFlags. If testFlags & 0x100 is not equal to 0, the exception will not be thrown, and execution will proceed.
Let’s analyze the most important fragments of the isAuthorized method:
At [1], the method retrieves enrollmentId, found within the token submitted by the requester.
At [2], it tries to retrieve the enrollment object from the database, based on enrollmentId.
At [3], it checks to see if enrollment was retrieved.
Supposing that enrollment was not retrieved successfully, the code checks for a particular value in testFlags at [4]. If not, it will return false at [6]. But if the relevant value is found in testFlags, the authentication routine will return true at [5], even though the requester’s authorization token did not contain a valid enrollmentId.
Note that this method also checks an enrollment password, although that part is not important for our purposes.
Here as well, testFlags can also be used to bypass the relevant check. Hence, if we can control testFlags, neither the authentication nor the uuid validation will cause any further trouble for us.
Here is where InfoRail comes into play. It turns out that the Smart Device Server AgentTaskHandler message can be used to modify testFlags:
At [1], it retrieves flagsToSet from the sds.modflags.set property.
At [2], it obtains the Config Directory API interface.
At [3], it uses flagsToSet to calculate the new flags value.
At [4], it saves the new flag value.
To sum up, an attacker can control testFlags, and use this to bypass both the authentication check and the uuid check.
Exploitation
Exploitation includes two steps.
1) Set testFlags to bypass the authentication and the uuid check.
To modify the testFlags, the attacker must send an InfoRail message with the following parameters:
2) Exploit the path Traversal through a web request
The path traversal can be exploited with an HTTP Request, as in the following example:
The response will return the name of the uploaded webshell:
Finally, an attacker can use the uploaded JSP webshell for remote code execution as SYSTEM.
Figure 8 - Remote Code Execution with the uploaded webshell
Conclusion
I really hope that you were able to make it through this blog post, as I was not able to describe those issues with a smaller number of details (believe me, I have tried). As you can see, undiscovered attack surfaces can lead to both cool and dangerous vulnerabilities. It is something that you must look for, especially in products that are responsible for the administration of many other devices.
This blog post is the last in this series of articles on Ivanti Avalanche research. However, I am planning something new, and yes, it concerns Java deserialization. Until then, you can follow me @chudypb and follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
Riding the InfoRail to Exploit Ivanti Avalanche – Part 2
Another Patch Tuesday is upon us, and Adobe and Microsoft have released a bevy of new security updates. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for September 2022
For September, Adobe released seven patches addressing 63 in Adobe Experience Manager, Bridge, InDesign, Photoshop, InCopy, Animate, and Illustrator. A total of 42 of these bugs were reported by ZDI Sr Vulnerability Researcher Mat Powell. The update for InDesign is the largest patch this month, with eight Critical-rated and 10 Important-rated vulnerabilities receiving fixes. The most severe of these could lead to code execution if a specially crafted file is opened on an affected system. The patch for Photoshop fixes 10 CVEs, nine of which are rated Critical. Again, an attacker can get code execution if they can convince a user to open a malicious file. The fix for InCopy fixes five similar code execution bugs and two info disclosure bugs. Adobe Animate also receives patches for two Critical-rated code execution bugs.
The update for Adobe Bridge corrects 10 Critical-rated code execution bugs and two Important-rated info disclosure bugs. One of the three Illustrator vulnerabilities getting patched could also lead to code execution. As with the bugs previously mentioned, a user would need to open a malicious file with an affected software version. Finally, the patch for Adobe Experience Manager addresses 11 Important-rated bugs, primarily of the cross-site scripting (XSS) variety.
None of the bugs fixed by Adobe this month are listed as publicly known or under active attack at the time of release. Adobe categorizes these updates as a deployment priority rating of 3.
Apple Patches for September 2022
Yesterday, Apple released updates for iOS, iPadOS, macOS, and Safari. They also released updates for watchOS and tvOS but provided no details on any of the fixes included in these patches. Two of the bugs patched by Apple were identified as being under active exploit. The first is a kernel bug (CVE-2022-32917) resulting from improper bounds checking. It affects iOS 15 and iPadOS 15, macOS Big Sur, and macOS Monterey. Interestingly, this CVE is also listed in the advisory for iOS 16, but it is not called out as being under active exploit for that flavor of the OS. The Big Sur version of macOS also includes a fix for an Out-of-Bounds (OOB) Write bug in the kernel (CVE-2022-32894) that’s also listed as under active attack. One final note: Apple states in its iOS 16 advisory that “Additional CVE entries to be added soon.” It is possible other bugs could also impact this version of the OS. Either way, it’s time to update your Apple devices.
Microsoft Patches for September 2022
This month, Microsoft released 64 new patches addressing CVEs in Microsoft Windows and Windows Components; Azure and Azure Arc; .NET and Visual Studio and .NET Framework; Microsoft Edge (Chromium-based); Office and Office Components; Windows Defender; and Linux Kernel (really). This is in addition to the 15 CVEs patched in Microsoft Edge (Chromium-based) and one patch for side-channel speculation in Arm processors. That brings the total number of CVEs to 79. Five of these CVEs were submitted through the ZDI program.
The volume of fixes released this month is about half of what we saw in August, but it is in line with the volume of patches from previous September releases. For whatever reason, the last quarter of the calendar year tends to have fewer patches released. We’ll see if that trend continues in 2022.
Of the 64 new CVEs released today, five are rated Critical, 57 are rated Important, one is rated Moderate, and one is rated Low in severity. One of these new CVEs is listed as publicly known and under active attack at the time of release. Let’s take a closer look at some of the more interesting updates for this month, starting with the CLFS bug under active attack:
- CVE-2022-37969 - Windows Common Log File System Driver Elevation of Privilege Vulnerability This bug in the Common Log File System (CLFS) allows an authenticated attacker to execute code with elevated privileges. Bugs of this nature are often wrapped into some form of social engineering attack, such as convincing someone to open a file or click a link. Once they do, additional code executes with elevated privileges to take over a system. Usually, we get little information on how widespread an exploit may be used. However, Microsoft credits four different agencies reporting this bug, so it’s likely beyond just targeted attacks.
- CVE-2022-34718 - Windows TCP/IP Remote Code Execution Vulnerability This Critical-rated bug could allow a remote, unauthenticated attacker to execute code with elevated privileges on affected systems without user interaction. That officially puts it into the “wormable” category and earns it a CVSS rating of 9.8. However, only systems with IPv6 enabled and IPSec configured are vulnerable. While good news for some, if you’re using IPv6 (as many are), you’re probably running IPSec as well. Definitely test and deploy this update quickly.
- CVE-2022-34724 - Windows DNS Server Denial of Service Vulnerability This bug is only rated Important since there’s no chance of code execution, but you should probably treat it as Critical due to its potential impact. A remote, unauthenticated attacker could create a denial-of-service (DoS) condition on your DNS server. It’s not clear if the DoS just kills the DNS service or the whole system. Shutting down DNS is always bad, but with so many resources in the cloud, a loss of DNS pointing the way to those resources could be catastrophic for many enterprises.
- CVE-2022-3075 - Chromium: CVE-2022-3075 Insufficient data validation in Mojo This patch was released by the Google Chrome team back on September 2, so this is more of an “in case you missed it.” This vulnerability allows code execution on affected Chromium-based browsers (like Edge) and has been detected in the wild. This is the sixth Chrome exploit detected in the wild this year. The trend shows the near-ubiquitous browser platform has become a popular target for attackers. Make sure to update all of your systems based on Chromium.
Here’s the full list of CVEs released by Microsoft for September 2022:
Chromium: CVE-2022-3058 Use after free in
Sign-In Flow
Low
N/A
No
No
RCE
* Indicates this CVE had previously been assigned by a 3rd-party and is now being incorporated into Microsoft products.
Checking the remaining Critical-rated updates, there are two for Windows Internet Key Exchange (IKE) Protocol Extensions that could also be classified as “wormable.” For both bugs, only systems running IPSec are affected. There are also two Critical-rated vulnerabilities in Dynamics 365 (On-Premises) that could allow an authenticated user to perform SQL injection attacks and execute commands as db_owner within their Dynamics 356 database.
Moving on to other code execution bugs, more than half of this month’s release involves some form of remote code execution. Of these, the patches for SharePoint stand out. Microsoft recently detailed how a SharePoint bug was used by Iranian threat actors against the Albanian government, resulting in Albania breaking off diplomatic relations with Iran. Those attacks involved a SharePoint bug we had previously blogged about. These new SharePoint cases do require authentication, but they sound very similar to other SharePoint bugs that came through the ZDI program. There are six RCE bugs in OLE DB Provider for SQL Server, but they require user interaction. A threat actor would need a user on an affected system to connect to a malicious SQL server via OLEDB, which could result in the target server receiving a malicious packet, resulting in code execution. There are five RCE bugs in the ODBC driver that also require user interaction. For these, opening a malicious MDB in Access would get code execution, similar to the other open-and-own bugs in Office components. The bug in LDAP also requires user interaction, but no other information about the exploit scenario is given.
The bug in the Enterprise App Management component requires authentication, but it’s still intriguing. An attacker could use the vulnerability to install arbitrary SYSTEM services that would then run with SYSTEM privileges. I could definitely see this bug being used after an initial breach for lateral movement and to maintain a presence on a target network. The RPC bug also looks interesting, but it’s likely not as practical since an attacker would need to spoof the localhost IP address of the target. There’s an RCE bug in .NET, but no information besides the requirement for user interaction is given. Finally, there are updates for the AV1 video extension and the Raw image extension. Both updates are delivered automatically through the Microsoft store. If you’re in a disconnected environment, you’ll need to apply these updates manually.
There are a total of 19 elevation of privilege (EoP) fixes in this month’s release, including the aforementioned patch for CLFS. Many of these require an authenticated user to run specially crafted code on an affected system. The bug in Windows Defender for Mac fits this description, as do the kernel-related patches. However, there are a couple of interesting bugs that don’t fit this profile. The first of these is a bug in the Credential Roaming Service that could allow attackers to gain remote interactive logon rights on a machine. There are two bugs in Kerberos that could lead to SYSTEM, but both have many caveats, so exploitation is unlikely. The EoP in Azure Guest Configuration and Arc-Enabled servers is fascinating for multiple reasons. A threat actor could use this vulnerability to replace Microsoft-shipped code with their own code, which would then be run as root in the context of a Guest Configuration daemon. On an Azure Arc-enabled server, it could run in the context of the GC Arc Service or Extension Service daemons. While this is interesting on its own, the mere fact that Microsoft is producing patches for the Linux kernel boggles the mind. And, of course, it wouldn’t be a monthly update if it didn’t include a patch for the print spooler.
The September release includes six patches for information disclosure vulnerabilities. For the most part, these only result in leaks consisting of unspecified memory contents. One exception is the bug impacting the Data Protection Application Programming Interface (DPAPI). If you aren’t familiar with it, DPAPI allows you to encrypt data using information from the current user account or computer. The bug patched this month could allow an attacker to view the DPAPI master key. The vulnerability in the Windows graphics component could leak metafile memory values, although it’s not clear what an attacker could do with this information.
Seven different DoS vulnerabilities are patched this month, including the DNS bug previously mentioned above. Two bugs in secure channel would allow an attacker to crash a TLS by sending specially crafted packets. There’s a DoS in IKE, but unlike the code execution bugs listed above, no IPSec requirements are listed here. If you’re running newer OSes with the latest features, don’t miss the fix for an HTTP DoS. The system needs HTTP/3 enabled and the server using buffered I/O to be affected. HTTP/3 is a new feature in Windows Server 2022, so in this rare instance, older is better.
The September release includes a fix for a lone security feature bypass in Network Device Enrollment (NDES) Service. An attacker could bypass the service’s cryptographic service provider.
The Low-rated bug is a sandbox escape in Microsoft Edge (Chromium-based) that requires user interaction. However, the CVSS for this bug is 7.7, which Mitre classifies as “High.” Microsoft claims the user interaction involved justifies the Low rating, but I would still treat this as an important update and not delay the rollout.
No new advisories were released this month. The latest servicing stack updates can be found in the revised ADV990001.
Looking Ahead
The next Patch Tuesday falls on October 11, and we’ll return with details and patch analysis then. Don’t forget - I’ll be premiering the Patch Report webcast tomorrow on our YouTube channel at 9:00 am Central time. I hope you’re able to tune in and check it out. Until then, stay safe, happy patching, and may all your reboots be smooth and clean!
Disclosure of uninitialized memory is one of the common problems faced when copying data across trust boundaries. This can happen between the hypervisor and guest OS, kernel and user space, or across the network. The most common bug pattern noticed among these cases is where a structure or union is allocated in memory, and some of the fields or padding bytes are not initialized before copying it across trust boundaries. The question is, is it possible to perform variant analysis of such bugs?
The idea here is to perform a control flow insensitive analysis to track all memory store operations statically. Any memory region never written to is identified as uninitialized when the data from it is copied across trust boundaries.
Generalizing the code pattern for analysis
Consider the case of CVE-2018-17155, a FreeBSD kernel memory disclosure in the getcontext() and swapcontext() system calls due to a lack of structure initialization. Shown below is the patch for sys_getcontext(). The listing on the left shows the patched code. sys_swapcontext() was patched in a similar fashion.
Figure 1 - Patch for sys_getcontext() information disclosure. Vulnerable code appears on the right.
The vulnerable code declared a ucontext_t structure on the stack, wrote to some but not all fields, and finally used copyout() to copy UC_COPY_SIZE bytes of data from the structure to userland. The problem here is that not all fields are initialized, so any data occupying the uninitialized parts of the structure memory region are disclosed. To solve the problem, the patched code zeroes out the entire structure using the bzero() function.
The generalization of the above code pattern looks like this:
• A memory region (structure, union, etc.) is declared on the stack or allocated on the heap, which could be the source of uninitialized memory. • The memory region may get fully or partially written. • There is an API that transfers data across trust boundaries. This could be the sink for uninitialized memory. • The API generally takes at least 3 parameters: source buffer, destination buffer, and size. In this case, the source of the memory is a stack offset, and the size of the transfer is a constant value. A constant size of transfer means the value is either the entire size of the memory region (using sizeof operator) or a part of it until an offset. • The memory region may be zeroed out before usage using functions like memset() or bzero().
The sink function is application-specific. To mention a few of the more likely sinks: copy_to_user() in case of Linux kernel, copyout() in case of BSD kernels, send() or sendto() for network transfers or any wrappers around them. The definitions of these functions are either documented, or else understood by reverse engineering if the target is closed source.
Searching the code pattern for analysis
Once the sink function and its definition are known, we can query for calls to the sink function with a constant size argument and source buffer pointing to a stack offset or heap memory. Querying for a pointer to stack memory is straightforward, whereas detecting heap pointers requires visiting the definition site of source variables. Consider the definition of copyout() function in BSD:
When looking for stack memory disclosures, search for cross-references to the copyout() function where kaddr is pointing to a stack offset and the len parameter is a constant.
Binary Ninja has a static data flow feature that propagates known values within a function, including stack frame offsets and type information. Using this feature, it is possible to narrow down calls to copyout() that satisfy our search criteria. To understand this better, let’s inspect the arguments passed to copyout() from sys_getcontext().
The kaddr parameter, or params[0], holds a kernel stack pointer, is shown as the stack frame offset -0x398. The value for the len parameter, or params[1], is shown as the constant 0x330. Since Binary Ninja has no information regarding uaddr, this is shown as <undetermined>. With this register type information for kaddr and len, the following query fetches all instances of calls to copyout() with a kernel stack pointer and constant size:
Statically tracking memory stores
The core idea of the analysis is to track all the memory store operations using Binary Ninja’s static data flow capability and propagate pointers manually using Single Static Assignment (SSA) form whenever necessary. For tracking stack memory stores in local function scope, we rely on Low-Level IL (LLIL), because Medium Level IL (MLIL) abstracts stack access and might eliminate some of the memory stores. For tracking inter-procedure store operations where the address is passed to another function, we rely on the MLIL SSA form to propagate the pointers. The visitor class implemented to handle IL instructions is based on Josh Watson’s Emilator.
Tracking stack memory stores with LLIL
In LLIL, any instruction writing to memory is represented as an LLIL_STORE operation. It has a source and destination parameter. The idea is to linearly visit each LLIL instruction in a function and check if it is an LLIL_STORE operation having a stack frame offset as its destination. When a memory store writing to stack is identified, we will log the source offset of the write and its size. Consider a simple 8-byte memory move operation and its corresponding LLIL information provided by Binary Ninja:
Figure 3 - LLIL_STORE operation in freebsd32_sigtimedwait()
The StackFrameOffset value is the offset from the base of the stack and the size property gives the size of the store operation. Using this information, it is possible to know which memory address are being written. In this case, the addresses from stack base offset -116 to -109 (8 bytes) are being initialized.
Static function hooks and memory writing APIs
While memory store instructions are one way to initialize memory, functions like memset() and bzero() are frequently used to initialize a memory region with NULLs. Similarly, functions such as memcpy(), memmove(), bcopy(), strncpy(), and strlcpy() are also used to write to a memory region. All these functions have something in common: there is a destination memory pointer and a size to write. If the destination and size values are known, it is possible to know the memory region being written to. Consider the case of bzero(), which is used to clear stack memory in the patched sys_getcontext():
Figure 4 - Clearing stack memory using bzero()
By querying the destination pointer and size parameters, it is possible to know their respective values and hence the target memory region.
Now let us consider how the analyzer can handle CALL operations. Static hooks are handlers to functions which we intend to handle differently compared to other functions. For any CALL instruction with a known destination i.e., MLIL_CONST_PTR, the symbol is fetched to check for static hooks.
A JSON configuration with the function names as well their positional parameters (destination buffer and size) is provided to the analyzer for static hooking:
The copyin() function is specific to BSD kernels. It is used to initialize kernel buffers with data from user space. Any target-specific functions to hook can be added to the JSON config and handled in visit_function_hooks() as per necessity.
Handling x86 REP optimization
Many times compilers optimize memory writing functions into REP instructions or a series of store operations. While store operations introduced due to optimization can be handled like any other store operation, REP instructions requires special handling. Static function hooks are not useful in detecting memory writes due to REP. So how do we handle such optimizations and avoid missing those memory writes? First, let’s look at how Binary Ninja translates the REP instruction in LLIL or MLIL.
Figure 5 - memcpy() optimized to REP instruction
Figure 6 - REP instruction translation in MLIL
The REP instruction repeats the string operation until RCX is 0. The direction of copy operation depends on the Direction Flag (DF), hence the branching where one branch increments the source (RSI) and destination (RDI) pointers and the other decrements them. In general, it is reasonably safe to assume that DF will be 0, and that pointers are incremented.
When linearly walking through the ILs, the translated REP instruction will look no different from other instructions. The idea is to check for GOTO instruction, and for every GOTO instruction in IL, fetch the disassembly at the same address. If the disassembly is REP instruction, then fetch the destination pointer as well as size arguments and mark the memory region as initialized.
The LLIL has a get_possible_reg_values() API to read values of registers statically. The MLIL provides couple of APIs, get_var_for_reg() and get_ssa_var_version(), to map architecture registers to SSA variables. This is very useful when propagating values manually using SSA variables in the absence of RegisterValueType information (i.e. RegisterValueType.UndeterminedValue). Similar APIs are currently missing in LLIL and tracked as a feature request: API to get SSARegister for a register at a given LLIL instruction.
Tracking Inter-procedure memory stores with MLIL
At this point we can track memory store operations, CALL operations such as bzero(), memset(), and also deal with REP optimization. The next task is to track memory writes across function calls, as when a caller passes a memory address to a callee. The interesting challenge here is that once a stack pointer has been passed into another function, it can no longer be tracked using the register value type information (StackFrameOffset) as we did within the local function scope using LLIL (see above).
To solve this problem, we propagate the pointers within the callee function using MLIL SSA variables, just like propagating taint information. Whenever a MLIL_STORE_SSA instruction is encountered, we log the offset of the write operation and size values whenever the destination of the memory write operation is resolved manually based on values of SSA variables. The set_function_args() function shown below iterates through MLIL variables and assigns the value (pointer) passed by the caller:
Once the initial SSA variables are set, we visit all the instructions linearly to propagate the pointer and log memory writes. While doing this, the most common operation performed on the pointer is addition. Therefore, it is necessary to emulate MLIL_ADD instruction to handle pointer arithmetic operations. Additionally, it is also important to emulate instructions such as MLIL_SUB, MLIL_LSR and MLIL_AND to handle certain pointer-aligning operations in case of optimizations. Here is an example of how these MLIL SSA expressions are resolved to log a memory store operation:
Considering the SSA variable rax_43#65 as a manually propagated pointer value, it is possible to resolve the destination of the store operation as well as the size of the write. But when the value of the SSA variable rax_43#65 is not available, this memory is not associated with the pointer that was propagated by the caller and therefore not logged.
Handling pointer-aligning optimizations
When performing inter-procedure analysis, further optimizations were noticed in addition to the REP optimization as seen in the “Handling x86 REP optimization” section above. A variable allocated on the stack will usually be aligned to meet the needs of upcoming operations. Let’s say a stack pointer is passed to memset() and the compiler inlines the call as a REP instruction. In this case, it is very likely the memory will be allocated at an aligned address such that the fastest instructions can be used during REP operation.
However, when a pointer is received as an argument by a callee or as a return value of an allocator function, the compiler may have to generate pointer and size alignment opcodes which could rely on branching decisions before reaching REP instruction. Here is an example of such an optimization commonly found in the NetBSD kernel used for analysis:
Figure 7 - An example memset() optimization from NetBSD
When such branching decisions are involved, the pointer, as well as the size, can take multiple possible values (from the perspective of static analysis) at the point of REP instruction. This is different from what we observed in the “Handling x86 REP optimization" section where there is only one possible value for pointer and size. Our goal here is to find the actual value of the pointer and size in the absence of pointer-aligning computations. To achieve this, a couple of SSA expressions were identified that can be used to resolve the original value:
• Search for an expression involving (ADDRESS & BYTESIZE). This could be the first use of ADDRESS before taking any conditional branches. • Search for an expression involving (SIZE >> 3). This is where the adjusted size is passed to a REP instruction.
I had a couple of ideas in mind to track back the above expressions from the point of REP instruction, one relying entirely on SSA and the other based on dominators:
• Use get_ssa_var_definition() and get_ssa_var_uses() APIs to get a variable’s definition site and its uses. • Alternatively, get the dominators of the basic block containing the REP instruction and visit the instructions in the dominator blocks.
The function resolve_optimization() shown below uses dominators to get the basic blocks to perform the search operation. Since the pointer is manually passed by the caller, the value is fetched from the SSA variables.
In the case of a possible constant size value, we fetch the maximum from the list of available size values. Once both pointer and size values are available, we log the memory region as initialized.
Tracking memory stores in dynamic memory allocations
So far, all our analyses were concentrated on stack memory as the source buffer for information disclosure. This is largely due to the prevalence of stack memory disclosure bugs, as described in KLEAK: Practical Kernel Memory Disclosure Detection (PDF). What about other memory regions such as the heap? Can we model some of the heap memory disclosures too?
When looking for heap memory disclosures, the idea remains the same. We are still looking for calls to sink functions with known size value. But instead of the source pointer being RegisterValueType.StackFrameOffset, we check for RegisterValueType.UndeterminedValue. Consider the code for sys_statfs():
Figure 8 - Dynamic memory allocation in sys_statfs()
Here the kernel pointer rdi_1#2 in copyout() is undetermined because Binary Ninja does not know what the allocator function returns. However, by using the SSA form, we can manually track back whether rdi_1#2 is holding the return value of malloc(). For example, follow the highlighted instructions in Figure 8. - the variables are assigned as rax_1#1->r15#1->rdi_1#2. This information can be obtained programmatically using the MLIL get_ssa_var_definition() API. Once the definition site of an SSA variable is obtained, we can check whether the variable is initialized using a CALL operation as demonstrated below:
How does the analyzer know the definition of allocator functions? We can take the same approach used for providing information regarding static function hooks (see the “Static function hooks and memory writing APIs” section above). A JSON configuration with a list of allocator functions and an index of size parameters is provided to the analyzer. For any CALL instruction with a known destination (i.e., MLIL_CONST_PTR), the symbol is fetched to check for known allocator functions. Here is a sample JSON configuration used for analysis:
Once we have established the connection between the source pointer and allocator call, the next question is, what pointer value will be assigned as the return value of the allocator call? The stack pointers as tracked as negative offsets in Binary Ninja as seen below:
To have a generalized representation between the stack and heap pointers, I decided to set the return value of a heap allocator calls as a negative value of the size of the allocation. For the malloc() call in sys_statfs(), rax_1#1 is set to -0x1d8 as the starting address. Therefore, the memory region which needs to be initialized ranges from -0x1d8 to 0 [start + size of allocation]. Even when the allocation size is undetermined, starting address can be set to some arbitrary value such as -0x10000. All that matters here is to know whether the contiguous memory region accessed by copyout() is initialized or not.
Filtering memory stores using dominators and post dominators
A dominator in graph theory provides information on the order of execution of some basic blocks. While we have already used dominators for handling pointer-aligning optimizations in the “Handling pointer aligning optimizations” section, this section details the usage of dominators in detecting control flow-sensitive memory store operations.
To analyze uninitialized memory disclosures, we explore two ideas: dominators and post-dominators. A basic block X is said to dominate another basic block Y if all paths to Y should go through X. A basic block Y is said to post-dominate basic block X if all paths from X to any of the function’s return blocks should go through Y. Consider this example from Wikipedia:
Figure 9 - Graph demonstrating dominators and post dominators
In the provided graph, node B dominates nodes C, D, E, and F because all paths to these nodes must go through node B. By definition, every node dominates itself, so the set of all nodes dominated by node B will be B, C, D, E, and F. Also, node A dominates all the nodes in the graph. Therefore, the dominators of nodes C, D, E, F are A and B.
Similarly, when A is considered as the function entry node, with E and F being exit nodes, node B is the post-dominator of node A. This is because all paths from A to the exit nodes must go through B.
Now, how can dominators and post-dominators help us in this analysis?
We can perform dominator analysis on the callers of the sink function. The idea is to log only memory stores in basic blocks which dominate the basic block calling copyout(), that is, basic blocks which will be executed irrespective of branching decisions. Consider the code below:
Figure 10 - Dominators of basic block calling copyout()
Here the basic block calling copyout() is <mlil block: x86_64@32-35> and there are five dominator blocks in the path from the function entry to copyout(). When performing dominator-based analysis, we will log only memory stores within these five dominator blocks. The memory store operations in other basic blocks might be skipped and not execute. The same is the case with the callee function. We will perform an inter-procedure analysis only when the function is called from a dominator block.
Post-dominator analysis is done on the callee function during an inter-procedure analysis. It is meant to find bugs where a callee can possibly return before initializing the memory region it is supposed to. Consider the callee function do_sys_waitid() from figure 10.
Figure 11 - Post dominators of function entry block in do_sys_waitid()
The function entry block <mlil block: x86_64@0-8> is always executed. The other basic blocks that are executed irrespective of the branching decisions are <mlil block: x86_64@14-22> and <mlil block: x86_64@8-9>. Once again, memory stores and callee analysis are limited only to these three basic blocks.
Dominator- and post-dominator-based analysis tries to fill the gaps in control flow insensitive analysis performed by the analyzer. The general assumption here is that memory is initialized or cleared before performing further operations and therefore dominates other basic blocks. However, this assumption is not always true. For example, there are cases where individual code paths can perform the same operation as done in the dominators. Moreover, when a callee returns due to any error condition, the return value could be validated by the caller before calling copyout(). Consequently, dominator-based analysis as done in this implementation is prone to large numbers of false positives.
Checking for uninitialized memory disclosures
Once all the memory store operations are statically logged with information on offset and size of write, the memory region copied out to user space using copyout() can be evaluated for uninitialized memory disclosure. Consider the call to copyout() shown below:
The source pointer is -0x398 and the size copied is 0x330 bytes. Therefore, the analyzer has to validate if all the bytes in the memory range from -0x398 to (-0x398 + 0x330) are initialized, and if not, flag that as a bug.
False positives and limitations
The analyzer is written with the goal of finding memory regions that never get written to in any possible code paths. False positives occur in cases when it is unable to track a memory store operation. Below are some common false positive conditions and limitations of the implementation:
• The analyzer does not emulate branching instructions. Therefore, false positives are seen in code constructs involving control flow decisions. Consider a memory region such as an array that is initialized in a loop operation. In this case, the store operation would be detected only once because the loop body is visited only once by the analyzer, and not in a loop as it would be during execution.
• Indirect calls are not resolved statically. Consequently, any memory store done during indirect calls is not tracked.
• Optimizations may make it harder to track memory stores. Some common optimizations noticed were tackled in the “Handling x86 REP optimization” and “Handling pointer aligning optimizations” sections.
• Binary Ninja may wrongly detect type information of functions used for static hooking or sink functions like copyout(). Since our analysis relies on RegisterValueType information, any failure to accurately detect the function prototype may lead to false results. Verify the type information before analysis and update if necessary.
• The analyzer looks only for code patterns where the memory source and sink function are within the same function. There is no tracking back of memory source beyond the local function scope.
• Dominator analysis is experimental. You should use it only as a guideline to perform code reviews.
When there is access to source code, some of these false positives can be resolved by changing the optimization flags or by unrolling loops to reduce branching decisions.
Analysis and results
The target kernel executable is loaded in Binary Ninja to generate the BNDB analysis database. Then the analyzer is executed against the database for faster analysis. There are a couple of scripts: one for analyzing stack memory disclosures and another for analyzing sink functions with known size and unknown source pointer. Since the source pointer could be from a heap allocator, provide a JSON configuration with a list of allocator functions as an argument. The dominator analysis is experimental. You need to enable it using an optional argument when needed:
Conclusion
The scripts were tested on Binary Ninja version 2.4.2846 against FreeBSD 11.4, NetBSD 9.2, and OpenBSD 6.9 kernels. Amongst the results, code paths that are possibly reachable for an unprivileged user were evaluated. The OpenBSD bugs were found in sysctls related to multicast routing in IPv4 as well as IPv6, which are tracked as ZDI-22-073 and ZDI-22-012 respectively.
The four vulnerabilities (ZDI-22-075, ZDI-22-1036, ZDI-22-1037, ZDI-22-1067) found in NetBSD are related to syscalls supporting backward compatibility for older NetBSD releases ZDI-22-075 and ZDI-22-1036 are information disclosures in VFS syscalls for NetBSD 3.0 and NetBSD 5.0 respectively. Details regarding the fixes can be found here. Next, ZDI-22-1037 is an information disclosure in getkerneinfo syscall for NetBSD 4.3. This bug was fixed with many other potential issues as seen here. Finally, ZDI-22-1067 is another information disclosure related to VFS syscalls but in NetBSD 2.0 compatibility. Details regarding the fix can be found here.
The FreeBSD bug found in version 11.4 was also related to compatibility, which in this case for supporting 32-bit binaries. However, this bug was fixed without a disclosure during a large change done for the 64-bit inode. The uninitialized structure fields were cleared in the copy_stat function as part of the 64-bit inode project. Though this commit was in May 2017, it was tagged to release 12.0 and above. Therefore, the bug remained unfixed in release 11.4 until it reached EOL in September 2021, soon after our bug report.
Putting it together, most of the bugs were found in BSD’s compatibility layers. Additionally, all these bugs are stack memory disclosures. For anyone interested, the source code for the project can be found here.
You can find me on Twitter @RenoRobertr, and follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
Another Patch Tuesday is here, and Adobe and Microsoft have released their latest crop of new security updates and fixes. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for October 2022
For October, Adobe released four patches addressing 29 vulnerabilities in Adobe Acrobat and Reader, ColdFusion, Commerce and Magento, and Adobe Dimension. A total of 22 of these bugs were reported through the ZDI program. The fix for ColdFusion seems to be the most critical, with multiple CVSS 9.8 code execution bugs being addressed. There’s also a fix for a bug in the Admin Component service. The service uses a hard-coded password for the administrator user. An attacker can leverage this vulnerability to bypass authentication on the system. Hard to imagine hard-coded credentials have existed in the product for so long without being discovered.
The Commerce and Magento update addresses only one bug, but it’s a CVSS 10. If you’re using either of these products, ensure you test and deploy this quickly to fix the stored cross-site scripting (XSS) bug. The patch for Acrobat and Reader fixes six bugs, with the most severe being stack-based buffer overflows that could lead to code execution. A threat actor would need to trick someone into opening a specially crafted PDF to get arbitrary code exec. The fix for Dimension corrects nine bugs, eight of which are rated critical. Most of these are file parsing bugs and would require user interaction to exploit.
None of the bugs fixed by Adobe this month are listed as publicly known or under active attack at the time of release. Adobe categorizes these updates as a deployment priority rating of 3.
Microsoft Patches for October 2022
This month, Microsoft released 85 new patches addressing CVEs in Microsoft Windows and Windows Components; Azure, Azure Arc, and Azure DevOps; Microsoft Edge (Chromium-based); Office and Office Components; Visual Studio Code; Active Directory Domain Services and Active Directory Certificate Services; Nu Get Client; Hyper-V; and the Windows Resilient File System (ReFS). This is in addition to the 11 CVEs patched in Microsoft Edge (Chromium-based) and one patch for side-channel speculation in Arm processors. That brings the total number of CVEs to 96. Six of these CVEs were submitted through the ZDI program.
What may be more interesting is what isn’t included in this month’s release. There are no updates for Exchange Server, despite two Exchange bugs being actively exploited for at least two weeks. These bugs were purchased by the ZDI at the beginning of September and reported to Microsoft at the time. With no updates available to fully address these bugs, the best administrators can do is ensure the September 2021 Cumulative Update (CU) is installed. This adds the Exchange Emergency Mitigation service. This automatically installs available mitigations and sends diagnostic data to Microsoft. Otherwise, follow this post from Microsoft with the latest information. Their mitigation advice has changed multiple times, so you’ll need to make sure you check it often for updates.
Of the 85 new patches released today, 15 are rated Critical, 69 are rated Important, and one is rated Moderate in severity. This volume is somewhat in line with what we’ve seen in previous October releases, but it does put Microsoft on track to exceed its 2021 total. If that happens, 2022 would the second busiest year for Microsoft CVEs. One of the new CVEs released this month is listed as publicly known and one other is listed as being in the wild at the time of release. Let’s take a closer look at some of the more interesting updates for this month, starting with the bug under active attack:
- CVE-2022-41033 – Windows COM+ Event System Service Elevation of Privilege Vulnerability This patch fixes a bug that Microsoft lists as being used in active attacks, although they specify how broad these attacks may be. Since this is a privilege escalation bug, it is likely paired with other code execution exploits designed to take over a system. These types of attacks often involve some form of social engineering, such as enticing a user to open an attachment or browse to a malicious website. Despite near-constant anti-phishing training, especially during “Cyber Security Awareness Month”, people tend to click everything, so test and deploy this fix quickly.
- CVE-2022-37987/CVE-2022-37989 – Windows Client Server Run-time Subsystem (CSRSS) Elevation of Privilege Vulnerability These bugs were reported by ZDI Sr. Vulnerability Researcher Simon Zuckerbraun and pertain to the behavior of the CSRSS process when it searches for dependencies. CVS-2022-37989 is a failed patch for CVE-2022-22047, an earlier bug that saw some in-the-wild exploitation. This vulnerability results from CSRSS being too lenient in accepting input from untrusted processes. By contrast, CVE-2022-37987 is a new attack that works by deceiving CSRSS into loading dependency information from an unsecured location. We’ll publish additional details about these bugs on our blog in the future.
- CVE-2022-37968 – Azure Arc-enabled Kubernetes cluster Connect Elevation of Privilege Vulnerability This vulnerability could allow an attacker to gain administrative control over Azure Arc-enabled Kubernetes clusters. Azure Stack Edge devices may also be impacted by this bug. To exploit this remotely, the attacker would need to know the randomly generated DNS endpoint for an Azure Arc-enabled Kubernetes cluster. Still, this bug receives the rare CVSS 10 rating – the highest severity rating the system allows. If you’re running these types of containers, make sure you either have auto-upgrade enabled or manually update to the latest version by running the appropriate commands in the Azure CLI.
- CVE-2022-38048 – Microsoft Office Remote Code Execution Vulnerability This bug was reported to the ZDI by the researcher known as “hades_kito” and represents a rare Critical-rated Office bug. Most Office vulnerabilities are rated Important since they involve user interaction – typically opening a file. An exception to that is when the Preview Pane is an attack vector, however, Microsoft states that isn’t the case here. Likely the rating results from the lack of warning dialogs when opening a specially crafted file. Either way, this is a UAF that could lead to passing an arbitrary pointer to a free call which makes further memory corruption possible.
Here’s the full list of CVEs released by Microsoft for October 2022:
Chromium: CVE-2022-3317 Insufficient
validation of untrusted input in Intents
Low
N/A
No
No
Spoofing
* Indicates this CVE had previously been assigned by a 3rd-party and is now being incorporated into Microsoft products.
Looking at the rest of the Critical-rated patches, the update for Active Directory Certificate Services (ADCS) stands out the most as successful exploitations would provide the attacker domain administrative privileges. However, exploiting this would be tricky. A malicious DCOM client would need to trick a DCOM server to authenticate to it through ADCS and then use the credential to launch a cross-protocol attack. There are seven Critical-rated fixes for the Point-to-Point Tunneling Protocol (PPTP). If you’re still using this, consider migrating to a more modern (and secure) solution. There’s a fix for a guest-to-host escape in Hyper-V that could result in the attacker executing code on the root OS. In addition to the one mentioned above, there are two other Critical-rated bugs impacting Office components. Neither have a Preview Pane attacker vector, so it’s not clear why the Critical rating applies. Speaking of confusing, there’s a Critical fix for SharePoint that reads identical to the Important-rated SharePoint fixes. Microsoft offers no clarity on why this bug is different.
There are only nine other fixes for remote code execution vulnerabilities, including three for SharePoint that have the same description as the Critical-rated SharePoint bugs already mentioned. There are two patches for the WDAC OLE DB provider for SQL Server and one for the ODBC Driver itself. There’s a fix for an RCE in Visual Studio Code, but no details are provided on what the attack scenario would be. That’s not the case for the GDI+ bug. An attacker would need to convince a user to browse to a malicious website or open a specially crafted file to get code execution. Finally, former Pwn2Own winner Bien Pham from Team Orca of Sea Security reported a code execution bug in the CD-ROM driver through the ZDI program. It’s an integer overflow that could lead to an out-of-bound write on kernel heap memory. In this case, an attacker would need to convince someone to open a malicious .iso file, which does seem a bit unlikely.
A total of 39 bugs in this release are Elevation of Privilege (EoP) bugs, including those mentioned above. The majority of these require an authenticated user to run specially crafted code on an affected system, but there are a few that stand out. The first is the patch for the print spooler. While we’re certainly used to spooler updates by now, this one was reported by the National Security Agency (NSA). The EoP in the Workstation service requires privileges, but it can be reached remotely. An attacker could execute RPC functions that are normally restricted to the local client. You would also need to be authenticated to send malicious RPC calls to the DHCP service to escalate to SYSTEM. The bug in Active Directory Domain Services could allow an attacker to get domain administrator privileges, but Microsoft offers no details on how that would occur. The NuGet package manager for .NET receives a fix impacting multiple NuGet versions. The fix for Visual Studio Code contains an …uh… interesting workaround:
“Create a folder C:\ProgramData\jupyter\kernels\ and configure it to be writable only by the current user.”
It’s not clear why this prevents the attack, but Microsoft claims it will. Lastly, the EoP in the Local Security Authority (LSA) could lead to a sandbox escape.
The October release includes fixes for 11 information disclosure bugs, including one in Office that’s listed as publicly known. Most of the other info disclosure vulnerabilities only result in leaks consisting of unspecified memory contents. There are a couple of notable exceptions. The bug in the Web Account Manager could allow an attacker to view unbound refresh tokens issued by one cloud on a different cloud. The patches for Visual Studio Code and the Mixed Reality Developer Tools fix disclosure bugs that could allow reading from the file system. The final info disclosure bug fixed this month could allow reading from the HKLM hive of the registry which you normally would not have access to.
There are two patches for Security Features Bypass (SFB) vulnerabilities this month, and the first requires physical access. On systems with outdated USB controller hardware, a Group Policy might have silently failed, which would leave the Windows Portable Device Enumerator Service open to attacks that rely on inserting a USB storage device. The SFB bug in Active Directory Certificate Services requires a Man-in-the-Middle (MiTM) and applies to Windows Challenge/Response (NTLM) authentication.
Eight different DoS vulnerabilities are patched this month. Probably the most interesting is the DoS in TCP/IP, which could be exploited by remote, unauthenticated attackers and does not require user interaction. Microsoft states systems with IPv6 disabled aren’t affected, but IPv6 comes enabled by default on most systems these days. Microsoft provides no further details about the seven other DoS patches.
The October release is rounded out by five spoofing bugs, including the lone Moderate-rated fix, which addresses a spoofing vulnerability in Microsoft Edge (Chromium-based). The most interesting is the Critical-rated fix for the Windows CryptoAPI. This bug could allow an attacker to spoof an existing public x.509 certificate to authenticate or sign code as the targeted certificate. I’m sure malware authors will definitely try to use this one in the near future. There’s also a store cross-site scripting (XSS) bug in the Service Fabric Explorer. If you’re using this, you need to ensure you are on the latest version by following these instructions. No additional details are provided about the spoofing bugs in Office or NTLM.
No new advisories were released this month. The latest servicing stack updates can be found in the revised ADV990001.
Looking Ahead
The next Patch Tuesday falls on November 8, and we’ll return with details and patch analysis then. Be sure to catch the Patch Report webcast on our YouTube channel. It should be posted in just a few hours. Until then, stay safe, happy patching, and may all your reboots be smooth and clean!
In this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, Guy Lederfein and Dusan Stevanovic of the Trend Micro Research Team detail a recently patched code injection vulnerability in the Sophos Firewall. The bug is due to improper validation of JSON keys submitted in the “JSON” parameter sent to the Controller endpoint. Successful exploitation of this vulnerability could result in remote code execution with the privileges of the root user. The following is a portion of their write-up covering CVE-2022-3236, with a few minimal modifications.
Sophos recently patched a code injection vulnerability in Sophos Firewall v19.0 MR1 (19.0.1) and previous. This vulnerability is due to improper validation of JSON keys submitted in the “json” parameter sent to the Controller endpoint. A remote, unauthenticated attacker could exploit this vulnerability by sending a specially crafted request to an affected server. Successfully exploiting this vulnerability could result in remote code execution with the privileges of the root user.
The Vulnerability
Sophos Firewall is a network security solution, which can be deployed on purpose-built devices, on a cloud network (AWS/Azure), on a virtual device, or as a software appliance on x86 Intel hardware. The firewall application supports multiple network security features, including application-aware routing, TLS inspection, deep packet inspection, remote access VPN, logging, and reporting. Sophos Firewall exposes a web admin console for managing the device’s configuration via HTTPS on TCP port 4444. In addition, Sophos Firewall exposes a user portal for updating a user’s details or downloading authentication clients via HTTPS on TCP port 443.
HTTP is a request/response protocol described in RFCs 7230 - 7237 and other RFCs. A request is sent by a client to a server, which in turn sends a response back to the client. An HTTP request consists of a request line, various headers, an empty line, and an optional message body:
where CRLF represents the new line sequence Carriage Return (CR) followed by Line Feed (LF) and SP represents a space character. Parameters can be passed from the client to the server as name-value pairs in either the Request-URI or in the message-body, depending on the Method used and the Content-Type header. For example, a simple HTTP request passing a parameter named “param” with value “1”, using the GET method might look like this:
A corresponding HTTP request using the POST method might look like this:
JavaScript Object Notation (JSON) is a data-interchange format used for creating machine parseable, human-readable output. A JSON object has the following syntax:
• An object is enclosed in curly braces {}. • An object is comprised of zero or more items delimited by a comma (“,”) character. • An item is comprised of a key and a value. A key is delimited from its value by a colon (“:”) character. • A key must be a string enclosed in quotes. • A value must be a valid type. JSON defines seven value types: string, number, object, array, true, false, and null. • An array is an object enclosed in square braces []. • An array is comprised of zero or more strings, numbers, JSON objects, arrays, boolean, or null type-objects delimited by a comma (“,”) character.
An example JSON object is as follows:
{“name”:”bob”, “age”:30}
The web admin and user portal web interfaces exposed by Sophos Firewall both run on a Jetty server behind an Apache httpd server. Configuration and diagnostic requests issued through these interfaces are submitted via requests to the Controller servlet. This servlet retrieves the appropriate EventBean object based on the mode HTTP request parameter. For example, if the mode HTTP request parameter is set to 151 or 451, the WebAdminAuth or UserPortalAuth classes are called to process the request, respectively. In each of these classes, the generateAndSendAjaxEvent() method of the CSCClient class is called. This method parses the json HTTP request parameter and modifies specific fields from the parsed object. The send() method is then called, which in turn calls _send(), which adds the mode JSON parameter according to the mode of the associated EventBean object. It then sends the created JSON object as a string, including appropriate headers, to the local CSC server over TCP or UDP port 299.
When the CSC server receives the JSON object submitted by the Jetty server, it validates the JSON object submitted via the validateJSON() method in the Perl script CyberAPIArch.pm. If the JSON object contains a key named _discriminator, the getValidationHash() method is called. This method iterates over each key of the _discriminator Perl hash, representing field names. Each field name is associated with a JSON object describing the mapping between field values and object names. Some Perl objects resolved when parsing the JSON object received (natrule, securitypolicy, hotspot, etc.) contain a template with a _discriminator key containing such a mapping for specific field names between field values and their associated objects. The method iterates over the field values to check whether the submitted JSON object contains a field with the referenced name and value. If so, it retrieves the associated object name and attempts to resolve it to an object using the eval function.
A code injection vulnerability has been reported for Sophos Firewall. This vulnerability is due to improper validation of JSON keys submitted in the “json” parameter sent to the Controller endpoint. Specifically, the _discriminator key can be set in the HTTP request. This JSON object is sent, after some modification, to the CSC server. However, the _discriminator key set is sent unmodified. Once the validateJSON() method of the Perl script CyberAPIArch.pm is called, it will detect this key and call getValidationHash(). The Perl method iterates over the $hashObj hash object, which contains a key named _discriminator whose value is a nested hash with a value key set with the value set for the _discriminator key in the original request sent. This value key is treated as a nested hash containing field values mapped to object names. Therefore, if the originally submitted JSON object contains a key named value with its value set to one of the values in this nested hash, the associated object name will be resolved using the eval function. Since the _discriminator key in the original request can be set to a JSON object with an arbitrary mapping between values and object names, a malicious object can be submitted to be concatenated into the eval function, resulting in code injection.
Sophos attempts to perform input validation on request parameters, including the JSON object, using the RequestCheckFilter Java object. This filter detects request parameters and JSON keys with non-ASCII printable characters. However, arbitrary request parameters and JSON keys containing ASCII printable characters can still be submitted, including the _discriminator key.
A remote, unauthenticated attacker could exploit this vulnerability by sending a crafted request to the target server. Successfully exploiting this vulnerability could result in arbitrary Perl commands being run on the server, resulting in remote code execution with the privileges of the root user.
Source Code Walkthrough
The following code snippet was taken from Sophos Firewall version 19.0.1 with additional comments added by Trend Micro.
From the decompiled Java class cyberoam.sessionmanagement.RequestCheckFilter:
From the Perl script CyberAPIArch.pm:
Detecting Attacks
To detect an attack attempting to exploit this vulnerability, the detection device must monitor and parse traffic on ports 443/TCP and 4444/TCP. Note that the traffic is encrypted with SSL/TLS. The detection device must decrypt the traffic before proceeding through the next steps.
Based on the TCP ports monitored, the detection device must inspect HTTP GET and POST requests to a Request- URI containing the following string:
Requests to the Webadmin Controller endpoint (TCP port 4444) can use the multipart/form-data encoding.
Multipart/form-data is made up of multiple parts, each of which contains a Content-Disposition header. Each part is separated by a string of characters. The string of characters separating the parts is defined by the boundary keyword found on the Content-Type header line, which is set to “multipart/form-data”. The Content-Disposition header contains a name parameter describing the form element being returned. Additional header lines may be present in each part. Each line is separated by a new line sequence. The header is terminated by two consecutive new lines. The form element's data follows. The filename parameter provides a suggested filename to be used if the entity is detached and stored in a separate file. The following is a sample Content-Disposition header for a file item, where the boundary keyword is “TMSR”:
If a request to one of the above endpoints is found, the detection device must parse its parameters according to the encoding described in the Content-Type header and search for the json parameter. If found, the detection device must inspect the json parameter value using any suitable methods below.
Method 1: If the detection device is capable of parsing JSON, it must parse the json parameter as a JSON object. The detection device must parse any items (potentially nested) whose key is the string “_discriminator”. If found, the traffic should be considered malicious as an attack exploiting this vulnerability is likely underway.
Method 2: If the detection device is not capable of parsing JSON, it must inspect the json parameter as a string and check if it contains the string “_discriminator”. If found, the traffic should be considered malicious as an attack exploiting this vulnerability is likely underway.
Additional things to note:
• Parameter names and values may be URL-encoded and must be decoded before applying the above detection guidance. • String matching for the URI and parameter names (“json”) and values (“_discriminator”) must be performed in a case-sensitive manner. • String matching for HTTP header names (i.e., “Content-Type”) and values (i.e., “multipart/form-data”) must be performed in a case-insensitive manner.
Conclusion
There are reports that this vulnerability is being used to target a small group of organizations and that Sophos has “informed each of these [affected] organizations directly.” This bug is also similar to a previous vulnerability, CVE-2022-1040, that that Volexity and The Record claim was used by a Chinese APT crew in March 2022. Regardless, this bug has a CVSS base score of 9.8 and should be remediated immediately. Sohpos users who don’t have hotfixes enabled or are on legacy versions should patch immediately as outlined in Sophos’s advisory. You should also consider blocking the affected ports from external network access if it is not required.
Special thanks to Guy Lederfein and Dusan Stevanovic of the Trend Micro Research Team for providing such a thorough analysis of this vulnerability. For an overview of Trend Micro Research services please visit http://go.trendmicro.com/tis/.
The threat research team will be back with other great vulnerability analysis reports in the future. Until then, follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
CVE-2022-3236: Sophos Firewall User Portal and Web Admin Code Injection
I stumbled upon the Apache Batik library while researching other Java-based products. It immediately caught my attention, as this library parses Scalable Vector Graphics (SVG) files and transforms them into different raster graphics formats (i.e., PNG, PDF, or JPEG). I was even more encouraged when I looked at the Batik documentation. It was obvious that such a library could be prone to Server-Side Request Forgery (SSRF) issues (e.g., loading of images from remote resources). However, the documentation shows that Batik can also:
· Execute JavaScript through the Rhino interpreter. · Load and execute remote Java classes.
Those are some neat features! On the other hand, Apache Batik protects its users from both SSRF and remote code execution (RCE) vulnerabilities through the various security modes it offers. In this blog post, I am going to show you:
· How I bypassed the default security modes: DefaultScriptSecurity (CVE-2022-40146) and DefaultExternalResourceSecurity (CVE-2022-38398). · How to abuse the SSRF in the default Batik Transcoder to make arbitrary HTTP GET requests or to trigger an NTLM challenge. · What configurations are vulnerable to the RCE through remote class loading. · What configurations are vulnerable to the RCE through the Rhino interpreter and JavaScript execution.
Before we get into the details, here’s a quick video demonstrating a remote code execution vulnerability exploited through remote JAR loading.
Sample Web Application Endpoint
Apache Batik can be used in different ways. There is a pretty good chance that you have already seen it in web applications during the conversion of SVG to PDF/PNG/JPEG. Let’s define a sample endpoint that performs such a conversion:
```
This endpoint performs the following actions:
· Retrieves and decodes the base64-encoded SVG file. · Creates the Apache Batik JPEG Transcoder. · Converts the SVG to JPEG.
This is a common usage of Apache Batik. Note that there is a risk of an easy SSRF if the SVG loads an image from an external resource. Batik tries to protect against such a scenario with its external resource controls, although some of these have existing bypasses with their own CVEs assigned. Let’s quickly review those resource controls.
Apache Batik External Resource Controls
Apache Batik resource controls can be divided into two main categories:
Let’s take a brief look at the scripting controls. They control whether script provided within an SVG will be executed. The external resource controls are similar to the scripting controls but apply to the fetching of resources such as images. For a full description of security controls, you can access the documentation here. Here’s a quick overview of the available ScriptSecurity implementations:
· NoLoadScriptSecurity – scripts are completely blocked. · EmbededScriptSecurity [sic] – scripts embedded in the document can be executed when properly referenced. · DefaultScriptSecurity – Embedded external scripts (as above) plus scripts coming from the same origin as the document referencing them are allowed. · RelaxedScriptSecurity – scripts from any location can be loaded.
In my research so far, I have focused only on the default security controls.
Note that the default security control has a concept of “origin”, but what exactly does this mean? It means that the resource or script will be loaded only if it originates from the same “host” as the SVG file. For example:
· If we load a local SVG file, we can also load local scripts or resources. · If we load a local SVG file, we cannot load scripts or resources from remote origins (e.g., through HTTP or SMB). · If we load an SVG file through the HTTP protocol, we can load remote scripts from the same host through either HTTP or any other supported protocol, such as SMB.
In order to avoid any confusion, let’s quickly describe what “loading an SVG through the HTTP protocol” means in Batik. It specifically means that the HTTP URL is directly provided to the Batik TranscoderInput.
This does not look like a particularly common scenario, because the attacker would need to control the URL from which the SVG file is (directly) loaded into Batik.
Accordingly, the default security controls seem to be appropriate. When a local SVG file is loaded, or an SVG is provided as an InputStream, the default controls should block the loading of any remote resources.
Now let’s see how we can bypass those security checks.
DefaultScriptSecurity and DefaultExternalResourceSecurity vs URL.getHost
To start, let’s dig into the DefaultScriptSecurity constructor, which is responsible for our security check. Please note that the code of DefaultExternalResourceSecurity is almost identical, thus it will not be presented.
At [1], the scriptURL and docURL of ParsedURL type are provided. For the sake of simplicity, let’s say that ParsedURL wraps the Java URL class.
At [2] and [3], the respective host strings are retrieved with the getHost method. Under the hood, it retrieves the output of the Java URL.getHost.
At [4], hosts obtained in points [2] and [3] are compared. If they are the same, the code flow continues, and the exception will not be thrown.
At [5], a SecurityException is thrown if the security check is not successful.
If the document host and the script host are the same, the exception will not be thrown, and the script or resource will be loaded. Next, let’s look at how the Java URL.getHost behaves for different protocols:
It’s pretty simple. The host for a local file will be equal to null, whereas for the remote files shown here (referenced by either UNC path or HTTP) it will be equal to evil.com. If the Apache Batik TranscoderInput is created with the InputStream, the getHost method will also return null.
It seems that the default security routines work properly, and we will not be able to load remote resources during processing of SVGs coming from local files or input streams.
Unfortunately, a trivial bypass exists, and honestly, Java itself is the likely culprit. Let’s see the output of the getHost getter for the JAR protocol:
What? It seems that the host for the JAR protocol is also null. In order to properly retrieve the host from the JAR URL, the following cumbersome code can be used. We retrieve the file member from the URL and then use it to create a new URL, from which we can get the host.
In this way, the security check can be easily bypassed with the JAR protocol. Let’s have a look at a sample SVG that leads to SSRF through the image tag.
This SVG will bypass the DefaultExternalResourceSecurity control and will make an HTTP GET request to the attacker’s server. Please note that we can also use the syntax “jar:file://…”, in order to get an NTLMv2 challenge-response in a Windows environment and potentially perform an NTLM relaying attack.
Now that we have shown how to bypass the default external resources controls to get an easy SSRF through the image tag, let’s see how to get remote code execution. This has been fixed in Batik 1.15.
Apache Batik Remote Class Loading Feature
While digging through the Apache Batik documentation, I found an intriguing feature: “Referencing Java Code From a Document”.
Batik implements the Java bindings for SVG, and thus allows Java code to be referenced from script elements… In order to use this extension, the type attribute of a script element must be set to application/java-archive. In addition, the xlink:href attribute must be the URI of a jar file that contains the code to run.
It seems that we can provide a script of type application/java-archive referencing a properly structured JAR file. We already know that we can bypass the DefaultScriptSecurity check and load files from remote locations, thus it looks like a win!
Luckily, the script execution is not enabled by default in the Apache Batik transcoder and some configuration modifications must be applied:
1) Enable script execution
Script execution can be enabled in the transcoder with the following line of code:
Please note that the Apache Batik is a “do it yourself” library and often requires a lot of customization. There is a chance that you will see such a configuration in the wild. Also, Batik defines some methods that allow dynamic verification of whether the SVG file contains scripts or not. This method can be used to automatically enable script execution if needed.
2) Fix the logical flaw to allow execution of scripts of type “application/java-archive”.
It seems that Apache Batik’s definition of default-allowed script types contains an unintended error. Let’s have a quick look:
You can clearly see that the script types are separated with a comma followed by a space. Now, let’s look at the method that retrieves the list of allowed types:
The list is created with StringTokenizer, where the delimiter is set to a comma without a space! According to that, all the allowed types other than the first one (ECMASCRIPT) will contain a leading space. For example, the allowed type will be “ application/java-archive” instead of “application/java-archive”.
The code will compare the script type declared in the SVG against the type specified in the list. You may think that this is not a problem, since we can declare a script type in the SVG that also includes a space:
<script type=” application/java-archive”>
This will not work, though. The type check for remote JAR loading is performed twice. The second check verifies if the script type is equal to “application/java-archive”, without a leading space. As a result, we will not be able to pass both checks. To enable remote class loading, we must manually modify the list of allowed script types by making an API call as follows:
Now, let’s look at how to perform remote JAR loading in Batik. To begin, we must create a class that implements the EventListenerInitializer interface. Then, we must define the initializeEventListeners method. This method will be executed after the JAR is loaded. Here’s an example of a malicious class:
The MANIFEST.MF file included in the JAR needs to specify SVG-Handler-Class. The following snippet presents an exemplary manifest:
Finally, we specify a malicious SVG that loads such a JAR and bypasses the security policies:
The following screenshot presents a proof of concept where the JAR was loaded through the HTTP protocol and the code was executed, spawning a curl process and making a request to our HTTP server.
Figure 1 - Code Execution through remote JAR loading
Success! We were able to bypass the restrictions defined in DefaultScriptSecurity, load the JAR file from the remote location, and achieve remote code execution.
Scripts Enabled with Remote JAR Loading Disallowed
Due to the logical flaw described in the previous section, it’s likely that you will encounter the following configuration:
· Scripts enabled. · The setting for allowed script types is untouched, so that, in practice, only ECMAScript is enabled.
Luckily, you can still get an easy RCE. ECMAScript is interpreted with Mozilla Rhino, an open-source implementation of JavaScript written in Java. This code execution vector has been already presented by the researcher known as pyn3rd.
The following snippet presents an SVG file with an ugly looking script that will execute the attacker’s command.
The following screenshot demonstrates the achieved code execution:
Figure 2 - Code Execution through ECMAScript
Execution of ECMAScript is a well-documented feature of Apache Batik and this behavior will not be fixed. The official security guide recommends securing your application with the Java SecurityManager when scripting is enabled. I’m taking a guess, but I think that we will never see a completely secure implementation of SecurityManager within Batik. It would likely break too much functionality and make the application unusable. This is still merely speculation on my part. It should also be noted that running scripts is disabled by default and must be explicitly enabled.
UPDATE: Apache Batik 1.16 has been recently released. It introduces a hardening to Rhino script execution mechanisms. However, it’s hard to call this hardening a strong one. You are still able to call almost any class whose full name starts with “org.”. Saying that, you can still easily abuse many methods included in Apache libraries. This security check can be found here.
Summary
To wrap things up, the security checks implemented in the default external resource controllers of Apache Batik could be bypassed prior to Batik 1.15, in order to:
· Perform SSRF through the JAR protocol, producing either an HTTP GET request or NTLM relaying via an UNC path. · Potentially achieve RCE through remote JAR loading, provided that a non-default configuration was applied.
The bugs discussed here in DefaultScriptSecurity and DefaultExternalResourceSecurity were fixed in version 1.15. Still, Apache Batik may allow the execution of arbitrary Java code when script execution is enabled, even in the latest version 1.16.
If you are using Batik or are interested in finding additional bugs, here are some things to consider:
· Developers – do not allow scripts to execute through Batik. Apply the strictest controls possible. · Pentesters/Bug Hunters – when you test functionality that accepts SVG, try to use the SVG files presented in this blog post. · Vulnerability researchers – when your target uses Apache Batik for SVG parsing or conversions, analyze its configuration carefully. You might have an easy win over there.
Thanks for reading, and I hope you’ve enjoyed this post. You can follow me @chudypb and follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
Vulnerabilities in Apache Batik Default Security Controls – SSRF and RCE Through Remote Class Loading
Welcome to the penultimate Patch Tuesday of 2021. As expected, Adobe and Microsoft have released their latest security updates and fixes to the world. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for November 2022
For November, Adobe released no patches at all. They’ve released as few as one in the past, but this is the first month in the last six years where they had no fixes at all. Perhaps the U.S. elections play a factor, as Patch Tuesday hasn’t fallen on Election Day since 2016. Whatever the cause, enjoy a month of no Adobe updates.
Microsoft Patches for November 2022
This month, Microsoft released 64 new patches addressing CVEs in Microsoft Windows and Windows Components; Azure and Azure Real Time Operating System; Microsoft Dynamics; Exchange Server; Office and Office Components; SysInternals; Visual Studio; SharePoint Server; Network Policy Server (NPS); Windows BitLocker; and Linux Kernel and Open Source Software. This is in addition to five other CVEs from third parties being integrated into Microsoft products bringing the total number of fixes to 69. Eight of these CVEs were submitted through the ZDI program.
Of the 64 new patches released today, 11 are rated Critical and 53 are rated Important in severity. This volume is similar to previous November releases. It also pushes Microsoft over the number of fixes they released in 2021 and makes this year their second busiest ever for patches.
One of the new CVEs released this month is listed as publicly known and six others are listed as being in the wild at the time of release, which includes the two Exchange bugs listed as under active attack since September. Let’s take a closer look at some of the more interesting updates for this month, starting with those Exchange fixes we’ve been waiting for:
- CVE-2022-41082– Microsoft Exchange Server Remote Code Execution Vulnerability - CVE-2022-41040 – Microsoft Exchange Server Elevation of Privilege Vulnerability These patches address the recent Exchange bugs that are currently being used in active attacks. They were expected last month, but they are finally here (along with several other Exchange fixes). These bugs were purchased by the ZDI at the beginning of September and reported to Microsoft at the time. At some point later, they were detected in the wild. Microsoft has released several different mitigation recommendations, but the best advice is to test and deploy these fixes. There were some who doubted these patches would release this month, so it’s good to see them here.
- CVE-2022-41128 – Windows Scripting Languages Remote Code Execution Vulnerability This bug in JScript is also listed as being exploited in the wild. An attack would need to lure a user to either a specially crafted website or server share. In doing so, they would get their code to execute on an affected system at the level of the logged-on user. Microsoft provides no insight into how widespread this may be but considering it’s a browse-and-own type of scenario, I expect this will be a popular bug to include in exploit kits.
- CVE-2022-41091 – Windows Mark of the Web Security Feature Bypass Vulnerability If you follow Will Dormann on Twitter, you probably have already read quite a bit about these types of bugs. Mark of the Web (MoW) is meant to be applied to files downloaded from the Internet. These files should be treated differently and receive security warning dialogs when accessing them. This vulnerability is also listed as being under active attack, but again, Microsoft provides no information on how widespread these attacks may be.
- CVE-2022-41073 – Windows Print Spooler Elevation of Privilege Vulnerability The legacy of PrintNightmare continues as threat actors continue to mine the vast attack surface that is the Windows Print Spooler. While we’ve seen plenty of other patches since PrintNightmare, this one is listed as being in the wild. While not specifically called out, disabling the print spooler should be an effective workaround. Of course, that breaks printing, but if you’re in a situation where patching isn’t feasible, it is an option.
- CVE-2022-41125 – Windows CNG Key Isolation Service Elevation of Privilege Vulnerability The final bug listed under active attack for November is this privilege escalation in the “Cryptography Application Programming Interface - Next Generation” (CNG) Key Isolation Service. An attacker can abuse this bug to run their code at SYSTEM. They would need to be authenticated, which is why bugs like these are often paired with some form of remote code execution exploit. As with all the other in-the-wild exploits, there’s no indication of how widely this is being used, but it’s likely somewhat targeted at this point. Still, test and deploy the updates quickly.
Here’s the full list of CVEs released by Microsoft for November 2022:
Windows Win32k Elevation of Privilege
Vulnerability
Important
7.8
No
No
EoP
* Indicates this CVE had previously been assigned by a 3rd-party and is now being incorporated into Microsoft products.
There are four additional bugs in Exchange Server receiving fixes this month, and three of those were reported by ZDI Vulnerability Researcher Piotr Bazydło. Most notably, the privilege escalation bug is due to Exchange having a hardcoded path to a file on the “D:” drive. If a “D:” exists and an attacker puts a DLL in the specified folder, Exchange will load the DLL. By default, low-privileged users have write access to the “D:” drive (assuming it exists). Another vector would be if the low-privileged attacker can insert an optical disk or attach an external drive that will be assigned the letter “D:”. Hard to believe a hard-coded path still exists within Exchange, but here we are. The two spoofing bugs would allow an authenticated attacker to obtain the NTLMv2 challenge and eventually perform further NTLM Relaying attacks. I have a strong premonition many Exchange administrators have a long weekend in front of them.
Looking at the remaining Critical-rated fixes, the two privilege escalation bugs in Kerberos stand out. You’ll need to take additional actions beyond just applying the patch. Specifically, you’ll need to review KB5020805 and KB5021131 to see the changes made and next steps. Microsoft notes this is a phased rollout of fixes, so look for additional updates to further impact the Kerberos functionality. There’s another patch for Scripting Languages. In this case, it’s JScript and Chakra, and this one is not listed as under active attack. There are three Critical-rated fixes for Point-to-Point Tunneling Protocol (PPTP). This seems to be a continuing trend of researchers looking for (and finding) bugs in older protocols. If you rely on PPTP, you should really consider upgrading to something more modern. There’s a Critical-rated denial-of-service (DoS) bug in Hyper-V, which is pretty unusual to see. DoS bugs rarely get the Critical tag, but Microsoft states, “Successful exploitation of this vulnerability could allow a Hyper-V guest to affect the functionality of the Hyper-V host.” I guess that’s severe enough to earn a Critical rating despite the 6.5 CVSS score. The fix for the Azure CLI was actually released a couple of weeks ago, and it’s getting documented now.
In addition to the fixes we’ve already discussed, there are 11 other patches for remote code execution vulnerabilities, including a memory corruption bug in the Windows Graphics Component reported by ZDI Vulnerability Researcher Hossein Lotfi. There are also multiple RCE bugs in various Office components, including one from ZDI Vulnerability Researchers Mat Powell and Michael DePlante. For these cases, user interaction would be required – the Preview Pane isn’t an exploit vector. There’s an authenticated SharePoint RCE, but a default user has the needed permissions to take over a SharePoint server. The vulnerability in Azure RTOS would require a user to run specially crafted code, so a level of social engineering would likely be needed to exploit this bug. The final two RCE bugs are in the ODBC driver, and these would require some social engineering to exploit as well. An attacker would need to convince someone to connect to their SQL server via ODBC. If they can do that to an affected system, they could execute code remotely on the client.
A total of 26 bugs in this release are Elevation of Privilege (EoP) bugs, including those already mentioned. The majority of these require an authenticated user to run specially crafted code on an affected system, but there are a few that stand out. The first is the fix for Netlogon that reads similar to the aforementioned Kerberos fixes. Microsoft is rolling out updates in phases and admins should review KB5021130 for additional steps. The bug in Azure CloudCycle has a brute force component, which definitely makes exploitation more difficult. Still. If you are using CloudCycle to manage your HPC environments on Azure, ensure you get it updated. The fixes for ALPC note the bugs could be used to escape a contained execution environment. While certainly not the first bugs to do so, I don’t recall Microsoft documenting this before now. Finally, there’s an EoP in SysInternals services. These tools are often used by incident responders, so definitely make sure you have an updated version before heading out to recover a compromised system.
The November release includes eight new fixes for information disclosure bugs. Most of the info disclosure vulnerabilities only result in leaks consisting of unspecified memory contents. There is one notable exception. The vulnerability in Business Central requires admin credentials but could lead to the disclosure of integration secrets that are owned by a different partner. Presumably, you would be able to impersonate the other client with this info.
Four total Security Feature Bypass bugs are getting fixed this month, including the patch for the MoW bug being actively exploited. There’s another fix for a MoW bug, but this one is not listed as under active attack. The fix for Excel addresses a bug that would bypass the content check in the INDIRECT function. More notably, the bug in BitLocker could allow an attacker with physical access to bypass the Device Encryption feature and access the encrypted data. Preventing this is pretty much the “one job” of Device Encryption, so regardless of exploitability, this is a significant bypass.
Today’s release also includes fixes for five additional DoS bugs. Four of these impact network protocols: PPTP, RADIUS, and Network Address Translation (NAT). A successful attack on one of these protocols would cause the service to stop responding. The same is true of the bug in Kerberos, which could impact logging on and other functionality that relies on the Kerberos service.
There is one spoofing bug in SharePoint server, but beyond the authentication requirement, there’s no information regarding the exploit scenario.
Finally, you may have heard of some OpenSSL bugs that had everyone abuzz before their release. To say they fizzled out is a bit of an understatement. Still, the fixes for Microsoft products are included in this release.
There is one new advisory this month adding defense-in-depth functionality to Microsoft Office. The new feature provides hardening around IRM-protected documents to ensure the trust-of-certificate chain. The latest servicing stack updates can be found in the revised ADV990001.
Looking Ahead
The final Patch Tuesday of 2022 will be on December 13, and we’ll return with details and patch analysis then. Be sure to catch the Patch Report webcast on our YouTube channel. It should be posted in just a few hours. Until then, stay safe, happy patching, and may all your reboots be smooth and clean!
By now you have likely already heard about the in-the-wild exploitation of Exchange Server, chaining CVE-2022-41040 and CVE-2022-41082. It was originally submitted to the ZDI program by the researcher known as “DA-0x43-Dx4-DA-Hx2-Tx2-TP-S-Q from GTSC”. After successful validation, it was immediately submitted to Microsoft. They patched bothbugs along with several other Exchange vulnerabilities in the November Patch Tuesday release.
It is a beautiful chain, with an ingenious vector for gaining remote code execution. The tricky part is that it can be exploited in multiple ways, making both mitigation and detection harder. This blog post is divided into two main parts:
· Part 1 – where we review details of the good old ProxyShell Path Confusion vulnerability (CVE-2021-34473), and we show that it can still be abused by a low-privileged user. · Part 2 – where we present the novel RCE vector in the Exchange PowerShell backend.
Here’s a quick demonstration of the bugs in action:
Part 1: The ProxyShell Path Confusion for Every User (CVE-2022-41040)
There is a great chance that you are already familiar with the original ProxyShell Path Confusion vulnerability (CVE-2021-34473), which allowed Orange Tsai to access the Exchange PowerShell backend during Pwn2Own Vancouver 2021. If you are not, I encourage you to read the details in this blog post.
Microsoft patched this vulnerability in July of 2021. However, it turned out that the patch did not address the root cause of the vulnerability. Post-patch, unauthenticated attackers are no longer able to exploit it due to the implemented access restrictions, but the root cause remains.
First, let’s see what happens if we try to exploit it without authentication.
HTTP Request
HTTP Response
As expected, a 401 Unauthorized error was returned. However, can you spot something interesting in the response? The server says that we can try to authenticate with either Basic or NTLM authentication. Let’s give it a shot.
HTTP Request
HTTP Response
Exchange says that it is cool now! This shows us that:
· The ProxyShell Path Confusion still exists, as we can reach the PowerShell backend through the autodiscover endpoints. · As the autodiscover endpoints allow the use of legacy authentication (NTLM and Basic authentication) by default, we can access those endpoints by providing valid credentials. After successful authentication, our request will be redirected to the selected backend service.
Legacy authentication in Exchange is described by Microsoft here. The following screenshot presents a fragment of the table included in the previously mentioned webpage.
Figure 1 - Legacy authentication in Exchange services, source: https://learn.microsoft.com/
According to the documentation and some manual testing, it seems that an Exchange instance was protected against this vulnerability if:
· A custom protection mechanism was deployed that blocks the Autodiscover SSRF vector (for example, on the basis of the URL), or · If legacy authentication was blocked for the Autodiscover service. This can be done with a single command (though an Exchange Server restart is probably required):
So far, we have discovered that an authenticated user can access the Exchange PowerShell backend. We will now proceed to the second part of this blog post to discuss how this can be exploited for remote code execution.
Part 2: PowerShell Remoting Objects Conversions – Be Careful or Be Pwned (CVE-2022-41082)
In this part, we will focus on the remote code execution vulnerability in the Exchange PowerShell backend. It is a particularly interesting vulnerability, and is based on two aspects:
· PowerShell Remoting conversions and instantiations. · Exchange custom converters.
It has been a very long ride for me to understand this vulnerability fully and I find that I am still learning more about PowerShell Remoting. The PowerShell Remoting Protocol has a very extensive specifications and there are some hidden treasures in there. You may want to look at the official documentation, although I will try to guide you through the most important aspects. The discussion here should be enough to understand the vulnerability.
PowerShell Remoting Conversions Basics and Exchange Converters
There are several ways in which serialized objects can be passed to a PowerShell Remoting instance. We can divide those objects into two main categories:
· Primitive type objects · Complex objects
Primitive types are not always what you would think of as “primitive”. We have some basic types here such as strings and byte arrays, but “primitive types” also include types such as URI, XMLDocument and ScriptBlock (the last of which is blocked by default in Exchange). Primitive type objects can usually be specified with a single XML tag, for example:
Complex objects have a completely different representation. Let’s take a quick look at the example from the documentation:
First, we can see that the object is specified with the “Obj” tag. Then, we use the “TN” and “T” tags to specify the object type. Here, we have the System.Drawing.Point type, which inherits from System.ValueType.
An object can be constructed in multiple ways. Shown here is probably the simplest case: direct specification of properties. The “Props” tag defines the properties of the object. You can verify this by comparing the presented serialized object and the class documentation.
One may ask: How does PowerShell Remoting deserialize objects? Sadly, there is no single, easy answer here. PowerShell Remoting implements multiple object deserialization (or conversion) mechanisms, including quite complex logic and as well as some validation. I will focus on two main aspects, which are crucial for our vulnerability.
a) Verifying if the specified type can be deserialized b) Converting (deserializing) the object
Which Types Can Be Deserialized?
PowerShell Remoting will not deserialize all .NET types. By default, it allows those types related to the remoting protocol itself. However, the list of allowed types can be extended. Exchange does that through two files:
An example entry included in those files will be presented soon.
In general, the type specified in the payload that can be deserialized is referenced as the “Target Type For Deserialization”. Let’s move to the second part.
How Is Conversion Performed?
In general, conversion is done in the following way.
· Retrieve properties/member sets, deserializing complex values if necessary. · Verify that this type is allowed to be deserialized. · If yes, perform the conversion.
Now the most important part. PowerShell Remoting implements multiple conversion routines. In order to decide which converter should be used, the System.Management.Automation.LanguagePrimitives.FigureConversion(Type, Type) method is used. It accepts two input arguments:
· Type fromType – the type from which the object will be obtained (for example, string or byte array). · Type toType – the target type for deserialization.
The FigureConversion method contains logic to find a proper converter. If it is not able to find any converter, it will throw an exception.
As already mentioned, multiple converters are available. However, the most interesting for us are:
· ConvertViaParseMethod – invokes Parse(String) method on the target type. In this case, we control the string argument. · ConvertViaConstructor – invokes the single-argument constructor that accepts an argument of type fromType. In this case, we can control the argument, but limitations apply. · ConvertViaCast – invokes the proper cast operator, which could be an implicit or explicit cast. · ConvertViaNoArgumentConstructor – invokes the no-argument constructor and sets the public properties using reflection. · CustomConverter – there are also some custom converters specified.
As we can see, these conversions are very powerful and provide a strong reflection primitive. In fact, some of them were already mentioned in the well-known Friday the 13th JSON Attacks Black Hat paper. As we have mentioned, though, the toType is validated and we are not able to use these converters to instantiate objects of arbitrary type. That would certainly be a major security hole.
Let’s have a look at one particular item specified in the Exchange.types.ps1xml file:
There are several basic things that we can learn from this XML fragment:
· Microsoft.Exchange.Data.IPvxAddress class is included in the list of the allowed target types. · The TargetTypeForDeserialization member gives the full class name. · A custom type converter is defined: Microsoft.Exchange.Data.SerializationTypeConverter
The SerializationTypeConverter wraps the BinaryFormatter serializer with ExchangeBinaryFormatterFactory. That way, the BinaryFormatter instance created will make use of the allow and block lists.
To sum up, some of our types (or members) can be retrieved through BinaryFormatter deserialization. Those types must be included in the SerializationTypeConverter allowlist, though. Moreover, custom converters are last-resort converters. Before they are used, PowerShell Remoting will try to retrieve the object through a constructor or a Parse method.
RCE Payload Walkthrough
It is high time to show you the RCE payload and see what happens during the conversion.
This XML fragment presents the specification of the “-Identity” argument of the “Get-Mailbox” Exchange Powershell cmdlet. We have divided the payload into three sections: Object type, Properties, and Payload.
· Object type section – specifies that there will be an object of type System.ServiceProcess.ServiceController. · Properties section – specifies the properties of the object. One thing that should catch your attention here is the property with the name TargetTypeForDeserialization. You should also notice the byte array with the name SerializationData. (Note that Powershell Remoting accepts an array of bytes in the form of a base64 encoded string). · Payload section – contains XML in the form of a string. The XML is a XAML deserialization gadget based on ObjectDataProvider.
Getting Control over TargetTypeForDeserialization
In the first step, we are going to focus on the Properties section of the RCE payload. Before we do that, let’s quickly look at some fragments of the deserialization code. The majority of the deserialization routines are implemented in the System.Management.Automation.InternalDeserializer class.
Let’s begin with this fragment of the ReadOneObject(out string) method:
At [1], it invokes the ReadOneDeserializedObject method, which may return an object.
At [2], the code flow continues, provided an object has been returned. We will focus on this part later.
Let’s quickly look at the ReadOneDeserializedObject method. It goes through the XML tags and executes appropriate actions, depending on the tag. However, only one line is particularly interesting for us.
At [1], it calls ReadPSObject. This happens when the tag name is equal to “Obj”.
Finally, we analyze a fragment of the ReadPSObject function.
At [1], the code retrieves the type names (strings) from the <TN> tag.
At [2], the code retrieves the properties from the <Props> tag.
At [3], the code retrieves the member set from the <MS> tag.
At [4], the code tries to read the primary type (such as string or byte array).
At [5], the code initializes a new deserialization procedure, provided that the tag is an <Obj> tag.
So far, we have seen how InternalDeserializer parses the Powershell Remoting XML. As shown earlier, the Properties section of the payload contains a <Props> tag. It seems that we must look at the ReadProperties method.
At [1], the adaptedMembers property of the PSObject object is set to some PowerShell-related collection.
At [2], the property name is obtained (from the N attribute).
At [3], the code again invokes ReadOneObject in order to deserialize the nested object.
At [4], it instantiates a PSProperty object, based on the deserialized value and the property name.
Finally, at [5], it extends adaptedMembers by adding the new PSProperty. This is a crucial step, pay close attention to this.
Let’s again look at the Payload section of our RCE payload:
We have two properties defined here:
· The Name property, which is of type string and whose value is the string “Type”.
· The TargetTypeForDeserialization property, whose value is a complex object specified as follows:
o The type (TN tag) is System.Exception. o There is a value stored as a base64 encoded string, representing a byte array.
We have already seen that nested objects (defined with the Obj tag) are also deserialized with the ReadOneObject method. We have already looked at its first part (object retrieval). Now, let’s see what happens further:
At [1], the code retrieves the Type targetTypeForDeserialization through the GetTargetTypeForDeserialization method.
At [2], the code tries to retrieve a new object through the LanguagePrimitives.ConvertTo method (if GetTargetTypeForDeserialization returned anything). The targetTypeForDeserialization is one of the inputs. Another input is the object obtained with the already analyzed ReadOneDeserializedObject method.
As we have specified the object of the System.Exception type (TN tag), the GetTargetTypeForDeserialization method will return the System.Exception type. Why does the exploit use Exception? For two reasons:
· It is included in the allowlist exchange.partial.types.ps1xml. · It has a custom converter registered: Microsoft.Exchange.Data.SerializationTypeConverter.
These two conditions are important because they allow the object to be retrieved using the SerializationTypeConverter, which was discussed above as a wrapper for BinaryFormatter. Note that there are also various other types available besides System.Exception that meet the two conditions mentioned here, and those types could be used as an alternative to System.Exception.
Have you ever tried to serialize an object of type Type? If yes, you probably know that it is serialized as an instance of System.UnitySerializationHolder. If you base64-decode the string provided in the Properties part of our payload, you will quickly realize that it is a System.UnitySerializationHolder with the following properties:
To sum up, our byte array holds the object, which constructs a XamlReader type upon deserialization! That is why we want to use the SerializationTypeConverter – it allows us to retrieve an object of type Type. An immediate difficulty is apparent here, though, because Exchange’s BinaryFormatter is limited to types on the allowlist. Hence, it’s not clear why the deserialization of this byte array should succeed. Amazingly, though, System.UnitySerializationHolder is included in the SerializationTypeConverter’s list of allowed types!
Let’s see how it looks in the debugger:
Figure 2 - Deserialization leading to the retrieval of the XamlReader Type
Even though the targetTypeForDeserialization is Exception, LanguagePrimitives.ConvertTo returned the Type object for XamlReader (see variable obj2). This happens because the final type of the retrieved object is not verified. Finally, this Type object will be added to the adaptedMembers collection (see the ReadProperties method).
Getting Code Execution Through XamlReader, or Any Other Class
We have already deserialized the TargetTypeForDeserialization property, which is a Type object for the XamlReader type. Perfect! As you might expect, allowing users to obtain an arbitrary Type object through deserialization is not the best idea. But we still need to understand: why does PowerShell Remoting respect such a user-defined property? To begin answering this, let’s consider what the code should do next:
· It should deserialize the <S> tag defined after the <Props> tag (payload section of the input XML). This is a primitive string type, thus it retrieves the string. · It should take the type of the main object, which is defined in the <TN> tag (here: System.ServiceProcess.ServiceController). · It should try to create the System.ServiceProcess.ServiceController instance from the provided string.
Our goal is to switch types here. We want to perform a conversion so that the System.Windows.Markup.XamlReader type is retrieved from the string. Let’s analyze the GetTargetTypeForDeserialization function to see how this can be achieved.
At [1], it tries to retrieve an object of the PSMemberInfo type using the GetPSStandardMember method. It passes two parameters: backupTypeTable (this contains the Powershell Remoting allowed types/converters) and the hardcoded string “TargetTypeForDeserialization”.
At [2], the code retrieves the Value member from the obtained object and tries to cast it to Type. When successful, the Type object will be returned. If not, null will be returned.
GetPSStandardMember method is not easy to understand, especially when you are not familiar with the classes and methods used here. However, I will try to summarize it for you in two points:
At [1], the PSMemberSet object is retrieved through the TypeTableGetMemberDelegate method. It takes our specified type (here, System.ServiceProcess.ServiceController) and compares it against the list of allowed types. If the provided type is allowed, it will extract its properties and create the new member set.
The following screenshot presents the PSMemberSet retrieved for the System.ServiceProcess.ServiceController type:
Figure 3 - PSMemberSet retrieved for the System.ServiceProcess.ServiceController type
At [2], the collection of members is created from multiple sources. If a member is not included in the basic member set (obtained from the list of allowed types), it will try to find such a member in a different source. This collection includes the adapted members, which contain the deserialized properties obtained through the Props tag.
Finally, it will try to retrieve the TargetTypeForDeserialization member from the final collection.
Let’s have a quick look at the specification of the System.ServiceProcess.ServiceController in the list of allowed types. It is defined in the default Powershell Remoting types list, located in C:\Windows\System32\WindowsPowerShell\v1.0\types.ps1xml.
As you can see, this type does not have the TargetTypeForDeserialization member specified. Only the DefaultDisplayPropertySet member is defined. According to that, the targetTypeForDeserialization will be retrieved from adaptedMembers. As the Exchange SerializationTypeConverter converter allows us to retrieve a Type through deserialization, we can provide a new conversion type to adaptedMembers!
Following screenshot presents the obtained psmemberinfo, which defines the XamlReader type:
Figure 4 - Retrieved XamlReader type
Success! GetTargetTypeForDeserialization returned the XamlReader type. You probably remember that PowerShell Remoting contains several converters. One of them allows calling the Parse(String) method. According to that, we can call the XamlReader.Parse(String) method, where the input will be equal to the string provided in the <S> tag. Let’s quickly verify it with the debugger.
The following screenshot presents the debugging of the LanguagePrimitive.ConvertTo method. The resultType is indeed equal to the XamlReader:
Figure 5 - Debugging of the ConvertTo method - resultType
The next screenshot presents the valueToConvert argument. It includes the string (XAML gadget) included in our payload:
Figure 6 - Debugging of the ConvertTo method - valueToConvert
We will soon reach the LanguagePrimitives.FigureParseConversion method. The following screenshot illustrates debugging this method. One can see that:
· fromType is equal to String. · toType is equal to XamlReader. · methodInfo contains the XamlReader.Parse(String string) method.
Figure 7 – Debugging the LanguagePrimitives.FigureParseConversion method
Yes! We have been able to get the XamlReader.Parse(String string) method through reflection! We also fully control the input that will be passed to this function. Finally, it will be invoked through the System.Management.Automation.LanguagePrimitives.ConvertViaParseMethod.ConvertWithoutCulture method, as presented in the following screenshot:
Figure 8 - Execution of the XamlReader.Parse method
As you may be aware, XamlReader allows us to achieve code execution through loading XAML (see ysoserial.net). When we continue the process, our command gets executed.
Figure 9 - Remote Code Execution through the Exchange PowerShell backend
There are also plenty of other classes besides XamlReader that could be abused in a similar way. For example, you can call the single-argument constructor of any type, so you can be creative here!
TL;DR – Summary
Getting to understand this vulnerability has been a long and complicated process. I hope that I have provided enough details for you to understand this issue. I would like to summarize the whole Microsoft Exchange chain in several points:
· The path confusion in the Autodiscover service (CVE-2021-34473) was not fixed, but rather it was restricted to unauthenticated users. Authenticated users can still easily abuse it using Basic or NTLM authentication.
· PowerShell Remoting allows us to perform object deserialization/conversion operations.
· PowerShell Remoting includes several powerful converters, which can:
o Call the public single-argument constructor of the provided type. o Call the public Parse(String) method of the provided type. o Retrieve an object through reflection. o Call custom converters. o Other conversions may be possible as well.
· PowerShell Remoting implements a list of allowed types, so an attacker cannot (directly) invoke converters to instantiate arbitrary types.
· However, the Exchange custom converter named SerializationTypeConverter allows us to obtain an arbitrary object of type Type.
· This can be leveraged to fully control the type that will be retrieved through a conversion.
· The attacker can abuse this behavior to call the Parse(String) method or the public single-argument constructor of almost any class while controlling the input argument.
· This behavior easily leads to remote code execution. This blog post illustrates exploitation using the System.Windows.Markup.XamlReader.Parse(String) method.
It was not clear to us how Microsoft was going to approach fixing this vulnerability. Direct removal of the System.UnitySerializationHolder from the SerializationTypeConverter allowlist might cause breakage to Exchange functionality. One potential option was to restrict the returned types, for example, by restricting them to the types in the “Microsoft.Exchange.*” namespace. Accordingly, I started looking for Exchange-internal exploitation gadgets. I found more than 20 of them and reported them to Microsoft to help them with their mitigation efforts. That effort appears to have paid off. Microsoft patched the vulnerability by restricting the types that can be returned through the deserialization of System.UnitySerializationHolder according to a general allowlist, and then restricting them further according to a specific denylist. It seems that the gadgets I reported had an influence on that allowlist. I will probably detail some of those gadgets in a future blog post. Stay tuned for more…
Summary
I must admit that I was impressed with this vulnerability. The researcher clearly invested a good amount of time to fully understand the details of PowerShell Remoting, analyze Exchange custom converters, and find a way to abuse them. I had to take my analysis to another level to fully understand this bug chain and look for potential variants and alternate gadgets.
Microsoft patched these bugs in the November release. They also published a blog with additional workarounds you can employ while you test and deploy the patches. You should also make sure you have the September 2021 Cumulative Update (CU) installed. This adds the Exchange Emergency Mitigation service. This automatically installs available mitigations and sends diagnostic data to Microsoft. Still, the best method to prevent exploitation is to apply the most current security updates as they are released. We expect more Exchange patches in the coming months.
In a future blog post, I will describe some internal Exchange gadgets that can be abused to gain remote code execution, arbitrary file reads, or denial-of-service conditions. These have been reported to Microsoft, but we are still waiting for these bug reports to be addressed with patches. Until then, you can follow me @chudypb and follow the team on Twitter or Instagram for the latest in exploit techniques and security patches.
Control Your Types or Get Pwned: Remote Code Execution in Exchange PowerShell Backend
In this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, Justin Hung and Dusan Stevanovic of the Trend Micro Research Team detail a recently patched SQL injection vulnerability in Zoho ManageEngine products. The bug is due to improper validation of resource types in the AutoLogonHelperUtil class. Successful exploitation of this vulnerability could lead to arbitrary SQL code execution in the security context of the database service, which runs with SYSTEM privileges. The following is a portion of their write-up covering CVE-2022-3236, with a few minimal modifications.
ManageEngine recently patched a SQL injection vulnerability bug in their Password Manager Pro, PAM360, and Access Manager Plus products. The vulnerability is due to improper validation of resource types in the AutoLogonHelperUtil class. A remote attacker can exploit the vulnerability by sending a crafted request to the target server. Successful exploitation could lead to arbitrary SQL code execution in the security context of the database service, which runs with SYSTEM privileges.
The Vulnerability
Password Manager Pro is a secure vault for storing and managing shared sensitive information such as passwords, documents, and digital identities of enterprises. The product is also included in other two similar ManageEngine products: PAM360 and Access Manager Plus. A user can access the web console on these products through HTTPS requests via the following ports:
The HTTP request body may contain data of various types. The data type is indicated in the Content-Type header field. One of the standardized types is multipart, which contains various subtypes that share a common syntax. The most widely used subtype of multipart type is multipart/form-data. Multipart/form-data is made up of multiple parts, each of which contains a Content-Disposition header. Each part is separated by a string of characters. The string of characters separating the parts is defined by the boundary keyword found in the Content-Type header line. The Content-Disposition header contains parameters in “name=value” format. Additional header lines may be present in each part; each header line is separated by a CRLF sequence. The last header line is terminated by two consecutive CRLFs sequences and the form element’s data follows. The filename parameter in a ContentDisposition header provides a suggested file name to be used if the element's data is detached and stored in a separate file.
A user with admin privileges can add/edit a resource type via Password Manager Pro web interface by clicking the menu “Resources” -> “Resource Types” -> “Add” (or “Edit”) and a HTTP multipart/form-data request will be submitted to the “AddResourceType.ve” endpoint, as an example shown below:
where several form-data parts are transferred in the request, like “TYPEID”, “dnsname_label”, “resLabChkName__1”, etc. The data carried in the multipart/form-data part with a name parameter value of “resourceType” represents the name of the resource type, which is relevant to the vulnerability in this report.
An SQL injection vulnerability exists in Password Manager Pro. The vulnerability is due to a lack of sanitization of the name of the resource type in the Java class AutoLogonHelperUtil. The AutoLogonHelperUtil class is used by several controller classes, like AutologonController and PasswordViewController, to construct a partial SQL statement related to the query for existing resource types. For example, if a user clicks the menu “Connections” on the web admin interface, a request will be sent to “AutoLogonPasswords.ec” endpoint, and the includeView() method of ViewProcessorServlet class is called. The includeView() method will use AutologonController class to handle the request. The AutologonController class is derived from the SqlViewController class and its updateViewModel() method is called to process the request. The updateViewModel() method will first call the initializeSQL() method to get an SQL statement. It then calls the getAsTableModel() method of the SQLQueryAPI class to execute the SQL statement.
In the initializeSQL() method, it will call the getSQLString() method of the AutologonController class to get the SQL statement, which will invoke the getFilledString() method of the TemplateAPI class. In the getFilledString() method, it will call the getVariableValue() method of the AutologonController. The getVariableValue() method will use the getOSTypeCriteriaForView() method of the AutoLogonHelperUtil class to construct a partial SQL statement. The getOSTypeCriteriaForView() will call the getOSTypeCriteria() method, which uses getOSTypeList() to read all resource types from the database. It then uses these resource types to build a partial SQL statement as below:
PTRX_OSTYPE in ( <resource type 1>, <resource type 2>, ..., <resource type n> )
where <resource type n> represents a resource type name queried from a database by the getOSTypeList() method. Then, this partial SQL statement will be returned to getOSTypeCriteriaForView() and then be returned to the getFilledString(). The getFilledString() will use this partial SQL statement to generate the final complete SQL statement and return it back to getSQLString().
However, the getOSTypeCriteria() method of the AutoLogonHelperUtil class does not sanitize the name of the resource type (returned from getOSTypeList()) for SQL injection characters before using it to create a partial SQL statement. An attacker can therefore first add a new resource type (or edit an existing resource type) with a crafted resource type name containing a malicious SQL command, and then click a menu such as “Connections” to invoke the methods of the AutoLogonHelperUtil class which will use the malicious resource type name to construct a SQL statement. This could trigger the execution of the injected SQL command.
A remote authenticated attacker can exploit the vulnerability by sending a crafted request to the target server. Successful exploitation could lead to arbitrary SQL code execution in the security context of the database service, which runs with SYSTEM privileges.
Detection Guidance
To detect an attack exploiting this vulnerability, the detection device must monitor and parse traffic on the ports listed above. Note that the traffic is encrypted via HTTPS and should be decrypted before performing the following steps.
The detection device must inspect HTTP POST requests to a Request-URI containing the following string:
/AddResourceType.ve
If found, the detection device must inspect each part of the multipart/form-data parts in the body of the request. In each part, the detection device must search for the Content-Disposition header and its name parameter to see if its value is “resourceType”. If found, the detection device must continue to inspect the data carried in this multipart/ form-data part to see if it contains the single-quote character “' (\x27)”. If found, the traffic should be considered malicious and an attack exploiting this vulnerability is likely underway. An example of malicious requests is shown below:
Additional notes:
• The string matching for the Request-URI and “POST” should be performed in a case-sensitive manner, while other string matching like “name”, “resourceType” and “Content-Disposition” should be performed in a case-insensitive manner. • The Request-URI may be URL encoded and should be decoded before applying the detection guidance. • It is possible that the single quote “' (\x27)” is naturally found in the resource type name resulting in false positives. However, in normal cases, the possibility should be low.
Conclusion
ManageEngine patched this and other SQL injections in September. Interestingly, the patch for PAM360 came a day after the patches for Password Manager Pro and Access Manager Plus. The vendor offers no other workarounds. Applying these updates is the only way to fully protect yourself from these bugs.
Special thanks to Justin Hung and Dusan Stevanovic of the Trend Micro Research Team for providing such a thorough analysis of this vulnerability. For an overview of Trend Micro Research services please visit http://go.trendmicro.com/tis/.
The threat research team will be back with other great vulnerability analysis reports in the future. Until then, follow the team on Twitter, Mastodon, LinkedIn, or Instagram for the latest in exploit techniques and security patches.
CVE-2022-40300: SQL Injection in ManageEngine Privileged Access Management
Note: The contest rules were updated on January 6th to clarify the scope of the OPC UA categories. Please review the rules for full details.
¡Bienvenidos de nuevo a Miami!
Even as we make our final preparations for our consumer-focused contest in Toronto, we’re already looking ahead to warmer climes and returning to the S4 Conference in Miami for our ICS/SCADA-themed event. Pwn2Own returns to South Beach on February 14-16, 2023, and for this year’s event, we’ve refined our target list to include the latest trends in the ICS world. As we did last year, we’ll have contestants both in person and around the world demonstrating the latest exploits on OPC Unified Architecture (OPC UA) Servers, OPC UA Clients, Data Gateways, and Edge systems.
Our inaugural Pwn2Own Miami was held back in January 2020 at the S4 Conference, and we had a fantastic time as we awarded over $280,000 USD in cash and prizes for 24 unique 0-day vulnerabilities. Last year, we awarded $400,000 for 26 unique 0-days (plus a few bug collisions). At that event, we crowned Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) Master of Pwn for their multiple successful exploits. We’ll see if they return in 2023 to defend their crown.
This contest is not possible without the participation and help of our partners within the ICS community, and we would like to especially thank the folks at the OPC Foundation and AVEVA for their expertise and guidance. The cooperation of those within the ICS/SCADA community is essential in ensuring we have the right categories and targets. Pwn2Own Miami seeks to harden these platforms by revealing vulnerabilities and providing that research to the vendors. The goal is always to get these bugs fixed before they’re actively exploited by attackers. ICS vendors have been instrumental in making that goal a reality.
The 2023 edition of Pwn2Own Miami has four categories:
· OPC Unified Architecture (OPC UA) Server · OPC Unified Architecture (OPC UA) Client · Data Gateway · Edge systems
You’ll notice these are different categories from previous years. These differences reflect the changing state of the ICS industry and better reflect current threats to SCADA systems. Let’s look at the details of each category.
OPC UA Server Category
The OPC Unified Architecture (UA) is a platform-independent, service-oriented architecture that integrates all the functionality of the individual OPC Classic specifications into one extensible framework. OPC UA serves as the universal translator protocol in the ICS world. It is used by almost all ICS products to send data between disparate vendor systems. While we’ve had OPC UA targets in the past, for this event, we’ve set up distinct Server and Client categories. We’re also excited to have TXOne Networks sponsor a portion of the prize packages for these categories.
An attempt in this category must be launched against the target’s exposed network services from the contestant’s laptop within the contest network. An entry in the category must result in either a denial-of-service condition, arbitrary code execution, credential theft, or a bypass of the trusted application check.
The Credential Theft target should prove interesting. For this scenario, the contestant must create a session with a trusted certificate but use credentials acquired by either decrypting a password from an ongoing session or by abusing a vulnerability that allows for the retrieval of the stored password from the server. The server will be configured with an ‘admin’ account with a random password that is 12-16 characters long. A successful entry must log in using a legitimate client after the password is retrieved by some means. Brute force attacks won’t be allowed.
For the “bypass trusted application check” scenario, the contestant must bypass the trusted application check that occurs after the creation of a secure channel. Entries that bypass the check by manipulating the server security configuration are out of scope. There are additional requirements for this target, so definitely read the rules carefully if you want to enter.
Here is the full list of targets for the OPC UA Server category:
OPC UA Client Category
Similar to the Server category, we’ll have specific OPA UA Clients available to target. Again, the “bypass trusted application check” scenario must meet specific criteria, so you should check out the rules for a full description.
Here is the full list of targets for the OPC US Client category:
Data Gateway Category
This category focuses on devices that connect other devices of varying protocols. There are two products in this category. The first is the Triangle Microworks SCADA Data Gateway product. Triangle Microworks makes the most widely used DNP3 protocol stack. The other is the Softing Secure Integration Server. According to their website, “Secure Integration Server covers the full range of OPC UA security features and enables the implementation of state-of-the-art security solutions.” We’ll see if that holds true throughout the contest.
A successful entry in this category must result in arbitrary code execution.
Edge Category
This category is new for 2023 and reflects how edge devices are often used in ICS/SCADA networks to manage and maintain systems. For this year’s event, we’ll have the AVEVA Edge Data Store as our sole target in this category. Edge Data Store collects, stores, and provides data from remote and uncrewed assets. This is an exciting addition to the contest, and we look forward to seeing what exploits researchers demonstrate against this target.
A successful entry in this category must result in arbitrary code execution.
Master of Pwn
No Pwn2Own contest would be complete without crowning a Master of Pwn, and Pwn2Own Miami is no exception. Earning the title comes with a slick trophy and 65,000 ZDI reward points (instant Platinum status in 2024, which includes a one-time bonus estimated at $25,000).
For those not familiar with how it works, Master of Pwn points are accumulated for each successful attempt. While only the first demonstration in a category wins the full cash award, each successful entry claims the full number of Master of Pwn points. Since the order of attempts is determined by a random draw, those who receive later slots can still claim the Master of Pwn title – even if they earn a lower cash payout.
To add to the excitement, there are penalties for withdrawing from an attempt once you register for it. If a contestant decides to withdraw from the registered attempt before the actual attempt, the Master of Pwn points for that attempt will be divided by 2 and deducted from the contestant's point total for the contest. Since Pwn2Own is now often a team competition, along with the initial deduction of points, the same number of Master of Pwn points will also be deducted from all contestant teams from the same company.
The Complete Details
The full set of rules for Pwn2Own Miami 2023 can be found here. They may be changed at any time without notice. Anyone thinking about participating should read the rules thoroughly and completely.
Registration is required to ensure we have sufficient resources on hand at the event. Please contact ZDI at [email protected] to begin the registration process. (Email only, please; queries via Twitter, blog post, or other means will not be acknowledged or answered.) If we receive more than one registration for any category, we’ll hold a random drawing to determine the order of attempts. Contest registration closes at 5:00 p.m. Eastern Standard Time on February 9, 2023.
The Results
We’ll be live blogging results throughout the competition. Be sure to keep an eye on the blog for the latest results. We’ll also be posting results and videos to Twitter, YouTube, Mastodon, LinkedIn, and Instagram, so follow us on your favorite flavor of social media for the latest news from the event.
We look forward to seeing everyone again in Miami, and we look forward to seeing what new exploits and attack techniques they bring with them.
Special thanks to TXOne Networks for sponsoring the OPC UA Client and OPC UA Server categories.
Welcome to Pwn2Own Toronto 2022! his year marks the 10th anniversary of our consumer-focused version of the contest, and we plan on celebrating by putting some amazing research on display. For this year’s event, we have 26 contestants and teams attempting to exploit 66 targets across multiple categories. As always, we began our contest with a random drawing to determine the order of attempts. If you missed it, you can watch the replay here. Due to the number of entries, we will be running multiple attempts simultaneously and extending the contest to four days.
The complete schedule for the contest is below (all times Eastern [GMT -5:00]).
Note: All times subject to change
Tuesday, December 6 - 0930
Nettitude targeting the Canon imageCLASS MF743Cdw in the Printer category
Qrious Secure targeting the WAN interface of TP-Link AX1800 in the Router category
Tuesday, December 6 - 1100
Horizon3 AI targeting the Lexmark MC3224i in the Printer category
Gaurav Baruah targeting the WAN interface of the Synology RT6600ax in the Router category
Tuesday, December 6 - 1300
Interrupt Labs targeting the HP Color LaserJet Pro M479fdw in the Printer category
STAR Labs targeting the Samsung Galaxy S22 in the Mobile Phone category
Quarkslab targeting the LAN interface of the NETGEAR RAX30 AX2400 in the Router category
Computest targeting the LAN interface of the Synology RT6600ax in the Router category
Tuesday, December 6 - 1500
PHPHooligans targeting the NETGEAR router and the Lexmark printer SOHO SMASHUP category
Chim targeting the Samsung Galaxy S22 in the Mobile Phone category
Interrupt Labs targeting the LAN interface of the NETGEAR RAX30 AX2400 in the Router category
Tenable targeting the LAN interface of the TP-Link AX1800 in the Router category
Tuesday, December 6 - 1700
DEVCORE targeting the Mikrotik router and the Canon printer in the SOHO SMASHUP category
Claroty Research targeting the Synology DiskStation DS920+ in the NAS category
NCC Group EDG targeting the LAN interface of the TP-Link AX1800 in the Router category
Tuesday, December 6 - 1900
Team Viettel targeting the HP Color LaserJet Pro M479fdw in the Printer category
ASU SEFCOM targeting the Synology DiskStation DS920+ in the NAS category
Claroty Research targeting the LAN interface of the NETGEAR RAX30 AX2400 in the Router category
NCC Group EDG targeting the LAN interface of the Synology RT6600ax in the Router category
Tuesday, December 6 - 2030
Neodyme targeting the NETGEAR router and the HP printer in the SOHO SMASHUP category
Qrious Secure targeting the LAN interface of the NETGEAR RAX30 AX2400 in the Router category
Wednesday, December 7 - 0930
ANHTUD targeting the HP Color LaserJet Pro M479fdw in the Printer category
PHPHooligans targeting the WAN interface of the NETGEAR RAX30 AX2400 in the Router category
Wednesday, December 7, 1100
Bugscale targeting the Synology router and HP Printer in the SOHO SMASHUP category
Qrious Secure targeting the Sonos One Speaker in the Smart Speaker category
Team Viettel targeting the LAN interface of the TP-Link AX1800 in the Router category
Wednesday, December 7, 1300
Le Tran Hai Tung targeting the Canon imageCLASS MF743Cdw in the Printer category
NCC Group EDG targeting the WAN interface of the NETGEAR RAX30 AX2400 in the Router category
STAR Labs targeting the Sonos One Speaker in the Smart Speaker category
Synacktiv targeting the Lexmark MC3224i in the Printer category
Summoning Team targeting the LAN interface of the Synology RT6600ax in the Router category
Wednesday, December 7, 1500
Team Viettel targeting the Canon imageCLASS MF743Cdw in the Printers category
NCC Group EDG targeting the Lexmark MC3224i in the Printer category
Wednesday, December 7, 1630
Qrious Secure targeting the NETGEAR router and the Western Digital NAS in the SOHO SMASHUP category
Wednesday, December 7, 1700
DEVCORE targeting the HP Color LaserJet Pro M479fdw in the Printer category
Wednesday, December 7, 1830
DEVCORE targeting the Canon imageCLASS MF743Cdw in the Printer category
Ledger Donjon targeting WAN interface of the TP-Link AX1800 in the Router category
Luca MORO (@johncool__) targeting the WD My Cloud Pro Series PR4100 in the NAS category
Wednesday, December 7, 2030
Aleksei Stafeev targeting the Lexmark MC3224i in the Printer category
Bugscale targeting the WAN interface of the NETGEAR RAX30 AX2400 in the Router category
Interrupt Labs targeting the Samsung Galaxy S22 in the Mobile Phone category
Thursday, December 8 - 0930
STAR Labs targeting the Synology router and the Canon printer in the SOHO SMASHUP category
Team Viettel targeting the WD My Cloud Pro Series PR4100 in the NAS category
Thursday, December 8 - 1130
Chi Tran targeting the Canon imageCLASS MF743Cdw in the Printer category
DEVCORE targeting the Sonos One Speaker in the Smart Speaker category
Thursday, December 8 - 1330
Team Viettel targeting the Cisco router and the Canon printer in the SOHO SMASHUP category
Qrious Secure targeting the Samsung Galaxy S22 in the Mobile Phone category
Thursday, December 8 - 1530
Peter Geissler targeting the Canon imageCLASS MF743Cdw in the Printer category
Qrious Secure targeting the WAN interface of the NETGEAR RAX30 AX2400 in the Router category
Pentest Limited targeting the WD My Cloud Pro Series PR4100 in the NAS category
Thursday, December 8 - 1730
R-SEC targeting the Canon imageCLASS MF743Cdw in the Printer category
Neodyme targeting the WAN interface of the NETGEAR RAX30 AX2400 in the Router category
Pentest Limited targeting the Samsung Galaxy S22 in the Mobile Phone category
Thursday, December 8 - 1900
NCC Group EDG targeting the Ubiquiti and the Lexmark printer in the SOHO SMASHUP category
Thursday, December 8 - 1930
Claroty Research targeting the WD My Cloud Pro Series PR4100 in the NAS category
Friday, December 9 - 0930
NCC Group EDG targeting the Canon imageCLASS MF743Cdw in the Printer category
Quarkslab targeting the WAN interface of the NETGEAR RAX30 AX2400 in the Router category
Peter Geissler targeting the Lexmark MC3224i in the Printer category
Friday, December 9 - 1100
sushiQ targeting the Lexmark MC3224i in the Printer category
Nettitude targeting the WAN interface of the NETGEAR RAX30 AX2400 in theRouter category
Friday, December 9 - 1130
Synacktiv targeting the Canon imageCLASS MF743Cdw in the Printer category
Friday, December 9 - 1230
NCC Group EDG targeting the WAN interface of the Synology RT6600ax in the Router category
Friday, December 9 - 1300
ANHTUD targeting the Canon imageCLASS MF743Cdw in the Printer category
DEVCORE targeting the Lexmark MC3224 in the Printer category
Friday, December 9 - 1430
namnp targeting the Canon imageCLASS MF743Cdw in the Printer category
Sonar targeting the WAN interface of the Synology RT6600ax in the Router category
Welcome to the first day of Pwn2Own Toronto for 2022. We’ll be updating this blog in real time as results become available. Even though we have an unprecedented number of entries this year, we are going to buy all additional rounds that have entered the competition. The first winner on each target will receive the full cash award and the devices under test. For the second and subsequent rounds on each target, all other winners will receive 50% of the prize package, however, they will still earn the full Master of Pwn points.
Results current as of 19:30 Eastern
SUCCESS - To start off the competition with a bang, Nettitude was able to execute their Stack-based Buffer Overflow attack against the Canon imageCLASS MF743Cdw in the Printer category. They earn $20K and 2 Master of Pwn points.
SUCCESS - Tri Dang and Bien Pham (@bienpnn) from Qrious Secure were able to execute 2 bugs (authentication bypass and command injectiong) attack against the WAN interface of TP-Link AX1800 in the Router category. They earn $20K and 2 Master of Pwn points.
Qrious Secure targeting the WAN interface of TP-Link AX1800 in the Router category
SUCCESS - Horizon3 AI
was able to execute their command injection attack by serenading the crowd with a little tune from a popular classic against the Lexmark MC3224i in the Printer category. They earn $20K and 2 Master of Pwn points.
Some soothing tunes from some famous plumbers!
SUCCESS - Gaurav Baruah was able to execute their command injection attack against the WAN interface of the Synology RT6600ax in the Router category, earning $20K cash and 2 Master of Pwn points.
Command injection attack against the WAN interface of a Synology RT6600ax.
SUCCESS - Interrupt Labs provided the first bit of drama for the day, but was able to execute their stack-based buffer overflow attack on the 3rd and final try against the HP Color LaserJet Pro M479fdw in the Printer category. They earn $20K and 2 Master of Pwn points.
SUCCESS - STAR Labs was able to execute their improper input validation attack on their 3rd try against the Samsung Galaxy S22. They earn $50K and 5 Master of Pwn points.
WITHDRAWN - Unfortunately Quarkslab targeting the LAN interface of the NETGEAR RAX30 AX2400 in the Router category to had to withdraw their entry, resulting in a -0.5 point penalty against Master of Pwn. They have another entry later on, so best of luck to them then!
SUCCESS - Computest was able to execute their command injection root shell attack against the LAN interface of the Synology RT6600ax in the Router category. They earn $5K and 1 Master of Pwn points.
FAILURE - Unfortunately, PHPHooligans were unable to get the first ever SOHO SMASHUP exploit targeting the NETGEAR router and the Lexmark printer working within the time allotted.
SUCCESS - Chim was able to execute their improper input validation attack against the Samsung Galaxy S22. They earn $25K (round 2) and 5 Master of Pwn points.
Gotta love that calc!
SUCCESS - Interrupt Labs was able to execute 2 bugs (SQL injection and command injection) against the LAN interface of the NETGEAR RAX30 AX2400 in the Router category. They earn $5K and 1 Master of Pwn points.
FAILURE - Tenable was unable to get their exploit of the LAN interface of the TP-Link AX1800 in the Router category working within the time allotted.
SUCCESS - DEVCORE becomes the first team ever to successfully execute two different Stack-based buffer overflow attacks against a Mikrotik router and a Canon printer in the brand new SOHO SMASHUP category. They earn a cool $100K cash and 10 Master of Pwn points.
Pretty sure it’s obvious who Pwned this!
SUCCESS - Claroty Research was able to execute a chain of 3 bugs (2x Missing Auth for Critical Function and an Auth Bypass) attack against the Synology DiskStation DS920+ in the NAS category. They earn $40K and 4 Master of Pwn points.
WITHDRAWN - NCC Group EDG targeting the LAN interface of the TP-Link AX1800 in the Router category has withdrawn their entry which unfortunately results in a -0.5 Master of Pwn point penalty.
SUCCESS - Team Viettel was able to execute 2 bugs (including a command injection) in an attack against the HP Color LaserJet Pro M479fdw in the Printer category. They earn $10K and 2 Master of Pwn points.
Pwning in style!
BUG COLLISION - ASU SEFCOM was able to execute their OOB Write attack against the Synology DiskStation DS920+ in the NAS category to gain code execution. However, one of the exploits they used was already publicly known. They still earn $10K and 2 Master of Pwn points.
A collision, but still good stuff!
SUCCESS - Claroty Research was able to execute 5 different bugs in an attack against the LAN interface of the NETGEAR RAX30 AX2400 in the Router category. They earn $2.5K and 1 Master of Pwn points.
BUG COLLISION - NCC Group EDG was able to execute their command injection attack against the LAN interface of the Synology RT6600ax in the Router category. However, the exploit they used was exploited earlier in the competition. They still earn $1250 and 0.5 Master of Pwn points.
SUCCESS - Neodyme became the 2nd team to triumph in the new SOHO SMASHUP category by executing an attack using 3 bugs against a NETGEAR router and an HP printer. They earn $50K and 10 Master of Pwn points.
BUG COLLISION - Tri Dang from Qrious Secure successfully exploited the LAN interface of the NETGEAR RAX30 AX2400 in the Router category but was ruled a COLLISION because of an earlier exploit. They still earn $1250 and 0.5 Master of Pwn points.
That wraps up the first day of Pwn2Own Toronto 2022! We awarded $400,000 for 26 unique bugs during the first day of the contest. We’ll continue posting results and videos to Twitter, YouTube, Mastodon, LinkedIn, and Instagram, so follow us on your favorite flavor of social media for the latest news from the event.
Welcome back to Pwn2Own Toronto! Yesterday, we awarded $400,000 for 26 unique 0-days. We saw the Samsung Galaxy exploited twice and two successful demonstrations in the SOHO Smashup category. Today’s event’s look to be just as exciting. We’ll be updating this blog with results throughout the day.
Results current as of 21:15. All times Eastern (GMT-5). All denominations are in USD.
SUCCESS - for the first attempt of Day 2, ANHTUD Information Security Department was able to execute exploits against 2 bugs (one being a stack-based buffler overflow) on a HP Color LaserJet Pro M479fdw in the Printer category. They earn $10K and 2 Master of Pwn points.
We are not camera shy here at Pwn2Own!
BUG COLLISION - PHPHooligans was able to execute 2 exploits against the WAN interface of the NETGEAR RAX30 AX2400 in the Router category. However, the exploits they used were previously used in the competition. They still earn $10K and 1 Master of Pwn points.
SUCCESS and BUG COLLISION - Bugscale was able to succesfully launch an attack against the Synology router and HP Printer in today's first SOHO SMASHUP challenge using one unique bug and another previously known bug. They earn $37,500 and 7.5 Master of Pwn points.
SUCCESS - Toan Pham and Tri Dang from Qrious Secure were able to execute an attack using 2 bugs against the Sonos One Speaker in the Smart Speaker category. They earn $60K and 6 Master of Pwn points.
SUCCESS - Team Viettel was able to execute their Command Injection, Root Shell attack against the LAN interface of the TP-Link AX1800 in the Router category. They earn $5K and 1 Master of Pwn points.
Team Viettel (@rskvp93, @_q5ca, @hoangnx99 from @vcslab)
SUCCESS - Le Tran Hai Tung was able to execute an OOB Write attack against the Canon imageCLASS MF743Cdw in the Printer category. They earn $10K and 2 Master of Pwn points.
Pwned!
SUCCESS - Synacktiv was able to execute their command injection attack against the Lexmark MC3224i in the Printer category. They earn $10K and 2 Master of Pwn points.
Lexmark Pwn!
SUCCESS and BUG COLLISION - STAR Labs was able to succesfully launch an attack against the Sonos One Speaker in the Smart Speaker category using one unique bug and another previously known bug. They earn $22,500 and 4.5 Master of Pwn points.
Sonos Pwned!
BUG COLLISION - Summoning Team was able to execute their command injection attack against the LAN interface of the Synology RT6600ax in the Router category. However, the exploit they used was already used earlier in the competition. They still earn $1250 and 0.5 Master of Pwn points.
Collision! But still earns some coin!
SUCCESS and BUG COLLISION - NCC Group EDG was able to succesfully launch an attack against the WAN interface of the NETGEAR RAX30 AX2400 in the Router category using one unique bug and another N-day. They earn $7.5K and 1.5 Master of Pwn points.
SUCCESS - Team Viettel was able to execute their stack-based buffer overflow attack against the Canon imageCLASS MF743Cdw in the Printers category . They earn $10K and 2 Master of Pwn points.
New branding for the screen!
SUCCESS - NCC Group EDG was able to execute their command injectino attack against the Lexmark MC3224i in the Printer category. They earn $10K and 2 Master of Pwn points.
Lexmark printer pwned again!
FAILURE - Qrious Secure was unable to get their complete exploit of the NETGEAR router and the Western Digital NAS in the SOHO SMASHUP category working within the time allotted.
BUG COLLISION - DEVCORE was able to execute their Stack Based Buffer Overflow attack against the HP Color LaserJet Pro M479fdw in the Printer category. However, the exploit they used was already used earlier. They still earn $5K and 1 Master of Pwn points.
A touch of style but unfortunately a collision!
WITHDRAWN - Ledger Donjon unfortunately withdrew their attempt to attack the WAN interface of the TP-Link AX1800 in the Router category. This results in a -1 Master of Pwn point penalty.
SUCCESS - DEVCORE was able to execute their heap-based buffer overflow attack against the Canon imageCLASS MF743Cdw in the Printer category. They earn $10K and 2 Master of Pwn points.
Full win for DEVCORE!
SUCCESS - Luca MORO (@johncool__) was able to execute their Classic Buffer Overflow attack against the WD My Cloud Pro Series PR4100 in the NAS category. They earn $40K and 4 Master of Pwn points.
SUCCESS - Interrupt Labs was able to execute their improper input validation attack against the Samsung Galaxy S22 in the Mobile Phone category. They earn $25K and 5 Master of Pwn points.
Another poor Galaxy S22 pwned!
FAILURE - Bugscale was unable to get their exploit of the WAN interface of the NETGEAR RAX30 AX2400 in the Router category working within the time allotted.
SUCCESS and BUG COLLISION - for the final attempt of the night, Aleksei Stafeev was able to succesfully launch an attack against the Lexmark MC3224i in the Printer category using one unique command injection and another bug that was found earlier in the competition. They earn $7.5K and 1.5 Master of Pwn points.
Welcome back to Pwn2Own Toronto! Yesterday, we awarded another $281,500 for 17 unique bugs across multiple categories. That brings our two-day total to $681,250 awarded for 46 unique 0-days. Today’s highlights include more attempts at the Samsung Galaxy, entries in the SOHO Smashup category, and more smart speaker. We’ll be updating this blog with results throughout the day.
Results current as of 21:00. All times Eastern (GMT-5). All denominations are in USD.
SUCCESS - On the first success of Day 3, Team Viettel was able to execute their OS Command Injection attack against the WD My Cloud Pro Series PR4100 in the NAS category. They earn $20K and 4 Master of Pwn points.
BUG COLLISION - STAR Labs was able to execute their SOHO SMASHUP attack on the 3rd and final try against the Synology router and the Canon printer. However, the exploits they used were seen previously in the competition. They still earn $25K and 5 Master of Pwn points.
SOHO Smashed!
SUCCESS - newcomer Chi Tran of Bun Bo Ong Chi was able to execute their stack based buffer overflow attack against the Canon imageCLASS MF743Cdw in the Printer category. They earn $10K and 2 Master of Pwn points.
Anyone else getting a hankering for noodles?
SUCCESS and BUG COLLISION - DEVCORE builds on their total with a partial win (1 unique + 1 known bug) to execute their stack-based buffer overflow + OOB Read attack against the Sonos One Speaker in the Smart Speaker category. They earn $22.5K and another 4.5 Master of Pwn points.
Taking over the Sonos!
FAILURE - Qrious Secure was unable to get their exploit of the Samsung Galaxy S22 in the Mobile Phone category working within the time allotted.
SUCCESS and BUG COLLISION - Team Viettel launches a successful attack with 1 unique + 1 known bug against the Cisco router and the Canon printer in the SOHO SMASHUP category. They earn $37.5K and another 7.5 Master of Pwn points.
Celebrating the pwn with a little bubbly!!
SUCCESS - Pentest Limited was able to execute a 3-bug attack (OS command injection, SSRF & uncontrolled resource consumption) against the WD My Cloud Pro Series PR4100 in the NAS category. They earn $20K (round 3) and 4 Master of Pwn points.
BUG COLLISION - Peter Geissler (@bl4sty) was able to execute their successful attack against the Canon imageCLASS MF743Cdw in the Printer category. However, the exploit they used was already used in the contest. While earning $5K and 1 Master of Pwn points, Peter definitely wins major style points for one of the COOLEST hacks so far in the competition.
SUCCESS and BUG COLLISION - Qrious Secure launches a successful attack with 2 unique + 1 N-day bug against the WAN interface of the NETGEAR RAX30 AX2400 in the Router category. They earn $8.5K and another 1.75 Master of Pwn points.
FAILURE - Neodyme was unable to get their exploit of the WAN interface of the NETGEAR RAX30 AX2400 in the Router category working within the time allotted.
SUCCESS - Pentest Limited was able to execute their Improper Input Validation as the last Samsung Galaxy S22 attack in the Mobile Phone category. They earn $25K and 5 Master of Pwn points.
SUCCESS - R-SEC just upped the cool points and was able to not just execute their Stack-based Buffer Overflow attack against the Canon imageCLASS MF743Cdw in the Printer category, but they actually Rick-rolled the printer! They earn $10K and 2 Master of Pwn points.
SUCCESS - NCC Group EDG was able to execute a 2 exploit (command injection, type confusion) attack against the Ubiquiti and the Lexmark printer in the SOHO SMASHUP category. They earn $50K and 10 Master of Pwn points.
SUCCESS - for our nightcap, Claroty Research was able to execute a whopping FIVE bug attack against the WD My Cloud Pro Series PR4100 in the NAS category. They earn $20K and 4 Master of Pwn points.
Welcome back to the final day of Pwn2Own Toronto for 2022! Yesterday, we awarded another $253,500 USD, which brings our three-day total to $934,750. While that alone would make it an amazing event, we’ve got another full day of exploitation ahead of us. Stay tuned as we update this blog with results as we get them and total the points to crown the Master of Pwn.
Results current as of 16:30. All times Eastern (GMT-5). All denominations are in USD.
And we are finished! All of the Day Four results are below. We awarded another $55,000 today bringing our contest total to $989,750. Over the contest, we purchased 63 unique zero days. The Master of Pwn title came down to the wire, but the team from DEVCORE claimed their second title with winnings of $142,500 and 18.5 points. Team Viettel and the NCC group were close behind with 16.5 and 15.5 points respectively. Congratulations to all the contestants and Pwn2Own winners.
Final Master of Pwn standings
Day Four Results
FAILURE - Quarkslab was unable to get their exploit of the NETGEAR WAN interface working within the time allotted.
FAILURE - Peter Geissler was unable to get his exploit of the Lexmark MC3224i printer working within the time allotted.
BUG COLLISION - The NCC Group was able to execute their code execution attack against the WAN interface of the Canon printer. However, the exploit they used was previously in the contest. They still earn $5,000 and 1 Master of Pwn points.
NCC demonstrates their code execution by dropping their logo on the LCD screen
FAILURE - The Nettitude team was unable to get their exploit of the WAN interface of the NETGEAR router working within the time allotted.
BUG COLLISION - The Synacktiv team was able to execute their attack against the Canon printer with with a heap overflow. However, the exploit they used was previously used prior in the contest. They still earn $5,000 and 1 Master of Pwn points.
The Synacktiv ninjas leave the mark on a Canon printer
SUCCESS - Chris Anastasio used a heap-based buffer overflow to exploit the Lexmark printer, which earns him $10,000 and 1 Master of Pwn point.
Chris Anastasio shows off his reverse shell
BUG COLLISION - The NCC Group was able to execute their RCE attack against the WAN interface of the Synology router. However, the exploit they used was previously used in the contest. They still earn $5,000 and 1 Master of Pwn points.
SUCCESS - The ANHTUD Information Security Department used another heap-based overflow to exploit the Canon printer and add $10K to their contest total.
ANHTUD shows off the heap-based overflow
BUG COLLISION - The DEVCORE team may have had a collision against the Lexmark printer in their last attempt, but the $5k and 1 Master of Pwn points confirms their win of Master of Pwn - the second time they've reached that summit!
Even a collision can’t stop DEVCORE from becoming Master of Pwn
BUG COLLISION - The Sonar team successfully demonstrated there exploit of the WAN interface of the Synology router. However, the bug they used had been previousy demonstrated during the contest. They still earn $5,000 and 1 Master of Pwn points.
uid=0 means Sonar took control of this Synology router
SUCCESS - The namnp team showed a surprised Pikachu on the Canon printer, but the Pikachu was the only one surprised with the results. Their unique bug earned them $10,000 and 1 point towards Master of Pwn.
The namnp team was not surprised with this result
Pwn2Own Toronto 2022 - Day Four Results and Master of Pwn
Welcome to the final Patch Tuesday of 2022, and the first since Pwn2Own Toronto. As always, Adobe and Microsoft have released their latest security fixes just in time for the winter holidays. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for December 2022
For December, Adobe released three patches fixing 37 CVEs in Illustrator, Experience Manager, and Adobe Campaign Classic. One of these bugs was reported through the ZDI program. All of the patches are rated Important in severity. The largest is the update for Experience Manager, which covers 32 bugs. The most severe of these could allow code execution through cross-site scripting (XSS). The fix for Illustrator addresses four memory leaks. The final patch for Campaign corrects a single privilege escalation bug.
None of the bugs fixed by Adobe this month are listed as publicly known or under active attack at the time of release. Adobe categorizes these updates as a deployment priority rating of 3.
Microsoft Patches for December 2022
This month, Microsoft released 52 new patches addressing CVEs in Microsoft Windows and Windows Components; Azure; Office and Office Components; SysInternals; Microsoft Edge (Chromium-based); SharePoint Server; and the .NET framework. This is in addition to two CVEs fixed earlier this month, which brings the December release total to 54 fixes overall. A total of 12 of these CVEs were submitted through the ZDI program.
Of the 52 new patches released today, six are rated Critical, 43 are rated Important, and three are rated Moderate in severity. December is typically a light month for Microsoft patches, and this year is no exception. It’s also the smallest monthly release this year. Overall, 2022 was Microsoft’s second busiest ever with Microsoft fixing over 900 CVEs in total.
One of the new CVEs released this month is listed as publicly known and one is listed as being in the wild at the time of release. Let’s take a closer look at some of the more interesting updates for this month, starting with the bug under active attack:
- CVE-2022-44698 – Windows SmartScreen Security Feature Bypass Vulnerability This bug has been widely discussed on the bird site and is likely related to the Mark of the Web bug patched last month. In this case, a file could be created that evades the Mark of the Web detection and therefore bypass security features such as Protected View in Microsoft Office. Considering how many phishing attacks rely on people opening attachments, these protections are vital in preventing malware and other attacks. It’s good to see Microsoft (finally) address these bugs.
- CVE-2022-44713 – Microsoft Outlook for Mac Spoofing Vulnerability We don’t often highlight spoofing bugs, but anytime you’re dealing with a spoofing bug in an e-mail client, you should take notice. This vulnerability could allow an attacker to appear as a trusted user when they should not be. Now combine this with the SmartScreen Mark of the Web bypass and it’s not hard to come up with a scenario where you receive an e-mail that appears to be from your boss with an attachment entitled “Executive_Compensation.xlsx”. There aren’t many who wouldn’t open that file in that scenario.
- CVE-2022-41076 – PowerShell Remote Code Execution Vulnerability This Critical-rated bug could allow an authenticated user to escape the PowerShell Remoting Session Configuration and run unapproved commands on an affected system. Threat actors often try to “live off the land” after an initial breach – meaning they use tools already on a system to maintain access and move throughout a network. PowerShell is one such tool, so any bug that bypasses restrictions is likely to be abused by intruders. Definitely don’t ignore this patch.
- CVE-2022-44699 – Azure Network Watcher Agent Security Feature Bypass Vulnerability As someone who has done extensive incident response in the past, I know all too well the importance of good logs. That’s why this patch stood out to me. This bug would allow someone to terminate the packet capture from the Network Watcher agent. There might not be many enterprises relying on this tool, but for those using this VM extension, this fix should be treated as critical and deployed quickly.
Here’s the full list of CVEs released by Microsoft for December 2022:
Windows Graphics Component Elevation of
Privilege Vulnerability
Moderate
7.8
No
No
EoP
Looking at the remaining Critical-rated fixes, there are two patches for the older Secure Socket Tunneling Protocol (SSTP). Both could allow a remote, unauthenticated threat actor to get code execution on an affected system by sending a specially crafted connection request to a server with the RAS Server role enabled. If you aren’t using this service, you should disable it. If you are using it, test and deploy these patches quickly. There are also two Critical-rated code execution bugs in SharePoint server, and we’ve seen SharePoint exploited in the wild with older, patched bugs. Definitely make sure you’re patching your SharePoint instances. The final Critical bug resides in Dynamics AV and could allow an authenticated attacker to execute code in the context of the server’s account through a network call.
Beyond these, there are 16 other remote code execution bugs getting fixes this December, including multiple Office bugs reported by ZDI research Mat Powell. Most of these are the open-a-file-get-owned sort, but a couple of these patches are worth a second look. The update for the .NET Framework seems to hit every supported version, but no additional information about the bug itself is available. Two different researchers are credited for it, which implies a bug collision from multiple sources. I always pay extra attention to bugs when multiple people have independently reported them. Finally, the update for Windows Terminal is found in the Windows Store, so it should be automatically applied. However, if you have disabled automatic Store updates or are in a disconnected environment, you’ll need to apply the patch by hand.
There are 18 patches addressing Elevation of Privilege (EoP) bugs in this month’s release. For the most part, these bugs require an authenticated user to execute specially crafted code on an affected system to escalate privileges. However, there are a few that deserve extra scrutiny. The first two are yet more fixes for the Print Spooler service. The long tail of PrintNightmare grows even longer. The bug in the DirectX Graphics Kernel is the one bug listed as public for December. I already mentioned incident response and living off the land. The bug in Sysinternals Sysmon combines both as many responders rely on Sysinternals services. Exploiting these for privilege escalation would certainly be something. The final EoP of note is a bug in Hyper-V that would allow an attacker to execute code with SYSTEM privileges.
The December release includes three information disclosure bugs. This month, they all simply result in info leaks consisting of unspecified memory contents.
There are only three Denial-of-Service (DOS) bugs receiving patches this month. The first is in Hyper-V and could allow a guest OS to “affect the functionality of the Hyper-V host.” Microsoft doesn’t make it clear if the Hyper-V host would completely shut down or if only certain services are affected. Either way, it’s not good when on guest OS can negatively impact the host OS. The other DoS bugs are in the Windows Kernel and Local Session Manager (LSM), but Microsoft provides no further information on those.
Besides the one fix for Outlook for Mac, there’s one other spoofing bug in Microsoft Edge (Chromium-based) receiving a patch this month. This bug allows an attacker to change the content of the autofill box that overlaps an error message on a specially crafted website. While interesting, I’m not sure how this would really be used in an actual attack. Still, never underestimate the ingenuity of determined threat actors.
Finally, there is one new advisory (ADV220005) this month providing additional guidance on third-party drivers that appear to be certified by the Microsoft Windows Hardware Developer Program. According to Microsoft, drivers that appear to have been certified by this program have been seen in the wild in post-exploitation activity. There are no servicing stack updates this month.
Looking Ahead
The first Patch Tuesday of 2023 will be on January 10, and we’ll return with details and patch analysis then. Be sure to catch the Patch Report webcast on our YouTube channel. It should be posted in just a few hours. Until then, Merry Christmahanakwanzika, happy patching, and may all your reboots be smooth and clean!
Last week, we completed our largest Pwn2Own contest ever. We saw 66 entries over four days and witnessed some amazing research resulting in $989,750 USD for 63 unique 0-days. However, leading up to the event was anything but smooth sailing on calm seas. Here’s the wrap video summarizing the event:
When we published the rules, we anticipated quite a bit of interest in both the routers and the SOHO Smashup targets. What we didn’t expect was 85 entries overall. To put some perspective on that number, in 2017, we had 13 total entries in what was (at the time) our largest event ever. We’ve had some growth.
While we were struggling to find a way to run that many attempts in three days, the first of several patches appeared. Most notably, NETGEAR released a fix specifically targeting bugs that were scheduled to be demonstrated during the contest. TP-Link and Sonos also released updates. As a consequence, many contestants withdrew their entries. Our inbox was flooded with questions about various updates and configuration details. At one point, we were down to just over 50 entries. One of our goals with Pwn2Own is to incentivize companies to improve the security of their devices and services, so it’s great to see improvements happen – whether they are a direct result of Pwn2Own entries or pre-emptive patches that stop Pwn2Own entries. It also highlights the skill and ingenuity of the researchers participating in the contest as many had quickly bypassed the patch and re-submitted entries. By the time we started the contest, we had ramped back up to 66 entries scheduled for four days.
Targets awaiting configuration
Many don’t realize that each attempt needs at least two hours scheduled. The most obvious 30 minutes are the attempt itself. Before the attempt, we need time to set up the test environment. Sometimes that’s as simple as connecting a printer to a switch and giving it an IP address. Other times, it can be quite complex depending on the target. We need time after the attempt, too. The contestants provide ZDI analysts with the details of the bugs they used in their exploit. Pwn2Own is a true 0-day contest, which means it doesn’t qualify for the full award if we already know about the bug. In the past, we’ve seen contestants submit bugs to us and the vendors prior to the event in an attempt to kill their competitor’s bugs. Sometimes it works. Finally, we bring the vendors in to disclose the bugs to them as well. They are allowed to ask questions directly to the researchers about their entry. “How did you find this?” is a popular one. This is another great resource Pwn2Own provides – a bridge between a global network of independent researchers and vendors creating the services and products we all rely on.
All eyes on the primary stage
Now that we have identified the targets, published the rules, applied the patches, held the drawing, and made the schedule (whew!), we are now ready to run an attempt. A ZDI analyst, sometimes “a gruff-looking bald man with a goatee,” will ask if you are ready, and the countdown begins. Now we find out if your hours and hours of research will work as intended or if something goes awry. Most often, the exploit succeeds and everyone claps. Visually, there’s not a lot to see. We can’t show the screens because we’re dealing with unpatched bugs. We don’t want them unintentionally exposed. Sometimes it fails. Contestants have the opportunity to make changes to their exploit, confirm configurations, ask questions, and try again. Sometimes they triumph on a subsequent attempt, which happened multiple times in this contest. For those interested, here’s a list of the bug types used during the event:
Once the contest is complete, our work continues as we coordinate the release of the patches with the vendors, develop protection rules for the various Trend Micro products we support, and work on paying the winners. While it really is a mountain’s worth of effort, Pwn2Own is one of the highlights of our year. And there’s always another one coming up. Just days before the Toronto event occurred, we announced the rules and targets for our Miami contest, which happens in February.
Disclosing bugs after a successful attempt
I’ve literally lost count of how many Pwn2Owns I have participated in. Each one has its own unique story. Each one leaves us a different sort of exhausted. Each one shows us something we’ve never seen before. And that’s why we’ll keep doing them as long as the powers that be allow us to do so. We hope to see you at one someday soon.
We’ve successfully orbited our star once more and are full throttle into the new year. We’ve just completed our largest Pwn2Own ever in Toronto and are only six weeks away from Pwn2Own Miami, but before we go too far into 2023, now is a good time to look at some of the numbers and highlights of the past year.
These are a Few of My Favorite Bugs
It’s always great to see the huge number of amazing bugs submitted by independent researchers around the globe, but some really stood out. We’re super thankful for our global community of independent researchers, and we congratulate the 23 researchers to achieve reward levels in 2022. We had five people reach Platinum status, five reach Gold, seven Silver, and six Bronze. The work and submissions from our community of independent researchers are key to our success, and we thank all of them for their continued trust in our program. Of course, there are some particular bugs I wanted to specifically call out. These are not necessarily the best bugs of 2022 – I’m not sure how you could really judge that – but these are some that stand out to me. In no particular order, here are a few of my favorite bugs from last year:
ZDI-22-1655: Microsoft Teams Demonstrated during Pwn2Own Vancouver by the STAR Labs team, this exploit chain uses two vulnerabilities in the Microsoft Teams desktop client for Windows to achieve remote code execution on the victim user’s machine. The first vulnerability is a Client-Side Template Injection (CSTI) in rendering chat messages, allowing for arbitrary JavaScript code execution within the main webview of Microsoft Teams when the victim user previews a chat message containing an Angular template injection payload. The second vulnerability is an arbitrary file write operation, which allows the planting of malicious files that will be executed by subsequent launches of the Teams desktop client.
ZDI-22-1406/ZDI-22-1407: Tesla Model 3 Speaking of Pwn2Own Vancouver, these two bugs were used by the Synacktiv team to compromise the Model 3’s infotainment system. This allowed them to flash the headlights, open the “frunk”, and turn on the wiper blades. And they did it without touching the vehicle. Here’s the video of these bugs in action:
ZDI-22-1690: Linux Kernel This bug is the lone CVSS 10 advisory we published last year, and the advisory was published towards the end of December. However, the bug was actually patched in August. One of the difficulties in what we do at the ZDI revolves around getting vendors (or open-source maintainers) to let us know when bugs are fixed. This bug is a use-after-free that could result in code execution in the context of the kernel – provided the target is using ksmbd. How many people are running ksmbd? We don’t know either, but probably not millions. For those who are, though, this is a serious bug – and since the patch was released in August, most kernels should have been updated anyway by the time we published our advisory. And for the record, we agree that putting an SMB server in a Linux kernel module is…problematic.
ZDI-22-856: OPC UA .NET Standard Here’s another bug demonstrated at Pwn2Own. In this case, it was from the Miami edition, which focuses on industrial control systems (ICS) and SCADA. The team of Daan Keuper & Thijs Alkemade from Computest was able to bypass the trusted application check due to a mismatch between the .NET certificate chain validation API and a custom implementation of certificate chain building. This allows an attacker to forge new certificates accepted by the application, with full control over the contents of these certificates. Not only was it one of the most impressive bugs demonstrated at that contest, but it’s also some of the best research ever displayed at any Pwn2Own.
ZDI-22-1624: Microsoft Exchange Server There are actually 31 advisories with this CVE (CVE-2022-41082), but this was the initial report. There’s already been a mountain of information about these Exchange bugs (including some from our team), so I won’t re-hash the technical details here. What’s really wild to me is that there are still nearly 70,000 unpatched, internet-facing Exchange servers out there. If you’re still running Exchange on-prem, why aren’t you patching it??!? That’s probably something we should investigate in 2023.
Again – these are just a few of my favorites. There are plenty of others I could talk about, including beeping printers to the tune of Mario, multiple Samsung Galaxy hacks, multiple SOHO smash-up winners, a gazillion PDF-related bugs, and so much more.
By the Numbers
In 2022, the ZDI published 1,706 advisories – the most ever in the history of the program. This is the third year in a row that eclipsed our previous all-time record. While it’s unlikely we’ll keep up a record-breaking pace for a fourth year in a row, it does speak to the overall health of the program. Of course, I said that last year as well. While we do work with people from around the world, our own researchers had their busiest year ever, too. Just over 44% of all published advisories were reported by ZDI vulnerability analysts. Here’s how those numbers of advisories stack up year-over-year.
Figure 1 - Published ZDI Advisories Year-Over-Year
Coordinated disclosure of vulnerabilities continues to be a priority for our program, and it continues to be a success as well. While 2020 saw our largest percentage of 0-day disclosures, the number declined in 2021, and further declined last year to just 6% of our overall disclosures – down from the 18.6% high of 2020. This is a positive trend, and we hope it continues moving forward.
Figure 2 - 0-day Disclosures Since 2005
Here’s a breakdown of advisories by vendor. The top vendors should not surprise many, but it is interesting to see Adobe that far ahead of everyone else. Our program is responsible for over 70% of Adobe bugs fixed last year. Not too shabby. Siemens was in the #2 slot last year but fell to #7 in 2023. Bugs in SAP software more than doubled year-over-year to land them in the #5 position on our list. Many enterprises rely on SAP, so finding (and fixing) vulnerabilities in these products is a priority. We purchase quite a few ICS-related bugs throughout the year, and this list reflects that volume. Of course, Microsoft remains a popular target for our researchers as well. Around 15% of the bugs patched by the Redmond giant came through the ZDI.
Figure 3 - Published advisories per vendor for 2022
We’re always looking to acquire impactful bugs and, looking at the CVSS scores for the advisories we published in 2022, we did just that. A total of 76% of these vulnerabilities were rated Critical or High severity.
Figure 4 - CVSS 3.0 Scores for Published Advisories in 2022
When it comes to the types of bugs we’re buying, here’s a look at the top 10 Common Weakness Enumerations (CWEs) from 2022:
Figure 5 - Top 10 CWEs from 2022 Published Advisories
I’d say we had heaps of bugs last year, but that pun may be too bad even for me. Four out of the top five CWEs involve heap manipulation in one form or another. It’s also interesting to see the resurgence of SQL and OS command injection bugs. At least pointer dereferences decreased significantly as compared to 2021, so we got that going for us, which is nice.
Looking Ahead
Moving into the new year, we anticipate staying just as busy – especially in the first quarter. We currently have more than 750(!) bugs reported to vendors awaiting disclosure. We have Pwn2Own Miami and Pwn2Own Vancouver just on the horizon, plus a significant announcement later this month (no spoilers). Don’t worry if you can’t attend in person. We’ll be streaming and posting videos of the event to just about every brand of social media available.
We’re also looking to update our website and blog at some point this year. When that occurs, I promise you’ll be able to choose between a light and dark theme. I know – it doesn’t look the best on certain platforms. We’ll also be expanding our video offerings, too. I start the Patch Report in September and will continue that through 2023 at least. In the coming year, we’re also looking to expand our program by acquiring bugs with an even bigger impact on our customers and the global community.
We look forward to refining our outreach and acquisition efforts by further aligning with the risks our customers are facing to ensure the bugs we squash have the biggest impact on our customers and the broader ecosystem. In other words, the coming year is shaping up to be another exciting year with impactful research, great contests, and real information you can use. We hope you come along for the ride. Until then, be well, stay tuned to this blog, subscribe to our YouTube channel, and follow us on Twitter, Mastodon, LinkedIn, or Instagram for the latest updates from the ZDI.
Welcome to the first patch Tuesday of the new year. As expected, Adobe and Microsoft have released their latest fixes and updates. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for January 2023
For January, Adobe released four patches addressing 29 CVEs in Adobe Acrobat and Reader, InDesign, InCopy, and Adobe Dimension. A total of 22 of these bugs were submitted through the ZDI program. The update for Reader fixes 15 bugs with eight of these being ranked Critical in severity. The most severe of these would allow arbitrary code execution if an affected system opened a specially crafted file. The patch for InDesign fixes six bug, four of which are rated Critical. Similar to the Reader patch, opening a malicious file could result in code execution. That’s also true for InCopy, which also received fixes for six CVEs. The update for Dimension only addresses two CVEs, but the fix also includes an update for dependencies in SketchUp. The old version has February 22 timestamp, while the version shipped today is stamped November 9.
None of the bugs fixed by Adobe this month are listed as publicly known or under active attack at the time of release. Adobe categorizes these updates as a deployment priority rating of 3.
Microsoft Patches for January 2023
This month, Microsoft released 98 new patches addressing CVEs in Microsoft Windows and Windows Components; Office and Office Components; .NET Core and Visual Studio Code, 3D Builder, Azure Service Fabric Container, Windows BitLocker, Windows Defender, Windows Print Spooler Components, and Microsoft Exchange Server. A total of 25 of these CVEs were submitted through the ZDI program.
Of the 98 new patches released today, 11 are rated Critical and 87 are rated Important in severity. This volume is the largest we’ve seen from Microsoft for a January release in quite some time. It will be interesting to see if this volume of fixes continues throughout the year.
One of the new CVEs released this month is listed as publicly known and one is listed as being in the wild at the time of release. Let’s take a closer look at some of the more interesting updates for this month, starting with the bug under active attack:
- CVE-2023-21674 – Windows Advanced Local Procedure Call (ALPC) Elevation of Privilege Vulnerability This is the one bug listed as under active attack for this month. It allows a local attacker to escalate privileges from sandboxed execution inside Chromium to kernel-level execution and full SYSTEM privileges. Bugs of this type are often paired with some form of code exaction to deliver malware or ransomware. Considering this was reported to Microsoft by researchers from Avast, that scenario seems likely here.
- CVE-2023-21743 - Microsoft SharePoint Server Security Feature Bypass Vulnerability You rarely see a Critical-rated Security Feature Bypass (SFB), but this one seems to qualify. This bug could allow a remote, unauthenticated attacker to make an anonymous connection to an affected SharePoint server. Sysadmins need to take additional measures to be fully protected from this vulnerability. To fully resolve this bug, you must also trigger a SharePoint upgrade action that’s also included in this update. Full details on how to do this are in the bulletin. Situations like this are why people who scream “Just patch it!” show they have never actually had to patch an enterprise in the real world.
- CVE-2023-21763/CVE-2023-21764 - Microsoft Exchange Server Elevation of Privilege Vulnerability These bugs were found by ZDI researcher Piotr Bazydło and result from a failed patch of CVE-2022-41123. As such, these vulnerabilities were reported under our new timelines for bugs resulting from incomplete patches. Thanks to the use of a hard-coded path, a local attacker could load their own DLL and execute code at the level of SYSTEM. A recent report showed nearly 70,000 unpatched Exchange servers that were accessible from the internet. If you’re running Exchange on-prem, please test and deploy all the Exchange fixes quickly, and hope that Microsoft fixed these bugs correctly this time.
Here’s the full list of CVEs released by Microsoft for January 2023:
Windows Win32k Elevation of Privilege
Vulnerability
Important
7.8
No
No
EoP
Looking at the remaining Critical-rated fixes, I already mentioned the other two patches for Cryptographic Services, but these are privilege escalations rather than RCEs. There are five patches for the Layer 2 Tunneling Protocol (L2TP), which was introduced back in Windows 2000. An unauthenticated attacker could send a specially crafted connection request to a RAS server to get code execution. Microsoft lists exploit complexity as high due to the exploit needing to win a race condition, but you should not rely on that mitigation. The same is true for the two bugs in Secure Socket Tunneling Protocol (SSTP).
Moving to the other 25 code execution bugs fixed in this release, there are 14 fixes for the 3D Builder component reported by ZDI researcher Mat Powell. All of these require the user to open a maliciously crafted file to get code execution at the level of the logged-on user. That’s also true for the other Visual Studio and Office-related bugs, including two of the Visio bugs, which were also reported by Mr. Powell. There’s a fix for an LDP bug, which normally would concern me. However, in this case, it's listed as requiring authentication. There’s an RCE bug in Windows Authentication, but the description is confusing. According to Microsoft, “An attacker must already have access and the ability to run code on the target system.” Hopefully, the researchers who reported the bug will provide more information. There are two fixes for SharePoint for RCE bugs that require authentication. However, every user by default has the permissions required to exploit these bugs. There are a couple of SQL-related fixes. The first is in the ODBC driver. An attacker can execute code if they can convince an authenticated user into attempting to connect to a malicious SQL server via ODBC. It’s a similar scenario for the WDAC OLE DB provider for SQL component.
Including those already mentioned, there are a total of 38 Elevation of Privilege (EoP) bugs receiving patches this month. The vast majority of these require the attacker to execute their code on a target in order to escalate privileges – typically to SYSTEM. However, there are a few that stand out. The publicly-know bug in the Workstation Service could actually be hit remotely through RPC. If successful, they could run RPC functions that are normally restricted to local clients only. However, it only hits on systems with less than 3.5 GB of RAM, so feel free to use this as justification to buy more RAM. There are three fixes for the Print Spooler, and one of these was reported by the National Security Agency. One of the escalations in LSA leads to executing code with the group Managed Service Account (gMSA), an exception to the SYSTEM escalations. The bug in the Backup Service could allow for either privilege escalation or data deletion. The same goes for the vulnerability in Defender. Finally, the fix for the Azure Service fabric addresses a vulnerability that impacts Service Fabric clusters orchestrated by Docker. To be protected from this, you need to manually update your Service Fabric and enable and configure the “BlockAccessToWireServer” feature flag.
There are fixes for 11 different information disclosure bugs this month, and seven of these merely result in info leaks consisting of unspecified memory contents. The others are much more interesting. To start, there are three bugs in the Cryptographic Service that result in disclosing “Windows cryptographic secrets.” One of these bugs was reported by Canada’s Communications Security Establishment – similar to the USA’s NSA. I would think they know a thing or two about crypto. There’s an info disclosure bug in Exchange, but Microsoft simply states that it could result in disclosing “sensitive information.”
Looking at the security feature bypasses, there are patches for three more in addition to the SharePoint bug already mentioned above. One is for BitLocker and could allow a physical attacker to gain access to encrypted data. Physical access is also a requirement for the SFB in the Boot Manager. If you’re relying on these to protect systems from theft and other physical attacks, make sure you get these patches. The bypass in Smart Card Resource Management Server could allow an attacker to gain access to data related to FIDO keys managed on an affected system.
The January release fixes 10 different Denial-of-Service (DoS) bugs. Microsoft provides no real detail about these bugs, so it isn’t clear if successful exploitation results in the service stopping or the system crashing. I would be most concerned about the bugs in the Netlogon and LDAP services as a successful DoS attack on these components would significantly impact an enterprise.
Finally, there are two spoofing bugs in the Exchange server receiving fixes, although the descriptions imply a different impact. One notes that successful exploitation could disclose NTLM hashes, which I would describe as info disclosure. The other notes an authenticated attacker could achieve exploitation given a Powershell remoting session to the server, which would probably classify as privilege escalation. Regardless, make sure you update your Exchange server to ensure you remediate the multiple bugs being fixed this month.
No new advisories were released this month.
Looking Ahead
The next Patch Tuesday of 2023 will be on February 14, which also happens to be a pretty romantic holiday – the first day of Pwn2Own Miami! We’ll return with details and patch analysis then. Be sure to catch the Patch Report webcast on our YouTube channel. It should be posted in just a few hours. Until then, stay safe, happy patching, and may all your reboots be smooth and clean!
Note: The contest rules were updated on February 7th to clarify guest OSes that can be used in the Virtualization Category. Please review the rules for full details.
Last year, we celebrated the 15th anniversary of Pwn2Own with a spectacular contest. We awarded more than $1,000,000 USD for the amazing research demonstrated. That makes us even more excited to return to Vancouver for the 2023 edition of Pwn2Own. Similar to last year, we’ll be holding a hybrid conference with most of us in person at the Sheraton Wall Center in Vancouver for the CanSecWest conference on March 22-24, 2023. The other part of the hybrid event means that we also allow remote participation. If you have either travel restrictions or travel safety concerns, you can opt to compete remotely.
We’re also excited to have Tesla return as a partner. They always innovate, and we’ve updated our target list to keep up. We’ve added a Steam VM Escape category with multiple targets. It may a bit strange to be targeting a steam engine on an electric car, but here we are. We’ll have both a Tesla Model 3 and a Tesla Model S available as targets, with the top prize going for $600,000 (plus the car itself). Of course, virtualization exploits are always a contest highlight, and VMware returns as a sponsor with VMware Workstation and ESXi returning as targets.
We’ve added a couple of new targets in other existing categories as well. DNS is one of the core services of the internet, and cloud computing couldn’t work without it. That’s why we’ve added Microsoft DNS Server and ISC BIND into the Servers category. Apple systems are a common item found in work centers, so we’ve added macOS back into the Local Escalation of Privilege category with a focus on the M-series MacBook Pro.
In addition to the in-person attempts at the conference, we’ll be producing quick videos of the exploits, so if you can’t attend you can still get a feel for what it’s like in the room. All told, more than $1,000,000 USD in cash and prizes are available to contestants, including the Tesla vehicle, in the following categories:
Of course, no Pwn2Own competition would be complete without us crowning a Master of Pwn. Since the order of the contest is decided by a random draw, contestants with an unlucky draw could still demonstrate fantastic research but receive less money since subsequent rounds go down in value. However, the points awarded for each unique, successful entry do not go down. Someone could have a bad draw and still accumulate the most points. The person or team with the most points at the end of the contest will be crowned Master of Pwn, receive 65,000 ZDI reward points (instant Platinum status), a killer trophy, and a prettysnazzyjacket to boot.
Let's look at the details of the rules for this year's contest.
Virtualization Category
We’re happy to have VMware returning as a Pwn2Own sponsor for 2023, and this year, again we’ll have VMware ESXi alongside VMware Workstation as a target with awards of $150,000 and $80,000 respectively. VMware has been a sponsor of Pwn2Own for multiple years, and we’ve seen some great research presented at the contest in years past. Microsoft also returns as a target and leads the virtualization category with a $250,000 award for a successful Hyper-V Client guest-to-host escalation. Oracle VirtualBox rounds out this category with a prize of $40,000. We’ve seen some amazing guest-to-host OS escalations demonstrated at previous Pwn2Own contests. Here’s hoping we see more this year.
There’s an add-on bonus in this category as well. If a contestant can escape the guest OS, then escalate privileges on the host OS through a Windows kernel vulnerability (excluding VMware ESXi), they can earn an additional $50,000 and 5 more Master of Pwn points. That could push the payout on a Hyper-V bug to $300,000. Here’s a detailed look at the targets and available payouts in the Virtualization category:
While browsers are the “traditional” Pwn2Own target, we’re continuously tweaking the targets in this category to ensure they remain relevant. We re-introduced renderer-only exploits last year, and this year, their price increases to $60,000. However, if you have that Windows kernel privilege escalation or sandbox escape, that will earn you up to $100,000 or $150,000 respectively. If your exploit works on both Chrome and Edge, it will qualify for the “Double Tap” add-on of $25,000. The Windows-based targets will be running in a VMware Workstation virtual machine. Consequently, all browsers (except Safari) are eligible for a VMware escape add-on. If a contestant can compromise the browser in such a way that also executes code on the host operating system by escaping the VMware Workstation virtual machine, they will earn themselves an additional $80,000 and 8 more Master of Pwn points. Full exploits are still required for Apple Safari and Mozilla Firefox. Here’s a detailed look at the targets and available payouts:
Enterprise applications also return as targets with Adobe Reader and various Office components on the target list once again. This year, we’re also allowing these applications to be run on an M-series MacBook. Prizes in this category run from $50,000 for a Reader exploit with a sandbox escape or a Reader exploit with a kernel privilege escalation and $100,000 for an Office 365 application. Word, Excel, and PowerPoint are all valid targets. Microsoft Office-based targets will have Protected View enabled where applicable. Adobe Reader will have Protected Mode enabled where applicable. Here’s a detailed view of the targets and payouts in the Enterprise Application category:
As mentioned, we’re again expanding the Server category by adding ISC BIND and Microsoft DNS Server to the target list. A successful exploit on one of these will earn the contestants $200,000 or $150,000 respectively. We added Samba as a target last year but has no takers. We’ll see if any registers for it in 2023. This category is rounded out by Microsoft Windows RDP/RDS, which also has a payout of $200,000. Here’s a detailed look at the targets and payouts in the Server category:
This category is a classic for Pwn2Own and focuses on attacks that originate from a standard user and result in executing code as a high-privileged user. A successful entry in this category must leverage a kernel vulnerability to escalate privileges. Ubuntu Desktop, Apple macOS, and Microsoft Windows 11 are the OSes available as targets in this category.
We introduced this category in 2021 to reflect the importance of these tools in our modern, remote workforce, and we were thrilled to see both targets compromised during the contest. Last year’s event included a 0-click exploit of Microsoft Teams. A successful attempt in this category must compromise the target application by communicating with the contestant. Some example communication requests could be audio calls, video conferences, or messages. Both Zoom and Microsoft Teams have a $75,000 award available, so we’re hoping to see more great research in this category.
We introduced the Automotive category in 2019, and we are excited to have Tesla return as a partner for 2023. We awarded a Tesla Model 3 in that first contest, but we wanted to raise the level of complexity of what constitutes a successful exploit. Tesla vehicles are equipped with multiple layers of security, and for this year’s event, there are multiple tiers of awards within the Automotive category that corresponds to some of the different layers of security within a Tesla car, with additional prize options available in certain instances. Contestants can register an entry against either a Tesla Model 3 (Intel or Ryzen-based) or the Tesla Model S (Ryzen-based).
Tier 1 earns the top prizes and represents a complete vehicle compromise. Correspondingly, this also has the highest award amounts. To win this level, a contestant will need to pivot through multiple systems in the car, meaning they will need a complex exploit chain to get arbitrary code execution on three different sub-systems in the vehicle. Success here gets a big payout and, of course, a brand-new Tesla.
In addition to the vehicle itself and $500,000, contestants can go for the additional options to raise the payout to $600,000. This represents the single largest target in Pwn2Own history. If someone can do this, it would also mean 60 total Master of Pwn points, which is nearly insurmountable. Here’s some additional info on the optional add-ons that are included in the various tier levels.
Again, it’s difficult to express the complexity of completing such a demonstration, but we’re certainly hopeful that someone can show off their exploit skills and drive off a winner.
The second tier in this category is not quite as complex but still requires the attacker to pivot through some of the vehicle’s sub-systems. This level requires the contestant to get arbitrary code execution on two different sub-systems in the vehicle, which is certainly a difficult challenge. If you include the optional targets, the largest single payout for Tier 2 would be $400,000. A winning entry in Tier 2 would still be an impressive and exciting demonstration and includes driving off with the Tesla. Tier 2 also includes some of the above add-ons, as detailed below:
The targets in Tier 3 could prove to be just as difficult, but you only need to compromise one sub-system for a win here, which is still no easy task. Not every instance within Tier 3 includes winning the car. This year also introduces the Steam VM Escape category as an attack vector. Some of the Tier 3 targets have add-ons available, but to drive away with a Tier 3 prize, a contestant would need to target one of the entries marked “Vehicle Included” in the table below:
The complete rules for Pwn2Own 2023 are found here. As always, we encourage entrants to read the rules thoroughly if they choose to participate. If you are thinking about participating but have specific configuration or rule-related questions, email us. Questions asked over Twitter or other means will not be answered. Registration is required to ensure we have sufficient resources on hand at the event. Please contact ZDI at [email protected] to begin the registration process. Registration closes at 5 p.m. Pacific Time on March 16, 2022.
Be sure to stay tuned to this blog and follow us on Twitter, Mastodon, LinkedIn, or Instagram for the latest information and updates about the contest. We look forward to seeing everyone wherever they may be, and we hope someone has a new car to drive home from this year’s Pwn2Own competition.
With special thanks to our Pwn2Own 2023 Partner Tesla and our Pwn2Own 2023 sponsor VMware