In April of this year, FreeBSD patched a 13-year-old heap overflow in the Wi-Fi stack that could allow network-adjacent attackers to execute arbitrary code on affected installations of FreeBSD Kernel. This bug was originally reported to the ZDI program by a researcher known as m00nbsd and patched in April 2022 as FreeBSD-SA-22:07.wifi_meshid. The researcher has graciously provided this detailed write-up of the vulnerability and a proof-of-concept exploit demonstrating the bug.
Our goal is to achieve kernel remote code execution on a target FreeBSD system using a heap overflow vulnerability in the Wi-Fi stack of the FreeBSD kernel. This vulnerability has been assigned CVE-2022-23088 and affects all FreeBSD versions since 2009, along with many FreeBSD derivatives such as pfSense and OPNsense. It was patched by the FreeBSD project in April 2022.
When a system is scanning for available Wi-Fi networks, it listens for management frames that are emitted by Wi-Fi access points in its vicinity. There are several types of management frames, but we are interested in only one: the beacon management subtype. A beacon frame has the following format:
In FreeBSD, beacon frames are parsed in ieee80211_parse_beacon(). This function iterates over the sequence of options in the frame and keeps pointers to the options it will use later.
One option, IEEE80211_ELEMID_MESHID, is particularly interesting:
There is no sanity check performed on the option length (frm). Later, in function sta_add(), there is a memcpy that takes this option length as size argument and a fixed-size buffer as destination:
Due to the lack of a sanity check on the option length, there is an ideal buffer overflow condition here: the attacker can control both the size of the overflow (sp->meshid) as well as the contents that will be written (sp->meshid).
Therefore, when a FreeBSD system is scanning for available networks, an attacker can trigger a kernel heap overflow by sending a beacon frame that has an oversized IEEE80211_ELEMID_MESHID option.
Building a “Write-What-Where” Primitive
Let’s look at ise->se_meshid, the buffer that is overflown during the memcpy. It is defined in the ieee80211_scan_entry structure:
Here, the overflow of se_meshid allows us to overwrite the se_ies field that follows. The se_ies field is of type struct ieee80211_ies, defined as follows:
We will be interested in overwriting the last two fields: data and len.
Back in sta_add(), not long after the memcpy, there is a function call that uses the se_ies field:
This ieee80211_ies_init() function is defined as:
The data parameter here points to the beginning of the beacon options in the frame, and len is the full length of all the beacon options. In other words, the (data,len) couple describes the options buffer that is part of the frame that the attacker sent:
As noted in the code snippet, the ies structure is fully attacker-controlled thanks to the buffer overflow.
Therefore, at $1:
-- We can control len, given that this is the full size of the options buffer, and we can decide that size by just adding or removing options to our frame. -- We can control the contents of data, given that this is the contents of the options buffer. -- We can control the ies->data pointer, by overflowing into it.
We thus have a near-perfect write-what-where primitive that allows us to write almost whatever data we want at whatever kernel memory address we want just by sending one beacon frame that has an oversized MeshId option.
Constraints on the Primitive
A few constraints apply to the primitive:
The FreeBSD kernel expects there to be SSID and Rates options in the frame. That means that there are 2x2=4 bytes of the options buffer that we cannot control. In addition, our oversized MeshId option has a 2-byte header, so that makes 6 bytes we cannot control. For convenience and simplicity, we will place these bytes at the beginning of the options buffer.
Our oversized MeshId option must be large enough to overwrite up to the ies->data and ies->len fields, but not more. This equates to a length of 182 bytes for the MeshId option, plus its 2-byte header. To accommodate the MeshId option plus the two options mentioned above, we will use an options buffer of size 188 bytes.
The ies->data and ies->len fields we overwrite are respectively the last 8 and 4 bytes within the options buffer, so they too are constrained.
The ies->len field must be equal to len for the branch at $0 not to be taken.
The big picture of what the frame looks like given the aforementioned constraints:
Maintaining stability of the target
Let’s say we send a beacon frame that uses the primitive to overwrite an area of kernel memory. There is going to be a problem at some point when the kernel subsequently tries to free ies->data. This is because ies->data is supposed to point to a malloc-allocated buffer, which may no longer be true after our overwrite.
To maintain stability and avoid crashing the target, we can send a second, corrective beacon frame that overflows ies->data to be NULL and ies->len to be 0. After that, when the kernel attempts to free ies->data, it will see that the pointer is NULL, and won’t do anything as a result. This allows us to maintain the stability of the target and ensure our primitive doesn’t crash it.
Choosing what to write, and where to write it
Now we have a nice write-what-where primitive that we can invoke with just one beacon frame plus one corrective frame. What exactly can we do with it now?
A first thought might be to use the primitive to overwrite the instructions that the kernel executes in memory. (Un)fortunately, in FreeBSD, the kernel text segment is not writable, so we
cannot use our primitive to directly overwrite kernel instructions. Furthermore, the kernel implements W^X, so no writable pages are executable.
However, the page tables that map executable pages are writable.
Injecting an implant
Here we are going to inject an implant into the target's kernel that will process "commands" that we send to it later on via subsequent Wi-Fi frames — a full kernel backdoor, if you will.
The process of injecting this implant will take four beacon frames.
This is a bit of a bumpy technical ride, so fasten your seatbelt.
Frame 1: Injecting the payload
Background: the direct map is a special kernel memory region that contiguously maps the entire physical memory of the system as writable pages, except for the physical pages of read-only text segments.
We use the primitive to write data at the physical address 0x1000 using the direct map:
0x1000 was chosen as a convenient physical address because it is unused. The data we write is as follows:
The implant shellcode area contains the instructions of our implant. The rest of the fields are explained below.
Frame 2: Overwriting an L3 PTE
Quick Background: x64 CPUs use page tables to map virtual addresses to physical RAM pages, in a 4-level hierarchy that goes from L4 (root) to L0 (leaf). Refer to the official AMD and Intel specifications for more details.
In this step, we use the primitive to overwrite an L3 page table entry (PTE) and make it point to the L2 PTE that we wrote at physical address 0x1000 as part of Frame 1. We crafted that L2 PTE precisely to point to our three L1 PTEs, which themselves point to two different areas: (1) two physical pages of the kernel text segment, and (2) our implant shellcode.
In other words, by overwriting an L3 PTE, we create a branch in the page tables that maps two pages of kernel text as writable and our shellcode as executable:
At this point, our shellcode is mapped into the target’s virtual memory space and is ready to be executed. We will see below why we're mapping the two pages of the kernel text segment.
The attentive reader may be concerned about the constraints of the primitive here. Nothing to worry about: the L3 PTE space is mostly unpopulated. We just have to choose an unpopulated range where overwriting 188 bytes will not matter.
Frame 3: Patching the text segment
In order to jump into our newly mapped shellcode, we will patch the beginning of the sta_input() function in the text segment. This function is part of the Wi-Fi stack and gets called each time the kernel receives a Wi-Fi frame, so it seems like the perfect place to invoke our implant.
How can we patch it, given that the kernel text segment is not writable? By mapping as writable the text pages that contain the function. This is what we did in frames 1 and 2, with the first two L1 PTEs, that now give us a writable view of the instruction bytes of sta_input():
Back on topic, we use the primitive to patch the first bytes of sta_input() via the writable view we created in frames 1 and 2, and replace these bytes with:
This simply calls our shellcode. However, the constraints of our primitive come into play:
The first constraint of the primitive is that the first 6 bytes that we overwrite cannot be controlled. Overwriting memory at sta_input would not be great, as it would put 6 bytes of garbage at the beginning of the function, causing the target to crash.
However, if we look at the instruction dump of sta_input, we can see that it actually has a convenient layout:
What we can do here is overwrite memory at sta_input-6. The 6 bytes of garbage will just overwrite the unreachable NOPs of the previous sta_newstate() function, with no effect on execution.
With this trick, we don’t have to worry about these first 6 bytes, as they are effectively discarded.
The second constraint of the primitive is that we are forced to overwrite exactly 182 bytes, so we cannot overwrite the first few bytes only. This is not really a problem. We can just fill the rest of the bytes with the same instruction bytes that are there in memory already.
The third constraint of the primitive is that the last 12 bytes that we write are the ies->data and ies->len fields, and these don’t disassemble to valid instructions. That’s a problem because these bytes are within sta_input(). If the kernel tries to execute these bytes, it won’t be long before it crashes. To work around this, we must have corrective code in our implant. When called for the first time, our implant must correct the last 12 bytes of garbage that we wrote into sta_input(). Although slightly annoying, this is not complicated to implement.
With all that established, we’re all set. Our implant will now execute each time sta_input() is called, meaning, each time a Wi-Fi frame is received by the target!
Frame 4: Corrective frame
Finally, to maintain the stability of the target, we send a final beacon frame where we overflow ies->data to be NULL and ies->len to be 0.
This ensures that the target won’t crash.
Subsequent communication channel
With the aforementioned four frames, we have a recipe to reliably inject an implant into the target’s kernel. The implant gets called in the same context as sta_input():
Notably, the second argument, m, is the memory region containing the buffer of the frame that the kernel is currently processing. The implant can therefore inspect that buffer (via %rsi) and act depending on its contents.
In other words, we have a communication channel with the implant. We can therefore code our implant as a server backdoor and send commands to it via this channel.
A heap buffer overflow vulnerability exists in the FreeBSD kernel. An attacker can trigger this bug by sending a beacon frame with an oversized MeshId option.
Using that vulnerability, we can implement a write-what-where primitive that allows us to perform one kernel memory overwrite per beacon frame we send.
We can use that primitive three times to inject an implant into the target’s kernel.
A fourth beacon frame is used to clean up ies->data and ies->len, to prevent a crash.
Finally, our implant runs in the kernel of the target and acts as a full backdoor that can process subsequent Wi-Fi frames we send to it.
A full exploit can be found here. It injects a simple implant that calls printf() with the strings that the attacker subsequently sends. To use this exploit from a Linux machine that has a Wi-Fi card called wifi0, switch the card to monitor mode with:
Then, build and run the exploit for the desired target. For example, if you wish to target a pfSense 2.5.2 system:
Please exercise caution - this will exploit all vulnerable systems in your vicinity.
Once you have done this, look at the target’s tty0 console. You should see: “Hello there, I’m in the kernel”.
Thanks again to m00nbsd for providing this thorough write-up. They have contributed multiple bugs to the ZDI program over the last few years, and we certainly hope to see more submissions from them in the future. Until then, follow the team for the latest in exploit techniques and security patches.
CVE-2022-23088: Exploiting a Heap Overflow in the FreeBSD Wi-Fi Stack
It’s once again Patch Tuesday, which means the latest security updates from Adobe and Microsoft have arrived. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for June 2022
This month, Adobe released six patches addressing 46 CVEs in Adobe Illustrator, InDesign, InCopy, Bridge, Robohelp, and Animate. A total of 40 of these CVEs were reported by ZDI vulnerability researcher Mat Powell. The largest update belongs to Illustrator, which addresses 17 total CVEs. The most severe of these bugs could allow code execution if an affected system opens a specially crafted file. Many of these bugs fall into the Out-Of-Bounds (OOB) Write category. The update for Adobe Bridge fixes 12 bugs, 11 of which are rated Critical. The patch for InCopy fixes eight Critical-rated bugs, all of which could lead to arbitrary code execution. Similarly, the InDesign patch fixes seven Critical-rated arbitrary code execution bugs. For both InDesign and InCopy, the bugs are a mix of OOB Read, OOB Write, heap overflow, and Use-After-Free (UAF) vulnerabilities. The lone bug fixed by the Animate patch is also a Critical-rated OOB Write that could lead to arbitrary code execution. Finally, the Robohelp patch fixes a Moderate-rated privilege escalation bug caused by improper authorization.
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 priority 3.
Microsoft Patches for June 2022
For June, Microsoft released 55 new patches addressing CVEs in Microsoft Windows and Windows Components; .NET and Visual Studio; Microsoft Office and Office Components; Microsoft Edge (Chromium-based); Windows Hyper-V Server; Windows App Store; Azure OMI, Real Time Operating System, and Service Fabric Container; SharePoint Server; Windows Defender; Windows Lightweight Directory Access Protocol (LDAP); and Windows Powershell. This is in addition to the 4 CVEs patched in Microsoft Edge (Chromium-based), and the new update for MSDT. That brings the total number of CVEs to 60.
Of the 55 new CVEs released today, three are rated Critical, 51 are rated Important, and one is rated Moderate in severity. None of the new bugs patched this month are listed as publicly known or under active attack at the time of release, however, we do have an update for MSDT, which is public and reported to be under active attack.
It's also interesting to note is what is not included in today’s release. This is the first month in recent memory without an update for the Print Spooler. We’ll see if that trend continues or if this reprieve is only temporary. Finally, there are no fixes listed for any of the bugs disclosed during Pwn2Own Vancouver.
Before we take a deeper dive into this month’s release, let’s take just a minute to remember Internet Explorer, which will go out of support tomorrow. The ubiquitous browser has served up websites to users since 1995, and while it’s doubtful anyone will miss it, it certainly had a good run. If you’re worried about your legacy apps still functioning, IE Mode in Microsoft Edge will be supported through at least 2029. With nostalgia out of the way, let’s take a closer look at some of the more interesting updates for this month, starting with the much anticipated fix for MSDT:
- CVE-2022-30190 - Microsoft Windows Support Diagnostic Tool (MSDT) Remote Code Execution Vulnerability Although it’s difficult to see from the Security Update Guide, Microsoft did release an update to address the much discuss “Follina” vulnerability in MSDT. This bug has been reported to be under active attack, so priority should be given to the testing and deployment of this update.
- CVE-2022-30136 - Windows Network File System Remote Code Execution Vulnerability This CVSS 9.8 bug looks eerily similar to CVE-2022-26937 – an NFS bug patched last month and one we blogged about last week. This vulnerability could allow a remote attacker to execute privileged code on affected systems running NFS. On the surface, the only difference between the patches is that this month’s update fixes a bug in NFSV4.1, whereas last month’s bug only affected versions NSFV2.0 and NSFV3.0. It’s not clear if this is a variant or a failed patch or a completely new issue. Regardless, enterprises running NFS should prioritize testing and deploying this fix.
- CVE-2022-30163 - Windows Hyper-V Remote Code Execution Vulnerability This bug could allow a user on a Hyper-V guest to run their code on the underlying Hyper-V host OS. The update doesn’t list the privileges the attacker’s code would run at, but any guest-to-host escape should be taken seriously. Microsoft notes that attack complexity is high since an attacker would need to win a race condition. However, we have seen many reliable exploits demonstrated that involve race conditions, so take the appropriate step to test and deploy this update.
- CVE-2022-30148 - Windows Desired State Configuration (DSC) Information Disclosure Vulnerability Most info disclosure bugs simply leak unspecified memory contents, but this bug is different. An attacker could use this to recover plaintext passwords and usernames from log files. Since DSC is often used by SysAdmins to maintain machine configurations in an enterprise, there are likely some sought-after username/password combos that could be recovered. This would also be a great bug for an attacker to move laterally within a network. If you’re using DSC, make sure you don’t miss this update.
Here’s the full list of CVEs released by Microsoft for June 2022:
* 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 release we that more than half of the patches this month deal with remote code execution. Seven of these deal with LDAP vulnerabilities, which is at least a decrease from the 10 LDAP patches last month. The most severe of these clocks in with a CVSS of 9.8 but would require the MaxReceiveBuffer LDAP policy to be set to a value higher than the default value. This doesn’t seem to be a common scenario. Still, the volume of bugs in LDAP over the last couple of months could indicate a broad attack surface in the component. Speaking of fertile attack surfaces, there are another six fixes for code execution bugs in the AV1 and HEVC media codecs. If you are connected to the Internet, you should automatically get updates from the Windows Store. However, if you are using these optional components in a disconnected environment, you’ll need to get these through either the Microsoft Store for Business or the Microsoft Store for Education. The same holds true for the patch addressing the RCE in the Photos App.
There are three RCE bugs receiving fixes in the Azure RTOS GUIX Studio, which provides developers a design for developing GUIs for IoT applications. What’s not clear is whether these apps will also need updates after installing these patches. There are a few RCE bugs in Office components, including a couple of interesting SharePoint bugs. Most of these require a user to open a specially crafted file. The SQL Server bug sounds pretty nasty but requires authentication. That should lessen the impact. Still, admins will need to carefully review the listed chart to determine which GDR and CU updates they require. This release includes patches impacting the iSCSI Discovery Service, Encrypting File System (EFS), and the File History component. All require some form of authentication, and the iSCSI and File History bugs require user interaction.
Moving on, there are 12 patches to address elevation of privilege (EoP) vulnerabilities. Most of these require an attacker to log on to a system and run specially crated code. There are, however, a couple of patches that stand out. The update for Azure Open Management Infrastructure (OMI) impacts multiple different Azure and SCOM components. Admins will need to touch most of these to ensure the bug is fully addressed, which will add to their workload. The patch for Azure Service Fabric doesn’t fix any bugs. Instead, it enforces the path to least privilege on Linux clusters. The bug in Kerberos affects servers with both Credential Security Service Provider (CredSSP) and Remote Credential Guard (RCG) installed. An attacker could elevate privileges and then spoof the Kerberos logon process when an RCG connection is made via CredSSP. Finally, the patch for the File Server Shadow Copy Agent Service (RVSS) only affects systems where the File Server VSS Agent Service is installed. However, on those systems, the patch alone isn’t enough. Admins must install the updates on Application and File Servers. Failure to do so could negatively impact backups and cause them to fail. See this KB article for more details.
The June release contains fixes for three Denial-of-Service (DoS) bugs. The DoS in the kernel could crash the OS, but it’s not clear how severe the bug in NAT could be. If it shut down NAT completely, it could devastate impacted enterprises. If you use NAT, treat this as a Critical update. Rapid7 also contributed a CVE in a Windows SMB that Microsoft had initially classified as a stability bug. This was silently fixed in the May 2022 updates and is being documented publicly here.
There’s a single security feature bypass being fixed this month in Kerberos AppContainer. If exploited, an attacker could bypass the Kerberos service ticketing feature that performs user access control checks. There’s also a single spoofing bug in this release for the Windows Autopilot Device Management component. There are a mountain of caveats to this bug, so if you’re using this management tool, read the bulletin carefully to determine if your systems are affected.
The release is rounded out by 11 information disclosure bugs. As previously mentioned, most of these only result in leaks consisting of unspecified memory contents. There are a couple of exceptions. The Office bug could expose device information such as resource IDs, SAS tokens, and user properties. The bug in .NET and Visual Studio could be used to intercept the API key intended for NuGet.org.
Finally, there are four info disclosure bugs addressing Intel Processor MMIO stale data vulnerabilities. An attacker could use these bugs to read privileged data across trust boundaries. Microsoft has also released Advisory ADV220002 detailing these bugs, and Intel has also released further details about this class of vulnerabilities.
The next Patch Tuesday falls on July 12, and we’ll return with details and patch analysis then. 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 Jason McFadyen of the Trend Micro Research Team detail a recently patched code execution vulnerability in the Microsoft Windows operating system. The bug was originally discovered and reported to Microsoft by Yuki Chen. A stack buffer overflow vulnerability exists in Windows Network File System. A remote attacker can exploit this vulnerability by sending specially crafted RPC packets to a server, resulting in code execution in the context of SYSTEM. The following is a portion of their write-up covering CVE-2022-26937, with a few minimal modifications.
A stack buffer overflow vulnerability exists in Windows Network File System. The vulnerability is due to improper handling of crafted RPC responses to Portmap requests made by the Network Lock Manager (NLM) RPC program.
A remote attacker can exploit this vulnerability by sending malicious RPC calls to a target server. Successful exploitation may result in arbitrary code execution under the context of SYSTEM. Unsuccessful exploitation results in a crash of the target system.
Microsoft Windows ships with several network features designed to communicate and interact with non-Windows files shares. One of these modules is called Network File System (NFS).
NFS is a network file system 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 the share, 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.
The Network Lock Manager (NLM) protocol is an extension of NFS versions 2 and 3, which provides a System V style of advisory file and record locking over the network. Since NFS versions 2 and 3 are stateless protocols, the NLM protocol was developed to manage the state of locks on files stored on NFS shares. The NLM protocol supports both synchronous and asynchronous procedures to implement locking and file-sharing functionality. Similar to NFS, NLM also uses ONC RPC to exchange control messages.
ONC RPC uses XDR packets, which can be transmitted over UDP or TCP. Over UDP, the XDR packet is contained within the UDP payload. Over TCP, XDR packets are preceded by a Fragment header (as illustrated in the following table). The most significant bit of the Fragment header indicates whether the packet is the last fragment, and the remaining 31 bits are the length of the Fragment that follows. The Fragment itself contains the XDR packet.
The structure of an ONC RPC call is as follows:
The Program field of the RPC message specifies what RPC service the message is sent to. Windows NFS server implements the NLM protocol via RPC with Program type set to 100021. It supports multiple RPC procedures, which can be specified in the Procedure field in the RPC message. A list of synchronous and asynchronous procedures supported by the NLM protocol version 3 follows:
Microsoft Windows runs the RPCBIND RPC program, which implements the Port Mapper protocol, documented in RFC 1833. The RPCBIND program converts RPC program numbers into universal addresses, which can then be used by programs to communicate over UDP or TCP. Briefly, the way it works is that when a program wishes to use RPC, it registers its ports with the host's Port Mapper. A client that wishes to issue RPC calls connects to the Port Mapper, uses various RPC calls such as GETPORT, GETADDR etc. to obtain a port on which the RPC service is available, and connects to the desired RPC service. Standard RPC program numbers have been defined and maintained by IANA and they include portmapper (100000), nfs (100003), mount daemon (100005) and hundreds of other less commonly used programs. Only the portmapper service and NFS service have standard ports of 111 and 2049 respectively.
Windows implements the RPCBIND protocol via RPC with Program type set to 100000. It supports multiple RPC procedures, which can be specified in the Procedure field in the RPC message. One of the procedures supported by the RPCBIND program when Program Version is set to 3 or 4, is GETADDR, which is procedure number 3. The reply to this RPC call contains the Universal Address associated with the callee. The format for the returned Universal Address is XDR_String, which has the following format:
A stack buffer overflow vulnerability exists in Windows Network File System. More specifically, the vulnerability is due to incorrect handling of the Universal Address field returned in GETADDR RPC replies. When Windows NFS responds to an NLM call in an asynchronous manner, the NlmGetClientAddressAndConnection() function is called. This flow is triggered either as a response to an asynchronous NLM call, such as NLM_TEST_MSG, NLM_LOCK_MSG, NLM_UNLOCK_MSG, or when the server sends an `NLM_GRANTED` call to the client, after a previous (synchronous or asynchronous) call by the client to create a lock returned the status `LCK_BLOCKED`. If the IPv6 protocol is used for communication over the ONC RPC protocol, the server will issue a GETADDR RPC call to the client to retrieve its IP address. When the Universal Address field returned by the client in the GETADDR reply is processed by the NFS server, the field is copied using memmove() into a buffer of size 96 bytes. In addition, this buffer is later referenced at an index equal to the Universal Address field’s string size and set to 0. However, the NlmGetClientAddressAndConnection() function does not verify the size of the returned Universal Address string. Therefore, if the string provided by the client is 96 bytes or longer, the buffer will be written past its boundary, resulting in the stack buffer overflow condition.
A remote attacker can exploit this vulnerability by sending an NLM request triggering an asynchronous response by the NFS server. When the server sends a GETADDR RPC request, the attacker can respond with a crafted GETADDR reply. Successful exploitation may result in arbitrary code execution under the context of SYSTEM. Unsuccessful exploitation results in a crash of the target system.
Source Code Walkthrough
The following code snippet was taken from nfssvr.sys version 10.0.17763.1999. Comments added by Trend Micro have been highlighted.
In function NlmGetClientAddressAndConnection():
ONC RPC uses XDR packets, which can be transmitted over UDP or TCP. Over UDP, the XDR packet is contained within the UDP payload. Over TCP, XDR packets are preceded by a Fragment header (as illustrated in the following table). The most significant bit of the Fragment header indicates whether the packet is the last fragment, and the remaining 31 bits are the length of the Fragment that follows. The Fragment itself contains the XDR packet.
The detection device must inspect all outgoing ONC RPC calls, which have the following structure:
The detection device must check if the Message Type field is 0 (Call), the Program field is 100000 (portmap), the Program Version field is larger than 2, and the Procedure field is equal to 3 (GETADDR). If found, the device must inspect the Program-specific data object. This object uses the rpcb structure, which has the following format:
If the Program Number field is set to 100021 (NLM), the detection device must inspect all incoming ONC RPC replies, which have the following structure:
The detection device must check if the XID field is equal to the XID field of the GETADDR RPC call detected, and the Message Type field is 1 (Reply). If found, the device must inspect the Program-specific data object. This object uses the XDR_String structure, which has the following format:
If the String Length field is larger than 95, the traffic should be considered suspicious; an attack exploiting this vulnerability is likely underway.
This bug was patched by Microsoft in May 2022 and assigned CVE-2022-26937. In their write-up, they also list disabling NFSV2 and NFSV3 as a method to mitigate attacks. However, this could lead to a loss of functionality. Applying the security update is the best method to fully address this vulnerability.
Special thanks to Guy Lederfein and Jason McFadyen 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 ZDI team for the latest in exploit techniques and security patches.
CVE-2022-26937: Microsoft Windows Network File System NLM Portmap Stack Buffer Overflow
A lot of blog posts I have read go over interesting vulnerabilities and exploits but do not typically share the process behind discovery. I want to show how sometimes just manually poking around can quickly uncover vulnerabilities you might miss with other approaches to vulnerability discovery.
In my previous blog, I highlighted a tool named IO Ninja and shared why it is helpful when working with Inter-Process Communications (IPC). In this blog, I would like to show you how this tool helped me find two vulnerabilities: CVE-2021-4198 and CVE-2021-4199 in Bitdefender’s antivirus software on Windows. The exploit I wrote targets a named pipe used by the Vulnerability.scan.exe process. The first vulnerability results in a denial-of-service on almost any process within the AV. The second results in local privilege escalation by exploiting a link following issue.
Now you might be thinking, wait a minute... how does a tool that lets you communicate with named pipes allow you to find a link following vulnerability? That is what we are going to dive into next.
The pipelist tool from Sysinternals reveals that Bitdefender uses several pipes for IPC.
bdservicehost.exe is one of the executables that runs as SYSTEM after installing Bitdefender. It uses these pipes to communicate with other processes on the system and might be an interesting target.
Using IO Ninja, we can spawn a pipe server as our standard user to see if we can trigger a connection from the client. Without reading any code, we can poke around the agent GUI to see what IPC connections are being created and what the traffic looks like.
The screenshot below shows that we receive a connection from the client of the pipe that sends data to our named pipe server every time we open the agent GUI. This can be done by double clicking the Bitdefender icon in the system tray or opening it from the start menu.
What is interesting here is that the connection remains open. This allows us to send data back to the client. I took the first 16 bytes of data that was being sent to the server and echoed it back to the client multiple times to see if anything interesting would happen. I was also looking to see if the pipe connection would remain open after sending the data.
After sending several messages, the client disconnects, and we get a popup box from Bitdefender informing the user that something went wrong within the AV. Take note of the “x” at the top right for dismissing the dialog box. This will become relevant later.
After seeing this message, I knew that debugging information in some shape or form must be getting saved or logged. I fired up Process Monitor from Sysinternals to see if a crash dump file, which I can further analyze in a debugger, was created.
As it turns out, an executable named “BDReinit.exe”, which is Bitdefender’s own crash handler, produces a crash dump file for us on the system.
Another interesting discovery here was finding out that the folder to which the .dmp file is being written to is readable and writeable by standard users.
Unfortunately, after looking at the dump file, I concluded the crash alone was not very interesting, and the process being crashed runs as our current user. At this point, I knew I had a potential local DoS on the AV but there had to be more to chew on here.
After crashing this first process “seccenter.exe,” which is Bitdefender’s main GUI interface, I realized that I was still getting connections to my named pipe server. I was able to crash almost any process related to the AV by simply spamming the incoming pipe connections with those 16 bytes as soon as a client connected. I sat in front of my computer, watching the AV processes fall like dominos one after the other in process explorer.
I knew that kicking off a “Vulnerability Scan” in the GUI would spawn vulnerability.scan.exe, which ran as SYSTEM. I quickly tried to see if I could also crash this privileged process.
Ahh, the same “BDReinit.exe” process runs again, but this time it runs as SYSTEM. Based on the file name of the dump, we know we can also crash “Vulnerability.scan.exe,” and it writes the dump to disk as SYSTEM.
When looking for link following vulnerabilities, there are a few directories that are of immediate interest.
I often look for privileged file writes and delete operations in these directories.
In this case, a .dmp file is being written to this directory as SYSTEM when a highly privileged process that is part of the AV crashes. This alone is not very interesting as we do not control the contents of the dump being written, and it’s the same exact crash from before.
I further analyzed the Process Monitor log and discovered that “BDReinit.exe” was doing two very dangerous things. First, it was writing a very permissive DACL to a file with a predictable name in a different directory. This directory also allowed a standard user read and write access, and the DACL write happened every time a crash occurred.
The permissive DACL would get written to this file as SYSTEM if you crashed a process running as SYSTEM within Bitdefender. In this case, I just chose to again crash “Vulnerability.scan.exe” because of how easy it was to trigger. All I had to do was kick off a vulnerability scan in the GUI, and I would get a connection to my named pipe server from this process.
One of my favorite parts about logic bugs like this is that exploiting them is typically very quick and easy. All we need to do to escalate to SYSTEM is redirect the permissive DACL write to a DLL used by the system, modify the contents of that DLL, and then have it get loaded. To do this redirection we just need one symbolic link and a target DLL.
This is because a standard user can easily trigger a print job which will force svchost.exe to load our modified DLL as SYSTEM.
Putting this altoghther, the following screenshot demonstrates executing code at SYSTEM using the techniques described.
The second major issue I found was related to the crash dump itself. If you clicked the “x” at the top right of the popup box I showed earlier, “BDReinit.exe” or “BdSubWiz.exe” which is the submission wizard, would delete the crash dump as your current user. If the user waited or ignored it for a while, the dialog box would timeout and delete the dump file as SYSTEM if the process that crashed was running as SYSTEM!
In the above screenshot, you can see how we can redirect this highly privileged file deletion to any file on the system. You can also use the techniques described in this blog to achieve privilege escalation and execute code at SYSTEM. Again, this is because the crash dump was being written and deleted from a location that our standard user had read and write access to regardless of the user that was running the crashed process. Furthermore, the files in that folder were not protected at all, so deleting them and replacing one with our link before the timeout was not an issue.
Sometimes vulnerability discovery isn’t super methodical and that’s okay! I did not spend any time reversing the functions responsible for IPC in this application to figure out what data to send over the pipe. However, I identified an attack surface and started poking around. This led me to an entirely different attack surface where there were some critical vulnerabilities.
I hope this blog inspires and enables you to do the same with your targets. Furthermore, I hope it reminds you to look at custom crash handlers and their dialog boxes – both for bugs and to make sure you aren’t unintentionally giving away your research. 😀
Below is a Procmon filter I use that you can download and import to search for link-following vulnerabilities. Just be sure to either change your username to “lowpriv,” or edit the filter before you use it. You can download it here.
Keep an eye out for future blogs where I will share details on other vulnerabilities I have found. Until then, you can follow me @izobashi and the team @thezdi on Twitter for the latest in exploit techniques and security patches.
Pwn2Own Vancouver for 2022 is underway, and the 15th anniversary of the contest has already seen some amazing research demonstrated. Stay tuned to this blog for updated results, picture, and videos from the event. We’ll be posting it all here - including the most recent Master of Pwn leaderboard.
Here are the current standings for the Master of Pwn:
Day One - May 18, 2022
SUCCESS - Hector “p3rr0” Peralta was able to demonstrate an improper configuration against Microsoft Teams. He earns $150,000 and 15 Master of Pwn points.
SUCCESS - Billy Jheng Bing-Jhong (@st424204), Muhammad Alifa Ramdhan (@n0psledbyte), and Nguyễn Hoàng Thạch (@hi_im_d4rkn3ss) of STAR Labs successfully used an OOB Read and OOB Write to achieve escalation on Oracle Virtualbox. They earn $40,000 and 4 Master of Pwn points.
SUCCESS - Masato Kinugawa was able to execute a 3-bug chain of injection, misconfiguraton and sandbox escape against Microsoft Teams, earning $150,000 and 15 Master of Pwn points.
SUCCESS - Manfred Paul (@_manfp) successfully demonstrated 2 bugs - prototype pollution and improper input validation - on Mozilla Firefox, earning him $100,000 and 10 Master of Pwn points.
SUCCESS - Marcin Wiązowski was able to execute an out-of-bounds write escalation of privilege on Microsoft Windows 11, earning $40,000 and 4 Master of Pwn points, and high praise on the accompanying whitepaper from the Microsoft team.
SUCCESS - Team Orca of Sea Security (security.sea.com) was able to execute 2 bugs on Ubuntu Desktop - an Out-of-Bounds Write (OOBW) and Use-After-Free (UAF) - earning $40,000 and 4 Master of Pwn points.
SUCCESS - Daniel Lim Wee Soong (@daniellimws), Poh Jia Hao (@Chocologicall), Li Jiantao (@CurseRed) & Ngo Wei Lin (@Creastery) of STAR Labs successfully demonstrated their zero-click exploit of 2 bugs (injection and arbitrary file write) on Microsoft Teams. They earn $150,000 and 15 Master of Pwn points.
SUCCESS - Manfred Paul (@_manfp) successfully scored his second win of the day with an out-of-band write on Apple Safari, earning him another $50,000 and 5 additional Master of Pwn points.
SUCCESS - Phan Thanh Duy (@PTDuy and Lê Hữu Quang Linh (@linhlhq of STAR Labs earned $40K and 4 Master of Pwn points for a Use-After-Free elevation of privilege on Microsoft Windows 11.
SUCCESS - Keith Yeo (@kyeojy) earned $40K and 4 Master of Pwn points for a Use-After-Free exploit on Ubuntu Desktop.
Day Two - May 19, 2022
SUCCESS and BUG COLLISION - On the first attempt of the day, David BERARD and Vincent DEHORS from @Synacktiv were able to demonstrate 2 unique bugs (Double-Free & OOBW) with collision on a known sandbox escape on a Tesla Model 3 Infotainment System. They earn $75,000 and 7.5 Master of Pwn points, and although they don't win the car outright, they have made enough to go pick one up themselves!
FAILURE - On the second attempt of day 2, namnp was unable to get their exploit of Microsoft Windows 11 working within the time allotted.
SUCCESS - Bien Pham (@bienpnn) was able to execute a Use After Free bug leading to elevation of privilege on Unbuntu Desktop, earning $40,000 and 4 Master of Pwn points.
FAILURE - @Jedar_LZ was unable to get today's second Tesla attempt working within the time allotted. On a positive note, @thedzi decided to acquire the details of the exploit and disclose them to Tesla.
SUCCESS - T0 was able to successfully show an improper access control bug leading to elevation of privilege on Microsoft Windows 11 - earning $40,000 and 4 Master of Pwn points.
SUCCESS - On the final attempt of Day 2, Zhenpeng Lin (@Markak_), Yueqi Chen (@Lewis_Chen_), and Xinyu Xing (@xingxinyu) of Team TUTELARY from Northwestern University successfully demonstrated a Use After Free bug leading to elevation of privilege on Ubuntu Desktop. This earns him $40,000 and 4 Master of Pwn points.
Day Three - May 20, 2022
FAILURE - On the first attempt of day 3, Team DoubleDragon: Yonghwi Jin (@jinmo123) of Theori, and Yongjin Kim (@adm1nkyj1) of Enki was unable to get their exploit of Microsoft Teams working within the time allotted. All is not lost though, in that Team Double Dragon was able to get their research into the regular ZDI process.
SUCCESS - nghiadt12 from Viettel Cyber Security was able to successfully show an escalation of privilege via Integer Overflow on Microsoft Windows 11 - earning $40,000 and 4 Master of Pwn points.
SUCCESS - Billy Jheng Bing-Jhong (@st424204) STAR Labs was able to successfully demonstrate a Use-After-Free exploit on Ubuntu Desktop - earning another $40,000 and 4 Master of Pwn points.
SUCCESS - vinhthp1712 successfully achieved Elevation of Privilege via Improper Access Control on Microsoft Windows 11. vinhthp1712 earns $40,000 and 4 Master of Pwn points.
SUCCESS - On the final attempt of the competition, Bruno PUJOS (@brunopujos) from REverse Tactics successfully achieved Elevation of Privilege via Use-After-Free on Microsoft Windows 11. Bruno earns $40,000 and 4 Master of Pwn points.
That concludes the regular scheduled programming for our event! This year, we had a total of 21 attempts from 17 contestants with Trend Micro and ZDI awarding $1,155,000! We can’t wait to share more details in the near future about our fall event, so stay tuned!
As always, follow us on Twitter for the latest results, update, and breaking news.
Thanks again to our partners Tesla, Zoom, and Microsoft as well as our sponsor VMware. Thanks also to the researchers who participate and to the vendors for providing fixes for what was discovered and reported during the contest. As a reminder, vendors have 90 days to produce a fix for all vulnerabilities disclosed.
Welcome to Pwn2Own Vancouver 2022! This year marks the 15th anniversary of the contest, and we plan on celebrating by putting some amazing research on display. For this year’s event, we have 17 contestants attempting to exploit 21 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.
The complete schedule for the contest is below (all times Pacific [GMT -7:00]).
Note: All times subject to change - You can see the results and live updates here once they become available. Entries marked with a 📷 icon will be live-streamed on YouTube, Twitch, and Twitter.
Wednesday, May 18, 2022
0930: Hector “p3rr0” Peralta targeting Microsoft Teams in the Enterprise Communications category
📷 1030: Billy Jheng Bing-Jhong (@st424204), Muhammad Alifa Ramdhan (@n0psledbyte), and Nguyễn Hoàng Thạch (@hi_im_d4rkn3ss) of STAR Labs targeting Oracle VirtualBox with a guest-to-host escape in the Virtualization category
📷 1200: Masato Kinugawa targeting Microsoft Teams in the Enterprise Communications category
📷 1300: Manfred Paul (@_manfp) targeting Mozilla Firefox (including sandbox escape) in the Web Browser category
1330: Marcin Wiązowski targeting Microsoft Windows 11 in the Local Elevation of Privilege category
1400: Team Orca of Sea Security (security.sea.com) targeting Ubuntu Desktop in the Local Elevation of Privilege category
It’s the fifth second Tuesday of 2022, which also means it’s the also the fifth Patch Tuesday of the year, and it brings with it the latest security updates from Adobe and Microsoft. This is also the last release before Pwn2Own Vancouver, which means multiple participants will be holding their breath to see if their exploits still work or were patched out. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for May 2022
For May, Adobe released five bulletins addressing 18 CVEs in Adobe CloudFusion, InCopy, Framemaker, InDesign, and Adobe Character Animator. A total of 17 of these CVEs were reported by ZDI vulnerability researcher Mat Powell. The largest of these patches is the fix for Framemaker with 10 CVEs in total. Nine of these are Critical-rated bugs that could lead to code execution, mostly due to Out-of-Bounds (OOB) Write vulnerabilities. The patch for InDesign addresses three Critical-rated bugs that could lead to code execution. Two of these are due to OOB Writes while one is an OOB Read. The patch for InCopy also fixes three Critical-rated code execution bugs. In this case, it’s two OOB Writes plus a Use-After-Free (UAF). The patch for Character Animator fixes a single, Critical-rated OOB Write code execution bug. Finally, the ColdFusion patch corrects an Important-rated reflected cross-site scripting (XSS) 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 all of these updates as priority 3.
Microsoft Patches for May 2022
For May, Microsoft released 74 new patches addressing CVEs in Microsoft Windows and Windows Components, .NET and Visual Studio, Microsoft Edge (Chromium-based), Microsoft Exchange Server, Office and Office Components, Windows Hyper-V, Windows Authentication Methods, BitLocker, Windows Cluster Shared Volume (CSV), Remote Desktop Client, Windows Network File System, NTFS, and Windows Point-to-Point Tunneling Protocol. This is in addition to the 36 CVEs patched by Microsoft Edge (Chromium-based) in late April.
Of the 74 CVEs released today, seven are rated Critical, 66 are rated Important, and one is rated Low in severity. A total of seven of these bugs came through the ZDI program. Historically speaking, this volume is in line with May releases in the past, with 19 more than May 2021, but 5 less than May 2019. The entire 2020 release volume was somewhat of an anomaly, so comparisons there aren’t as useful.
One of the bugs released today is listed as publicly known and under active attack, while two others are listed as publicly known at the time of release. Let’s take a closer look at some of the more interesting updates for this month, starting with the vulnerability currently being exploited:
- CVE-2022-26925 – Windows LSA Spoofing Vulnerability This complex-sounding vulnerability could allow an unauthenticated attacker to force a domain controller to authenticate against another server using NTLM. The threat actor would need to be in the logical network path between the target and the resource requested (e.g., Man-in-the-Middle), but since this is listed as under active attack, someone must have figured out how to make that happen. Microsoft notes this would be a CVSS 9.8 if combined with NTLM relay attacks, making this even more severe. In addition to this patch, sysadmins should review KB5005413 and Advisory ADV210003 to see what additional measures can be taken to prevent NTLM relay attacks. Also note this patch affects some backup functionality on Server 2008 SP2. If you’re running that OS, read this one carefully to ensure your backups can still be used to restore.
- CVE-2022-26923 – Active Directory Domain Services Elevation of Privilege Vulnerability This bug was submitted through the ZDI program by Oliver Lyak (@ly4k_) of the Institut for Cyber Risk. The specific flaw exists within the issuance of certificates. By including crafted data in a certificate request, an attacker can obtain a certificate that allows the attacker to authenticate to a domain controller with a high level of privilege. In essence, any domain authenticated user can become a domain admin if Active Directory Certificate Services are running on the domain. This is a very common deployment. Considering the severity of this bug and the relative ease of exploit, it would not surprise me to see active attacks using this technique sooner rather than later.
- CVE-2022-26937 – Windows Network File System Remote Code Execution Vulnerability This CVSS 9.8-rated bug could allow remote, unauthenticated attackers to execute code in the context of the Network File System (NFS) service on affected systems. NFS isn’t on by default, but it’s prevalent in environments where Windows systems are mixed with other OSes such as Linux or Unix. If this describes your environment, you should definitely test and deploy this patch quickly. Microsoft notes NFSv4.1 is not exploitable, so upgrade from NFSv2 or NFSv3 if possible.
- CVE-2022-29972 – Insight Software: Magnitude Simba Amazon Redshift ODBC Driver This update was actually released yesterday and is complicated enough for Microsoft to blog about the bug and how it affects multiple Microsoft services. Microsoft also released its first advisory of the year, ADV220001, with additional information about the vulnerability. The flaw exists in the third-party ODBC data connector used to connect to Amazon Redshift, in Integration Runtime (IR) in Azure Synapse Pipelines, and Azure Data Factory, and could allow an attacker to execute remote commands across Integration Runtimes. If you use these services, review the blog and advisory to ensure you understand the risks to your services.
Here’s the full list of CVEs released by Microsoft for May 2022:
Looking at the remaining Critical-rated patches, there are two that affect the Windows implementation of Point-to-Point Tunneling Protocol (PPTP) that could allow an RCE. Microsoft notes an attacker would need to win a race condition to successfully exploit these bugs, but not every race condition is identical. In other words, an attacker may pull a Rich Strike and win that race. There’s a Critical-rated Elevation of Privilege (EoP) bug in Microsoft Kerberos, but no further information is provided. It’s unusual for an EoP to be rated Critical, so the privilege escalation must result in something beyond just a domain account. Finally, there’s another patch for the RDP Client, which seem to be coming at least once a month these days. An attacker would need to convince an affected system to connect to a specially crafted RDP server to gain code execution.
There are 20 other patches for RCE bugs in this month’s release, and half of those deal with LDAP vulnerabilities. The most severe of these clocks in with a CVSS of 9.8 but would require the MaxReceiveBuffer LDAP policy to be set to a value higher than the default value. It’s not clear if that is a common or rare configuration. The others would require some form of authentication. Three of the remaining RCEs came through the ZDI program. ZDI vulnerability researcher Hossein Lotfi discovered a bug in Windows Media Foundation that exists within the parsing of AVI files. The research known as ZhangYang found a heap overflow bug in Visual Studio, and Uncodable reported a use-after-free (UAF) bug in the Windows Graphic component. The remaining RCE bugs require some form of user interaction – mostly clicking on a link or opening a file. The only exception to this is the bugs in SharePoint, which requires an authenticated user with page creation permissions. By default, any authenticated user can create their own site where they have the necessary permissions.
Moving on to EoP-related patches, there are 21 total privilege escalation bugs in the release, including the two previously mentioned. Most of these require an attacker to log on a run their specially crafted code or somehow convince (or trick) an authorized user to do so. However, there are a couple of patches that stand out. The most obvious is the patch for Exchange Server, which requires an admin to specifically prepare Active Directory before installing the patch. This entails running specific commands from the command prompt once the patch has been downloaded. Microsoft doesn’t indicate what could happen if these steps are not followed, but the bug allows an Exchange admin to become a Domain Admin, so ensure you take the appropriate steps to fully remediate this vulnerability. There’s a privilege escalation in the Remote Access Connection Manager, but without further details from Microsoft, it’s not clear how this vulnerability manifests. Finally, there are two EoP fixes for the Print Spooler, with one coming from Oliver Lyak through ZDI. The bug he reported could allow an attacker to create a symbolic link, which could then cause the service to load an arbitrary DLL.
Speaking of the Print Spooler, two of the 17 info disclosure bugs patched by this month’s release impact this component, and both were reported by Oliver through ZDI. These bugs result from the lack of proper validation of a user-supplied path prior to using it in file operations. An attacker can leverage these vulnerabilities to disclose information in the context of SYSTEM. Most of the other Info Disclosure bugs in this release only result in leaks consisting of unspecified memory contents. The other exception to this would be the bug in the Windows Server Service (aka LanManServer). Microsoft states that an attacker could confirm the presence of specific file names and users over an internal network, but they don’t state how this would occur.
There are four fixes for Security Feature Bypass (SFB) bugs in this release, and each one deserves a mention. The first relates to a Virtual Machine Switch with virtual networking in Hyper-V Network Virtualization (HNV). An attacker could bypass extended ACLs and other checks, which implies one guest OS could impact a different guest OS on the same server. Up next is a bug in Office that could allow an attacker to gain personally identifiable information (PII) by bypassing the “ThisDocument.RemovePersonalInformation” functionality. If you’re sharing files online but want your personal information removed, be sure to apply this update. The update for Windows Authentication addresses a vulnerability that could allow Man-in-the-Middle (MITM) attackers to decrypt and read or modify TLS traffic between the client and server. Finally, there is a bypass of BitLocker Device Encryption that requires physical access but could allow an attacker to gain access to encrypted data in certain scenarios. These final two bugs may be a bit unlikely to be seen in the wild, but if they are, the impact would be quite severe. Bugs like these are the ones sought by advanced threat actors for use on high-profile targets.
The May release is rounded out by six updates to address Denial-of-Service bugs in Hyper-V, the WLAN Autoconfig Service, and .NET and Visual Studio. The WLAN vulnerability is limited to a logically adjacent topology and can’t be reached from the internet. The bug in Hyper-V is listed as public, but Microsoft provides no information on where it was posted or how much detail was exposed. There are multiple DoS bugs listed for .NET and Visual Studio, but no further details are provided. One of these .NET bugs is the lone Low-severity bug in this release.
There is one new advisory for May covering improvements to Azure Data Factory and Azure Synapse Pipeline. This was previously mentioned (above) and is in response to CVE-2022-29972. While certainly not new, the latest servicing stack updates can be found in the revised ADV990001.
The next Patch Tuesday falls on June 14, and we’ll return with details and patch analysis then. Until then, stay safe, happy patching, and may all your reboots be smooth and clean! (And hope to see you in Vancouver!)
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
Pwn2Own Miami for 2022 has wrapped up, and it was an amazing three days of competition. In total, we awarded $400,000 for 26 unique 0-days (plus a few bug collisions). With 90 points accumulated over three days, the team of Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) have won Master of Pwn! You can see all of the points and full results from all entries below.
Thanks again to all of the competitors who participated. We couldn’t have a contest without them. Thanks also to the participating vendors for their cooperation and for providing fixes for the bugs disclosed throughout the contest. As a reminder, vendors have 120 days to produce a fix for all vulnerabilities reported.
SUCCESS - 20urdjk was able to execute their DoS attack against Unified Automation C++ Demo Server. They earn $5,000 and 5 Master of Pwn points.
SUCCESS - Sam Thomas (@_s_n_t) from @pentestltd combined an auth bypass and a deserialization bug to get code execution. They win $20,000 and 20 points towards Master of Pwn.
SUCCESS - Or Peles, Omer Kaspi and Uriya Yavnieli from JFrog Security Research leveraged a Use-After-Free (UAF) bug to create a DoS on the Unified Automation C++ Demo Server. They win $5,000 and 5 Master of Pwn points.
SUCCESS - After a slight logistical delay, Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) used a deserialization bug to get their code executing on #Iconics Genesis64. They earn $20,000 and 20 Master of Pwn points.
SUCCESS - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) used a missing authentication for critical function vuln to execute code on Inductive Automation Ignition. They win $20,000 and 20 Master of Pwn points.
SUCCESS - Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) used an Uncontrolled Search Path bug in AVEVA Edge to execute their code. In doing so, they win $20,000 and 20 points towards Master of Pwn.
SUCCESS - The Claroty Research (@claroty) team of Noam Moshe, Vera Mens, Amir Preminger, Uri Katz, and Sharon Brizinov used a resource exhaustion bug to execute their DoS on the Prosys OPC UA SDK for Java. This wins them $5,000 and 5 Master of Pwn points.
SUCCESS - Axel '0vercl0k' Souchet of https://doar-e.github.io used a double free bug to execute his code on Iconics Genesis64. He wins $20,000 and 20 Master of Pwn points. You can watch a replay of this attempt here.
SUCCESS - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) used an uncontrolled search path vulnerability to get RCE in AVEVA Edge. They win $20,000 and 20 Master of Pwn points.
SUCCESS - 20urdjk used a file upload vulnerability on Inductive Automation Ignition to get RCE. He wins $20,000 and 20 more points towards Master of Pwn. His contest total is now $25,000 and 25 points.
SUCCESS - The Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) used a pair of bugs, including a directory traversal, to get code execution on Triangle Microworks SCADA Data Gateway. The win another $20,000 and 20 more Master of Pwn points.
BUG COLLISION - While the Claroty Research (@claroty) team of Noam Moshe, Vera Mens, Amir Preminger, Uri Katz, and Sharon Brizinov successfully demonstrated RCE against Iconics Genesis64, the bug used was one we already knew about. They still win $5,000 and 5 Master of Pwn points.
BUG COLLISION - The Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) were able to get code execution on Inductive Automation Ignition, but the bug they used was previously known. They still win $5,000 and 5 Master of Pwn points.
BUG COLLISION - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) successfully popped calc, but the bug they used had been disclosed earlier in the competition. They still win $5,000 and 5 Master of Pwn points.
SUCCESS - The Claroty Research (@claroty) team of Noam Moshe, Vera Mens, Amir Preminger, Uri Katz, and Sharon Brizinov used a resource exhaustion bug to perform a DoS on the OPC Foundation OPC UA .NET Standard. They earn $5,000 and 5 Master of Pwn points.
SUCCESS - Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) end Day One of Pwn2Own Miami 2022 by using a deserialization bug to execute code on AVEVA Edge. They win another $20,000 and 20 more Master of Pwn points. Their Day One total is $60,000 and 60 points.
Day Two - April 20, 2022
SUCCESS - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) used an infinite loop condition to create a DoS against the Unified Automation C++ Demo Server. They earn $5,000 and 5 points towards Master of Pwn.
SUCCESS - Piotr Bazydło (@chudyPB) used a deserialization bug to exploit Inductive Automation Ignition and execute his code on the system. He earns $20,000 and 20 Master of Pwn points.
SUCCESS - Ben McBride (@bdmcbri) used an exposed dangerous function bug to get RCE on Iconics Genesis64. He earns himself $20,000 and 20 Master of Pwn points.
SUCCESS - Or Peles, Omer Kaspi and Uriya Yavnieli from JFrog Security Research used a stack exhaustion bug to perform a DoS on the OPC Foundation OPC UA .NET Standard. They earn another $5,000 and 5 more Master of Pwn points.
BUG COLLISION - The Claroty Research (@claroty) team of Noam Moshe, Vera Mens, Amir Preminger, Uri Katz, and Sharon Brizinov did achieve RCE against AVEVA Edge, however the bug they used had been seen previously in the contest. They still earn $5,000 and 5 more Master of Pwn points.
FAILURE - Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) were unable to get their exploit of Inductive Automation Ignition working within the time allotted.
BUG COLLISION - Piotr Bazydło (@chudyPB) was able to get RCE on Iconics Genesis64, however the bug he used had been previously seen. He still earns $5,000 and 5 Master of Pwn points.
SUCCESS - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) used one of the more interesting bugs we've ever seen at a Pwn2Own to bypass the trusted application check on the OPC Foundation OPC UA .NET Standard. The earn $40,000 and 40 Master of Pwn points. Their contest total is now at $90,000 with a commanding lead in Master of Pwn.
BUG COLLISION - While Christopher Hernandez (@piffd0s) was able to show his RCE on AVEVA Edge, the bug he used was previous disclosed. He still earns $5,000 and 5 Master of Pwn points.
FAILURE - The Claroty Research (@claroty) team of Noam Moshe, Vera Mens, Amir Preminger, Uri Katz, and Sharon Brizinov were unable to get their DoS exploit of the Unified Automation C++ Demo Server working within the time allotted.
BUG COLLISION - The Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) did demonstrate their RCE on Iconics Genesis64, the bug used had been previously disclosed. They still win $5,000 and 5 Master of Pwn points.
SUCCESS - Piotr Bazydło (@chudyPB) used an untrusted search path bug to get code execution on AVEVA Edge. He wins another $20,000 and 20 Master of Pwn points. That brings his contest total to $45,000.
SUCCESS - The Claroty Research (@claroty) team of Noam Moshe, Vera Mens, Amir Preminger, Uri Katz, and Sharon Brizinov needed a little time, but they did get their amazing buffer overrun chain to achieve code execution against Kepware KEPServerEx. They earned $20,000 and 20 Master of Pwn points.
Day Three - April 21, 2022
SUCCESS - The Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) used a pair of bugs, including a directory traversal, to exploit the Softing Secure Integration server and run their code. They earn $20K and 20 Master of Pwn points. That brings their conference total to $80,000.
SUCCESS/BUG COLLISION - The Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) combined 3 bugs to get RCE on the Softing Secure Integration Server, but two were previously known. Their exploit chain earned them $10,000 and 10 Master of Pwn points. They end the contest with $40,000 total.
SUCCESS - The Claroty Research (@claroty) team of Noam Moshe, Vera Mens, Amir Preminger, Uri Katz, and Sharon Brizinov used a null pointer deref to perform their DoS on the Softing Secure Integration Server. They earn $5,000 and 5 Master of Pwn points, which brings their contest total to $45,000.
Welcome to Pwn2Own Miami 2022! This year’s ICS-focused event promises to be three days of great research and exploits, as we have 32 total entries from 11 contestants. 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.
The complete schedule for the contest is below (all times Eastern [GMT -4:00]).
Note: All times subject to change - You can see the results and live updates here once they become available. Entries marked with a 📷 icon will be live streamed on YouTube, Twitch, and Twitter.
Tuesday, April 19
09:30 - 20urdjk targeting Unified Automation C++ Demo Server with a DoS in the OPC UA Server category
10:30 - @_s_n_t from @pentestltd targeting Inductive Automation Ignition with an RCE in the Control Server category
📷 11:30 - Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) targeting Iconics Genesis64 with an RCE in the Control Server category
11:30: Or Peles, Omer Kaspi and Uriya Yavnieli from JFrog Security Research targeting the Unified Automation C++ Demo Server with a DoS in the OPC UA Server category
13:00 - Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) targeting AVEVA Edge with an RCE in the Human Machine Interface category
13:00 - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) targeting Inductive Automation Ignition with an RCE in the Control Server category
📷 14:00 - Axel '0vercl0k' Souchet of https://doar-e.github.io targeting Iconics Genesis64 with an RCE in the Control Server category
14:00 - Claroty Research targeting the Prosys OPC UA SDK for Java with a DoS in the OPC UA Server category
15:00 - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) targeting AVEVA Edge with an RCE in the Human Machine Interface category
15:00 - 20urdjk targeting Inductive Automation Ignition with an RCE in the Control Server category
16:00 - Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) targeting Triangle Microworks SCADA Data Gateway with an RCE in the Data Gateway category
16:00 - Claroty Research (@claroty) targeting Iconics Genesis64 with an RCE in the Control Server category
📷 17:00 - Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) targeting Inductive Automation Ignition with an RCE in the Control Server category
18:00 - Claroty Research (@claroty) targeting the OPC Foundation OPC UA .NET Standard with a DoS in the OPC UA Server category
18:00 - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) targeting Iconics Genesis64 with an RCE in the Control Server category
19:00 - Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) targeting AVEVA Edge with an RCE in the Human Machine Interface category
Wednesday, April 20
09:30 - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) targeting the Unified Automation C++ Demo Server with a DoS in the OPC UA Server category
10:30 - Piotr Bazydło (@chudyPB) targeting Inductive Automation Ignition with an RCE in the Control Server category
11:30 - Or Peles, Omer Kaspi and Uriya Yavnieli from JFrog Security Research targeting the OPC Foundation OPC UA .NET Standard with an DoS in the OPC UA Server category
11:30 - Ben McBride (@bdmcbri) targeting Iconics Genesis64 with an RCE in the Control Server category
12:30 - Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) targeting Inductive Automation Ignition with an RCE in the Control Server category
12:30 - Claroty Research (@claroty) targeting AVEVA Edge with an RCE in the Human Machine Interface category
📷 13:30 - Daan Keuper (@daankeuper) and Thijs Alkemade (@xnyhps) from Computest Sector 7 (@sector7_nl) targeting the OPC Foundation OPC UA .NET Standard with a Bypass of the Trusted Application Check in the OPC UA Server category
13:30 - Piotr Bazydło (@chudypb) targeting Iconics Genesis64 with an RCE in the Control Server category
14:30 - Christopher Hernandez targeting AVEVA Edge with an RCE in the Human Machine Interface category
15:30 - Claroty Research (@claroty) targeting Unified Automation C++ Demo Server with a DoS in the OPC UA Server category
15:30 - Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) targeting Iconics Genesis64 with an RCE in the Control Server category
16:30 - Piotr Bazydło (@chudypb) targeting AVEVA Edge with an RCE in the Human Machine Interface category
📷 17:20 - Claroty Research (@claroty) targeting Kepware KEPServerEx with an RCE in the Data Gateway category
Thursday, April 21
09:30 - Incite Team of Steven Seeley (@steventseeley) and Chris Anastasio (@mufinnnnnnn) targeting Softing Secure Integration Server with an RCE in the OPC UA Server category
10:30 - Flashback Team of Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) targeting Softing Secure Integration Server with an RCE in the OPC UA Server category
11:30 - Claroty Research (@claroty) targeting the Softing Secure Integration Server with a DoS in the OPC UA Server category
We’ll be posting updates on our Twitter page, and look for live video updates on Twitter as well. We wish all contestants good luck, and may all your exploits be unique and effective.
Another Patch Tuesday is upon, 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 April 2022
For April, Adobe released four updates addressing 70 CVEs in Acrobat and Reader, Photoshop, After Effects, and Adobe Commerce. The update for Acrobat and Reader is by far the largest, with 62 CVEs being addressed. A total of 54 of these CVEs were reported through the ZDI program, with ZDI vulnerability analyst Mat Powell responsible for 27 of these. The more severe vulnerabilities being fixed are the Critical-Rated Use-After-Free (UAF) and Out-of-Bounds (OOB) Write bugs. These could allow an attacker to execute code on a target system if they can convince a user to open a specially crafted PDF document. There are 13 CVEs fixed in the patch for Photoshop, and all of these were reported through the ZDI program. All the vulnerabilities addressed by this patch address Critical-rated code execution bugs. Again, an attacker would need to convince a user to open a specially crafted file to gain code execution.
The update for After Effects addresses two Critical-rated CVEs that could allow for code execution. Both bugs are listed as stack-based buffer overflows. Finally, the patch for Adobe Commerce fixes a single, Critical-rated vulnerability. Adobe rates this as a CVSS 9.1, but they also point out authentication would be required to exploit this bug. They also note admin privileges are required, so the high CVSS is somewhat puzzling. Still, if you’re using Commerce, test and deploy this patch as soon as you are able.
None of the bugs fixed by Adobe this month are listed as publicly known or under active attack at the time of release.
Microsoft Patches for April 2022
This month, Microsoft released 128 new patches addressing CVEs in Microsoft Windows and Windows Components, Microsoft Defender and Defender for Endpoint, Microsoft Dynamics, Microsoft Edge (Chromium-based), Exchange Server, Office and Office Components, SharePoint Server, Windows Hyper-V, DNS Server, Skype for Business, .NET and Visual Studio, Windows App Store, and Windows Print Spooler Components. This is in addition to the 17 CVEs consumed from the Chromium Open-Source Software (OSS) by Microsoft Edge (Chromium-based), which brings the April total to 145 CVEs.
Of the 128 new CVEs released today, 10 are rated Critical, 115 are rated Important, and three are rated Moderate in severity. A total of six of these bugs came through the ZDI program. This large volume of patches hasn’t been seen since the fall of 2020. However, this level is similar to what we saw in the first quarter of last year.
One of the bugs patched is listed as under active exploit this month, and one other is listed as publicly known at the time of release. Let’s take a closer look at some of the more interesting updates for this month, starting with a Critical-rated bug that could prove wormable:
- CVE-2022-26809 - RPC Runtime Library Remote Code Execution Vulnerability This bug is rated as a CVSS 9.8, and the exploit index notes exploitation is more likely. The vulnerability could allow a remote attacker to executed code at high privileges on an affected system. Since no user interaction is required, these factors combine to make this wormable, at least between machine where RPC can be reached. However, the static port used here (TCP port 135) is typically blocked at the network perimeter. Still, this bug could be used for lateral movement by an attacker. Definitely test and deploy this one quickly.
- CVE-2022-24491/24497 – Windows Network File System Remote Code Execution Vulnerability Speaking of nearly wormable bugs, these two NFS vulnerabilities also rate a 9.8 CVSS and are listed as exploitation more likely. On systems where the NFS role is enabled, a remote attacker could execute their code on an affected system with high privileges and without user interaction. Again, that adds up to a wormable bug – at least between NFS servers. Similar to RPC, this is often blocked at the network perimeter. However, Microsoft does provide guidance on how the RPC port multiplexer (port 2049) “is firewall-friendly and simplifies deployment of NFS.” Check your installations and roll out these patches rapidly.
- CVE-2022-26815 - Windows DNS Server Remote Code Execution Vulnerability This vulnerability is the most severe of the 18(!) DNS Server bugs receiving patches this month. This bug is also very similar to one patched back in February, which makes one wonder if this bug is the result of a failed patch. There are a couple of important mitigations to point out here. The first is that dynamic updates must be enabled for a server to be affected by this bug. The CVSS also lists some level of privileges to exploit. Still, any chance of an attacker getting RCE on a DNS server is one too many, so get your DNS servers patched.
- CVE-2022-26904 - Windows User Profile Service Elevation of Privilege Vulnerability This is one of the publicly known bugs patched this month, and not only is PoC out there for it, there’s a Metasploit module as well. This privilege escalation vulnerability allows an attacker to gain code execution at SYSTEM level on affected systems. They would, of course, need some level privileges before they could escalate. That’s why these types of bugs are often paired with code execution bugs like the ones in Adobe Reader (mentioned above) to completely take over a system.
Here’s the full list of CVEs released by Microsoft for April 2022:
Chromium: Inappropriate implementation in
* Indicates this CVE had previously been released by a 3rd-party and is now being incorporated into Microsoft products.
We should also call attention CVE-2022-24521, which is a bug in the Windows Common Log File System Driver and listed as under active attack. Since this vulnerability only allows a privilege escalation, it is likely paired with a separate code execution bug. We should also point out that this was reported by the National Security Agency. It’s not stated how widely the exploit is being used in the wild, but it’s likely still targeted at this point and not broadly available. Go patch your systems before that situation changes.
Looking at the remaining Critical-rated bugs patched this month, there are three RCE vulnerabilities impacted the Hyper-V server. In these cases, someone on a guest OS could gain code execution on the underlying host OS. There’s a bug in the LDAP service that’s remote and does not require user interaction. However, to be affected, the default setting for MaxReceiveBuffer LDAP setting must be changed. This isn’t something that’s commonly tweaked, but if your environment has this setting, pay attention to this one. There are Critical patches for SMB and the Server service. In both cases, a user must connect to a malicious share, which would typically require some form of social engineering – like a link in an email or instant message. This is yet another port (TCP 445) that should be blocked at the perimeter. Finally, there’s an update for Microsoft Dynamics 365 (on prem). This vulnerability requires a user to run a specially crafted trusted solution package to execute arbitrary SQL commands. This would allow an attacker to escalate and execute commands with the privileges of the db_owner.
Moving on to the Important-rated patches, the first that stand out are the bunches of fixes for some all too familiar components. We’ve already mentioned the 18 fixes for the DNS Server component. Most of these have multiple mitigations, but many could allow remote code execution. There’s one info disclosure bug thrown in there for good measure. Despite this component being around for years, it seems there are still bugs to find. There are also 15 patches for the Print Spooler this month. Ever since PrintNightmare last year, print spooler bugs seem to just keep coming. It makes sense as the printing system is complex and offers attackers a broad attack surface. Let’s hope these patches don’t cause the types of problems introduced by some the other printer-related patches. And when it comes to large groups of patches, there are a mountain of CVEs affecting the Edge (Chromium-based) browser as well. Most of these bugs were patched by Google and consumed by Edge earlier this month. However, this demonstrates the risk of everyone relying on the same browser platform. A bug in one is now shared by many.
In total, there are 47 patches to correct RCE bugs in this month’s patch. Beyond those already mentioned, there’s yet another RDP client bug that would allow code execution if a user connected to a malicious RDP server. If that sounds familiar, there was a similar bug last month (and more going back months prior). There are a few open-and-own bug in Office components, most notably Excel. The chances of people applying patches to Excel before April 15 seem low, so let’s hope these bugs don’t get exploited. There are a couple of intriguing bugs affecting Win32 file enumeration, although these also require a user to connect to a malicious server or share. There hasn’t been much research on this component, so it will be interesting to see if further bugs are found. Finally, there’s an RCE in Kerberos, but to be affected, the system needs Restricted Admin or Windows Defender Remote Credential Guard enabled on a box with Remote Desktop Connections configured. It’s not clear how common this configuration is, but you should check your systems and apply the update as needed.
The April release includes 59 patches to address Elevation of Privilege (EoP) bugs this month. For the most part, these are in Windows components and would need to be paired with an RCE to allow an attacker to take over a system. A few do stand out. The first is a vulnerability in the Windows Telephony Server that was reported by ZDI vulnerability researcher Simon Zuckerbraun. This flaw exists within the CreateObjectHandler COM object. Crafted method invocations on this object can trigger the deserialization of untrusted data. There are also a pair of bugs in Azure Site Recovery that should be called out as well. Don’t let the admin credential requirement fool you. This bug applies to the VMWare-to-Azure scenario, and administrators will need to upgrade to the latest version to mitigate these vulns.
There are 10 fixes address that address information disclosure bugs. For the most part, these only result in leaks consisting of unspecified memory contents. The lone exception is the bug impacting the Skype for Business. This vulnerability could inadvertently disclose file content to an attacker, but Microsoft doesn’t specific if any file content can be exposed or if just files in specific locations.
April brings eight updates to address DoS bugs, and a few stand out over the others. There’s a DoS in Microsoft Defender, but Microsoft provides no details. Another is a DoS bug in Hyper-V, which is always inconvenient if you happen to be one of the other guest OSes on that Hyper-V server. There are a trio of DoS vulnerabilities in the Windows Cluster Shared Volume (CSV) component, but again, Microsoft provides not details on how the DoS manifests. There are also no details provided about the DoS in Windows Secure Channel, but considering how much relies on schannel these days, definitely don’t take this update lightly.
This month’s update is rounded out by three updates addressing spoofing bugs. The spoofing bug in SharePoint could allow an authenticated user to send malicious content in SIP Address field. This would allow the user to have access to content that is otherwise not authorized. The spoofing vulnerability in Skype for Business and Lync could expose IP addresses or port numbers to an attacker. Finally, the patch for Power BI requires multiple uses hitting the gateway at the same time. While this can likely be scripted, it does increase the attack complexity.
No new advisories were released this month. The latest servicing stack updates can be found in the revised ADV990001.
The next Patch Tuesday falls on May 10, and we’ll return with details and patch analysis then. Until then, stay safe, happy patching, and may all your reboots be smooth and clean!
Memory corruption vulnerabilities have been well known for a long time and programmers have developed various methods to prevent them. One type of memory corruption that is very hard to prevent is the use-after-free and the reason is that it has too many faces! Since it cannot be associated with any specific pattern in source code, it is not trivial to eliminate this vulnerability class. In this blog, a use-after-free vulnerability in Mozilla Firefox will be explained which has been assigned CVE-2022-26381. The Mozilla bug entry 1756793 is still closed to the public as of this writing, but the Zero Day Initiative advisory page ZDI-22-502 can provide a bit more information.
What Is a Use-After-Free Vulnerability?
A use-after-free (UAF) vulnerability happens when a pointer to a freed object is accessed. It does not make sense! Why would a programmer free an object and afterward access it again?
It happens due to the complexity of today’s software. A browser, for example, has many components and each of them may allocate different objects. They may even pass these objects to each other for processing. A component may free an object when it is done using it, while other components still have a pointer to that object. Any dereference of that pointer can lead to a use-after-free vulnerability.
Let’s start quickly by having a look at the minimized proof-of-concept:
When running this on the latest vulnerable release version of Mozilla Firefox, which is 97.0.1, it gives a very promising crash:
This is what the crash point looks like in IDA. It happens inside a loop:
It dereferences a value from memory and then makes an indirect call (a virtual function call) using the fetched value. Thus, this is rated as a remote code execution vulnerability. The value of the “rax” register which is used during dereferencing is particularly interesting: 0xE5E5E5E5E5E5E5E5. This is a magic value that Firefox uses to “poison” the memory of a freed object so that a dereference of a value fetched from that freed object will cause a crash, as this value is never a valid memory address. This helps greatly to catch use-after-free conditions.
To analyze a use-after-free vulnerability, it is always desired to have more information about the freed object: its type, size, where it is allocated, where it is freed, and where it is subsequently used. On Windows, this is usually done by enabling advanced debugging features using the GFlags tool to enable various global flags. Specifically, it can be used to enable pageheap and create a user-mode stack trace to capture the stack trace at the time a particular object is allocated. Unfortunately, this will not help us on Mozilla Firefox, because Firefox has its own memory management mechanism called jemalloc. The way we can get more information about the object is to run the PoC on an ASAN version of Firefox. You can see the result below:
We got lots of information. Let’s break it down a bit by checking where the object is allocated:
Let’s further check this by looking at the source code (line 1164 of /builds/worker/checkouts/gecko/layout/svg/SVGObserverUtils.cpp). You can download the source code of Firefox 97.0.1 or use the online version (note that line numbers of the online version may not match, as it gets updated constantly):
And this is how it looks in the compiled release version:
So the object size is 0x70 (112) bytes and it is used to store and track properties of frames during reflow triggered by scrolling.
Then we want to know where it is freed and reused. ASAN provides a long stack trace. A closer look gives a good hint. Let’s first check the stack trace when the object is freed:
And now the stack trace when the object is subsequently used:
We can see the “mozilla::SVGRenderingObserverSet::InvalidateAll” function in the stack trace when the crash happens and when the object free is initiated. This also matches the crash point of the release version which is inside the OnNonDOMMutationRenderingChange function (it says it is inlined in xul!mozilla::SVGRenderingObserverSet::InvalidateAll). We can now make an initial educated guess: while an object was being processed in a loop in the “mozilla::SVGRenderingObserverSet::InvalidateAll” function, a code path was reached that freed the object being processed, leading to a use-after-free vulnerability.
Now that we have all the details, we can validate this hypothesis step-by-step by running the PoC on the released version of Firefox.
First, we want to know the address of an allocated object so we can monitor it. This can easily be achieved by setting a breakpoint that prints the address of the object upon allocation:
Then, let’s see how the objects are processed in the loop we saw in IDA inside the “mozilla::SVGRenderingObserverSet::InvalidateAll” function. We will print the address of the object that is going to be processed. We also set a breakpoint on the subsequent virtual function call:
We run the PoC, and the debugger stops before calling the virtual function. As you can see, two objects are allocated and these two are going to be processed in the loop. First, one object is processed and a call to the “SVGTextPathObserver::OnRenderingChange” function is made, which eventually frees various allocated objects including the second object which is awaiting processing!
We can see this clearly in the picture below, which is taken immediately after the return from the call. As you can see, the second object has been freed (and poisoned with 0xe5) during the processing of the first object:
In the second iteration, the freed object is loaded for processing, leading to a load of the poison value and resulting in a crash:
Release Versus ASAN Behavior
When running the PoC against the release version, we got a crash during a dereference of 0xE5E5E5E5E5E5E5E5. However, in the ASAN version, it crashed when writing to memory. Why is there a difference? The reason is as follows:
In a release (non-ASAN) build, when freeing an object, its memory remains accessible (not unmapped), and thus any read and write to that memory will still succeed without triggering an immediate crash. That is why the instruction “mov byte ptr [rcx+8], 0” in the above picture executed without error. A crash is likely to occur further along, though. As in our case, if a value is fetched value from a freed object and then dereferenced, the dereference may cause a crash. This is especially true if the freed object content is overwritten by “poison” values as seen above. Note that there is a chance that there will be no crash at all, for example, if there are only reads and writes to the freed object without any dereference operations on fetched values, or if the poison value becomes overwritten with unrelated data. This means that if we fuzz a release version, there is a chance we could miss a vulnerability.
ASAN, on the other hand, monitors all read, write, and dereferences on memory and can catch such vulnerabilities as soon as possible. That is why it is recommended to use an ASAN version for fuzzing.
Use-after-free vulnerabilities are often fixed by converting raw pointers to smart pointers or by correcting the management of the object reference count. Here, it was fixed by changing how continuations frame reflows are handled in the engine:
Developers have expended a great deal of effort to eliminate vulnerabilities associated with known patterns in source code, and they have mostly succeeded in decreasing their prevalence. However, there are some classes of vulnerabilities that are harder to prevent, and use-after-free is one of them. Assuring perfect management of object lifecycles in software with a million lines of code is extremely difficult. This is one of the main motivations behind languages like Rust that enforce proper object ownership and lifetime management.
You can find me on Twitter at @hosselot and follow the team for the latest in exploit techniques and security patches.
CVE-2022-26381: Gone by others! Triggering a UAF in Firefox
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:
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.
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
It’s once again Patch Tuesday, which means the latest security updates from Adobe and Microsoft have arrived. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for March 2022
The Adobe release for March is quite small. This month, Adobe released only three patches addressing six CVEs in Adobe Photoshop, Illustrator, and After Effects. The patch for After Effects is the largest of the three. It fixes four Critical-rated, stacked-based buffer overflows that could result in arbitrary code execution. The fix for Illustrator is also rated Critical. It addresses a single buffer overflow that could lead to arbitrary code execution. Finally, the update for Photoshop fixes a single Important-rated memory leak.
None of the bugs fixed by Adobe this month are listed as publicly known or under active attack at the time of release.
Microsoft Patches for March 2022
For March, Microsoft released 71 new patches addressing CVEs in Microsoft Windows and Windows Components, Azure Site Recovery, Microsoft Defender for Endpoint and IoT, Intune, Edge (Chromium-based), Windows HTML Platforms, Office and Office Components, Skype for Chrome, .NET and Visual Studio, Windows RDP, SMB Server, and Xbox. This is in addition to the 21 CVEs patched by Microsoft Edge (Chromium-based) earlier this month, which brings the March total to 92 CVEs.
Of the 71 CVEs released today, three are rated Critical and 68 are rated Important in severity. A total of seven of these bugs came through the ZDI program. Historically speaking, this is volume is in line with previous March releases. However, the number of Critical-rated patches is again strangely low for this number of bugs. It’s unclear if this low percentage of bugs is just a coincidence or if Microsoft might be evaluating the severity using different calculus than in the past.
None of the bugs are listed as under active exploit this month, while three are listed as publicly known at the time of release. Let’s take a closer look at some of the more interesting updates for this month, starting with one of the bugs listed as publicly known:
- CVE-2022-21990 – Remote Desktop Client Remote Code Execution Vulnerability This client-side bug doesn’t have the same punch as server-side related RDP vulnerabilities, but since it’s listed as publicly known, it makes sense to go ahead and treat this as a Critical-rated bug. If an attacker can lure an affected RDP client to connect to their RDP server, the attacker could trigger code execution on the targeted client. Again, this isn’t as severe as BlueKeep or some of the other RDP server bugs, but it definitely shouldn’t be overlooked.
- CVE-2022-23277 – Microsoft Exchange Server Remote Code Execution Vulnerability This Critical-rated bug in Exchange Server was reported by long-time ZDI contributor Markus Wulftange. The vulnerability would allow an authenticated attacker to execute their code with elevated privileges through a network call. This is also listed as low complexity with exploitation more likely, so it would not surprise me to see this bug exploited in the wild soon - despite the authentication requirement. Test and deploy this to your Exchange servers quickly.
- CVE-2022-24508 – Windows SMBv3 Client/Server Remote Code Execution Vulnerability This bug could allow an attacker to execute code on Windows 10 version 2004 and newer systems. It’s also reminiscent of CVE-2020-0796 from a couple of years ago. Both also list disabling SMBv3 compression as a workaround for SMB servers, but this doesn’t help clients. In 2020, Microsoft noted SMBv3 compression “is not yet used by Windows or Windows Server and disabling SMB Compression has no negative performance impact.” That’s not in the current advisory, so it’s unclear what disabling this feature will have now. Authentication is required here, but since this affected both clients and servers, an attacker could use this for lateral movement within a network. This is another one I would treat as Critical and mitigate quickly.
- CVE-2022-21967 – Xbox Live Auth Manager for Windows Elevation of Privilege Vulnerability This appears to be the first security patch impacting Xbox specifically. There was an advisory for an inadvertently disclosed Xbox Live certificate back in 2015, but this seems to be the first security-specific update for the device itself. Microsoft even notes other Windows OSes are not affected by this bug. It’s not clear how an attacker could escalate privileges using this vulnerability, but the Auth Manager component is listed as affected. This service handles interacting with the Xbox Live service. I doubt many enterprises are reliant on Xbox or Xbox Live, but if you are, make sure this patch doesn’t go unnoticed.
Here’s the full list of CVEs released by Microsoft for March 2022:
* Indicates this CVE had previously been released by a 3rd-party and is now being incorporated into Microsoft products.
Looking at the rest of the March release, the 11 CVEs impacting Azure Site Recovery stand out. For those not familiar with it, Site Recovery is a native disaster recovery as a service (DRaaS). This month’s release includes fixes for five elevation of privilege (EoP) and six remote code execution (RCE) bugs in the platform. Considering everything going on in the world, now is a bad time to have issues with your disaster recovery plans. If you’re using this platform, make sure these patches get installed. If you’re not using this platform, take time to review your disaster recovery plans anyway. It couldn’t hurt.
Besides the Exchange bug already mentioned, the Critical-rated fixes in this release both address bugs in HEVC and VP9 video extensions. These updates can be found in the Microsoft Store. If you aren’t connected to the internet or are in an otherwise disconnected environment, you’ll need to manually apply the patch.
Including those already mentioned, there are a total of 28 RCE fixes released today. There are additional updates for the HEVC video extension component. Again, these fixes are obtained through the Microsoft Store. The raw image extension bugs fall into this class as well. There are three fixes for Visio that were reported by kdot through this ZDI program. These bugs include a type confusion, an untrusted pointer deref, and an Out-Of-Bounds (OOB) Write. In each case, a user must open a specially crafted Visio file to be impacted. One of the other publicly known bugs is an RCE in .NET and Visual Studio. There’s scant information about this bug, but if you are developing apps in .NET or Visual Studio, review it carefully. Since RPC bugs are never out of fashion, there’s a fix for event tracing that could result in code execution through a specially crafted RPC connection. There are several caveats to this one that lower the severity, but don’t remove the risk completely.
Rounding out the RCE bugs is one submitted by an anonymous researcher through the ZDI program impacts Microsoft Defender for IoT. The vulnerability exists within the password change mechanism. It results from the lack of proper validation of a user-supplied string before using it to execute a system call. Defender for IoT also receives a patch for an EoP bug found by ZDI Vulnerability Researcher Simon Zuckerbraun. This bug also occurs within the password change mechanism, but here, the bug is caused by the lack of proper validation of a user-supplied string before using it to execute a system call. An attacker can leverage this vulnerability to escalate privileges and execute arbitrary code in the context of root.
Moving on to the other EoP cases, most would require an attacker to log on to a system and run a specially crafted program. Several of these fixes note that the vulnerability is the result of a race condition, making exploitation somewhat unreliable. There are some interesting components receiving fixes for privilege escalations this month, including the FAT file system, the Fax and Scan Service, and the CD-ROM driver. It’s almost retro. Another interesting component is the Windows PDEV, which is a logical representation of a physical device characterized by the type of hardware, logical address, and surfaces that can be supported. ZDI Vulnerability Researcher Lucas Leong reported a Use-After-Free (UAF) bug in the handling of PDEV objects. An attacker could use this to escalate privileges and execute arbitrary code in the context of SYSTEM.
Six of this month’s fixes address information disclosure bugs. For the most part, these only result in leaks consisting of unspecified memory contents. The lone exception is the bug impacting the Skype for Chrome extension. This vulnerability could inadvertently disclose the Skype ID of a target. An attacker could gain access to that ID they could match it within Skype to a name and Avatar of the target user. If you’re using Skype for Chrome, you’ll need to get the update through the Chrome Web Store.
There are four updates to address DoS bugs in this release, and two stand out over the others. The first is a DoS in Hyper-V, which is always inconvenient if you happen to be one of the other guest OSes on that Hyper-V server. The other is a vulnerability in the Point-to-Point Tunneling (PPTP) protocol, which is used in the implementation of virtual private networks (VPN) that allow people to extend their private networks over the Internet via “tunnels”. There are no details about this bug given, but anything that could take down a VPN is unwelcome – especially since so many of us rely on VPNs to work from home (or wherever).
Three different components receive fixes for security feature bypasses (SFB) in this month’s release. The first continues the retro theme by fixing bugs in the Windows HTML platforms, including Internet Explorer and Edge (HTML-Based). Microsoft does not indicate which security feature is bypassed, but considering how pervasive MSHTML continues to be, patching is certainly recommended. Word receives a fix for an SFB bug that could allow specific protections to be bypassed in Protected View. This could potentially result in a user opening a malicious document but not receiving the intended warning dialogs. The final SFB fix applies to the Intune Portal for iOS. An attacker could use this vulnerability to bypass the Intune policy file save location and presumably load their own policy instead.
This month’s release includes three updates for spoofing bugs. The Exchange spoofing bug could allow an authenticated attacker to view file content on the affected server. Microsoft provides little information about the spoofing bugs in Defender Endpoint and Visual Studio other than to say the Defender bug requires knowledge of the target environment and the Visual Studio bug requires a user to open a file.
We wrap up this month’s release with an odd tampering bug in Microsoft Word. Microsoft gives no information on how the vulnerability can be exploited, but they do indicate information from the victim can be sent to the attacker, and that the Preview Pane is an attack vector. It sounds like a specially crafted Word doc can send potentially sensitive information to an attacker when the document is opened or viewed in the Preview Pane. Office for Mac users are out of luck as well, as the patches for Microsoft Office 2019 for Mac and Microsoft Office LTSC for Mac 2021 are not available yet. It will be interesting to see if additional information is released about this bug in the future.
No new advisories were released this month. The latest servicing stack updates can be found in the revised ADV990001.
The next Patch Tuesday falls on April 12, and we’ll return with details and patch analysis then. Until then, stay safe, happy patching, and may all your reboots be smooth and clean!
In the first blog of the series, we saw how CodeQL and Clang checkers can be used to find bugs in MySQL Cluster involving untrusted size arguments leading to buffer overflow or out-of-bound array accesses. Though the majority of bugs were out-of-bounds array accesses, there were also bugs involving untrusted data being used in loop conditions or casted to pointers. In this final blog of the series, we experiment with CodeQL’s IR and Clang checkers for detecting such bug classes.
Defining taint sources - CSA vs CodeQL
The first part of the problem is defining the taint sources. Clang Static Analyzer (CSA) provides an experimental checker alpha.security.taint.TaintPropagation for performing static taint analysis. Implemented as GenericTaintChecker, it has a set of built-in taint sources. Since the Signal data used by message handlers does not come directly from these built-in taint sources, it is necessary to find an alternative approach to define taint sources. Lucas Leong had a quick approach to work around the problem - rewrite all access to signal->theData with getenv(). Since the return value of getenv() is considered tainted by GenericTaintChecker, taint propagation works after rewrite. Refer to his blog post “MindShaRE: When MySQL Cluster Encounters Taint Analysis” for details on using existing taint checkers and CodeQL to find memory corruption bugs.
One has to be careful with this approach to avoid missing potential taint sources. Though MySQL Cluster has defined APIs like Signal::getDataPtr() to fetch the Signal data pointer, various handlers don’t follow the standard. Instead, signal->theData is accessed in numerous other ways from offset 0 or from various other offsets. I rewrote some common patterns using find and sed. This may not be exhaustive but provides sufficient taint sources to experiment with the checkers.
The situation is much different when working with CodeQL, where defining taint sources is far more flexible. All we have to do is override the isSource() predicate to something like this:
CWE-822: Untrusted Pointer Dereference
In an untrusted pointer deference vulnerability, data from an untrusted source is casted to a pointer for further use. The impact of the bug depends on the usage of the casted pointer. This section provides details about detecting such pointer load operation using CSA and CodeQL.
Detecting untrusted pointer dereference using CSA
To detect this vulnerability using CSA, I relied on path-sensitive checker callback check::Location which fires every time a program accesses memory for read or write. The information below is from the checker documentation:
The SVal symbolic valueLoc points to the memory region being accessed. IsLoad indicates whether the access is a read or a write. To check if a memory load is happening from a tainted memory region, we can check if Loc is tainted. If so, we can use the statement S to get the type of the expression:
Whenever the expression type is a pointer, it is logged as a bug. Scanning MySQL Cluster with this checker gave about 86 results, which is significantly high and also has false positives. Here is what the scan results look like:
The large number of results is due to the fact that any pointer derived from a tainted value (via pointer arithmetic, array indexing, etc.) is also considered tainted, irrespective of whether the tainted value is constrained by validation. In some cases, OOB reads which load pointers are also reported. Understanding the nature of false-positive results significantly improves the triage experience.
Considering the high number of results, we can sort the results by “File” which is likely to organize the result by feature, or for a less familiar code base, sorting by “Path Length” can help identify code paths reachable with minimum complexity.
scan-view results sorted by File
scan-view results sorted by Path Length
CSA reported a number of bugs in the code handling DBDIH block with a path length of 1. Here is an example bug report:
Using a known bug pattern, it is possible to apply filters to reduce the results in addition to the taint check. For example, we can check the AST statements for pointer loads which are only assignment statements like above. The checker can be tweaked as per the nature of bugs in the codebase.
Analyzing memory loads using CodeQL IR
To perform a similar analysis in CodeQL, one can possibly rely on expression classes such as PointerDereferenceExpr, VariableAccess, FieldAccess and its subtypes. But in this case, I was curious to explore CodeQL’s Intermediate Representation (IR) to track memory loads. Since the documentation around CodeQL’s IR is limited, I used the Instruction class to dump the IR for further analysis. Here is a partial dump of IR for the line EmulatedJamBuffer * jambuf = (EmulatedJamBuffer*)req->jamBufferPtr in function execDIH_SCAN_TAB_REQ():
The CodeQL query used to dump the IR along with source code information:
Consider the below set of instructions in the IR:
Here the LoadInstruction relies on 2 operands - a source address operand (r17303_4) and a source value operand (m17300_12). The source value operand is a MemoryOperand. The MemoryOperand describes the memory address accessed by the instruction, whose value gets copied to the result register (r17303_5). Moreover, the result is also associated with type information. The idea was to filter all tainted memory load operations whose return type is a pointer. However, such a query resulted in an unusably large number of results.
Adding constraints using overlap relationship and virtual variables
Consulting CodeQL’s IR SSA Construction documentation, I found a couple of features that could be useful for refining the query: the overlap relationship and VirtualVariables.
Overlap defines the relationship between the definition of a memory location and its usage. The most interesting relationship for this analysis is MustExactlyOverlap - the set of bits written by the definition is identical to the set of bits read by the use, and the data type of both the definition and the use are the same. For more clarity on the overlap relationship, refer to the SSA test case found in the repository. In the case of untrusted pointer load bugs, it is very likely that there will be a mismatch of data type between definition and usage (type casting) or that the number of bits read will be a subset of the definition. Therefore, we can skip Load operations where the source value operand has an exactly overlapping relationship with its definition. The getOperandMemoryLocation() predicate provides information regarding the MemoryLocation read by a memory operand. Consider the output of the following query:
The memory operands that are marked with tilde “~” are the ones that do not have an exactly overlapping relationship. This can also be checked using isDefinitionInexact() predicate. Putting all this together, we can override the isSink() predicate to get a meaningful number of results to work with.
Many of the false-positive results were due to multiple load operations performed using some misidentified pointer. These results can be either skipped or removed by adding further constraints to the query, such as ignoring certain variable names in the sink or checking for AST patterns.
In the case of MySQL Cluster, one such constraint explored for filtering memory access to the Signal structure is VirtualVariable. As per the documentation, “Each MemoryLocation is associated with exactly one VirtualVariable. A VirtualVariable represents a set of MemoryLocations such that any two MemoryLocations that overlap have the same VirtualVariable.” VirtualVariable information can be fetched from a MemoryLocation using the getVirtualVariable() predicate.
When the variable names are consistent, we can add a constraint to consider only Load operations where the memory operand points to the signal variable. A more generic option is to fetch the type information of the virtual variable to check if it is a Signalstructure. Such a query is still restrictive (not as much variable name) but significantly reduces false positives and returns results involving jamBufferPtr:
CWE-606: Unchecked Input for Loop Condition
In CWE-606: Unchecked Input for Loop Condition, values from an untrusted source are used for loop termination conditions. This may lead to a DoS or other issues depending on the operations done in the loop body. This section provides details about detecting such tainted loop conditions using CSA and CodeQL.
Detecting tainted loop condition using CSA
Unlike tainted memory loads, I couldn’t find any path-sensitive callback to trigger on loop conditions. Moreover, AST-based matchers without path-sensitivity are not useful in this case. Therefore, I relied on the check::BranchCondition callback which fires every time a control flow branching occurs during analysis. The following information is from the checker documentation:
The idea here is, whenever the callback triggers due to a conditional statement, walk up the AST using ParentMap and check for a loop statement. Here is what an example AST looks like for while loop:
For loop operations we are only interested in 3 AST statement classes – WhileStmtClass, DoStmtClass and ForStmtClass. Below is the loop detection code used in the checker:
Once we know that the condition statement triggering the callback is part of a loop statement, we can check if it is tainted. Specifically, I wanted to look for some common code patterns involving induction variables compared against untrusted values, or untrusted values used as induction variables to decide on loop termination. Consider a couple of common code patterns below that involve explicit binary comparison operations:
• The induction variable is compared against a potentially untrusted value. For example, RHS could be tainted and LHS is not. • The induction variable could be potentially untrusted. Here LHS value is compared against constant 0 on RHS.
The checker specifically looks for these cases to make decisions on bugs. When RHS is constant 0, check if LHS is tainted. Otherwise, check if RHS is tainted:
Another common code pattern is unary operations in loop statements, especially while and do while loops:
No special breakdown is necessary in case of unary operations in the way we handled binary operations. However, in certain cases, implicit Boolean conversions result in implicit conditional statements received by the check::BranchCondition callback. Here is what the AST looks like:
To handle these, if any non-binary conditional operations have a Boolean outcome, it is possibly due to implicit casting and hence we get the sub-expression associated with the expression.
Evaluating constraints on tainted variables
While it is possible to know if an input is tainted or not, there is no way to know if the tainted input value is constrained by some validation. Without this information, the checker is going to generate a lot of false-positive results. To solve this problem, I used the solution provided by Andrew Ruef in the blog post Trail of Bits - Using Static Analysis and Clang to Find Heartbleed. Since Signal data is treated as an unsigned 32-bit integer in most cases, I queried if the variable can take a value greater than 0x10000. If yes, consider the variable as unconstrained and log the bug.
Configuring analyzer-max-loop in CSA
Clang analyzer has a configuration parameter to choose the number of times a basic block in a loop gets executed. By default, this value is 4.
So how does it matter in our analysis? Consider the below code:
Here is buffer->index is validated and the loop operation is considered safe. But the checker still reports a false positive bug.
What seems to be happening here is, the symbolic expression gets evaluated analyzer-max-loop number of times i.e., for each visit to the basic block.
The analyzer seems to evaluate that the decrement operation can underflow resulting in a value greater than 0x10000, therefore reporting it as a bug. I’m not entirely sure of the right way to solve this issue, but a quick workaround is to set analyzer-max-loop to 1. This can also be done in scan-build using the maxloop parameter. In this case, the expression is evaluated only once and it does not report the bug.
The scan reported around 46 bugs, with some valid ones including previously found issues like ZDI-CAN-14488, ZDI-CAN-15120, ZDI-CAN-15121.
Here is the example bug report for vulnerability in Dbdict::execLIST_TABLES_CONF():
Detecting tainted loop condition using CodeQL
Using the analysis done earlier for CSA, an equivalent query in CodeQL can be implemented using the Loop class. The isSink() predicate essentially looks as follows:
Building and Performing the Scan
In order to build clang with custom checkers, copy the source files to the clang/lib/StaticAnalyzer/Checkers directory in the LLVM toolchain. Then add the filenames to the CMakeLists:
Also update the clang/include/clang/StaticAnalyzer/Checkers/Checkers.td file to add the package information:
Once you make clang, the new checkers will be listed alongside other alpha checkers.
Now we can use scan-build to perform the analysis. Use the maxloop and use-analyzer configurations if necessary.
Building with checkers can be slow. To speed up the scan, limit the target path by either modifying the Makefile as necessary or use the custom Makefile by Lucas. All this analysis was performed on clang 12.0 and MySQL Cluster 8.0.25
Scanning with CodeQL requires creating a database, followed by running any queries we are interested in against the created database.
The source code for the Clang checkers and CodeQL queries can be found here.
We hope you’ve enjoyed this look at finding bugs using Clang Static Analyzer, CodeQL, and Binary Ninja. As ZDI Vulnerability Analysts, these have proved helpful in finding new bugs. If you use these (or other) tools to find bugs of your own, consider submitting them to our program. Until then, you can find me on Twitter @RenoRobertr, and follow the team for the latest in exploit techniques and security patches.
Clang Checkers and CodeQL Queries for Detecting Untrusted Pointer Derefs and Tainted Loop Conditions
Taint analysis is an effective technique for finding vulnerabilities, even in large codebases. My colleague, Lucas Leong, recently demonstrated how Clang Static Analyzer and CodeQL can be used to model and find vulnerabilities in MySQL NDB Cluster using taint analysis. Largely inspired by his work, I wanted to try something similar but using Binary Ninja since it can also work with closed-source programs.
These are a few things I had in mind while working:
• Identify vulnerabilities due to uses of untrusted values without bounds checking • Taint propagation and filtering should be control-flow sensitive • Support inter-procedure analysis
I approached this as a graph reachability problem, for which Tainted Flow Analysis on e-SSA-form Programs served as an excellent reference. All the analysis in this article is based on MySQL Cluster 8.0.25 and Binary Ninja 2.4.2846.
Defining Taint Sources
To get taint analysis working, it is essential to define the taint sources clearly. MySQL Cluster has a message passing architecture, and interesting taint sources are the messages themselves. This section provides details on message handling and how the message handlers can be identified for analysis.
MySQL NDB Cluster Signals
MySQL NDB Cluster defines functionalities as “blocks” and messages passing between them as “signals”. The NDB blocks are implemented as C++ classes, and each block registers multiple signal handlers during initialization, which are also methods of the class. Most of the vulnerabilities reported were in these message handlers, also known as signal handlers.
All the blocks inherit the SimulatedBlock class to register their signals using addRecSignal(), which invokes the SimulatedBlock::addRecSignalImpl() method. The registered signal handlers are of type ExecSignalLocal, which takes a single argument. Interested readers can refer to blog posts on Ndb software architecture by Frazer Clement and Code Reading Notes – MySQL Cluster by Steinway Wu for further details. The scope of this article is limited to entry points to signal handlers. Below is an example of the code of the NDBCNTR block registering a signal handler:
The “Signal” object that each handler receives contains untrusted data. The signal handlers can access the data as signal->getDataPtr() or with a few other methods. The handlers can also further pass the “Signal” object to other functions. There are a couple of ways to proceed here. You can either analyze any function that takes Signal as an argument or analyze only the actual signal handlers by cross-referencing calls to SimulatedBlock::addRecSignalImpl() and then let inter-procedure analysis take care of the rest. I chose to start with the former since the inter-procedure analysis was implemented at a later stage.
The Signal object is 0x8030 bytes in size and not all bytes should be considered tainted. We should only define a small region of memory of the object as tainted so that only memory reads from the tainted region are propagated. Marking the entire structure as tainted will lead to a lot of false positives. In this case, the signal’s tainted data starts at offset 0x28 and any memory loads from this offset are marked tainted. Both Signal::getDataPtr() and Signal::getDataPtrSend() return a pointer to this memory.
Porting type information from IDA Pro to Binary Ninja
The executable under analysis is “ndbd”, which is the NDB Cluster Data Node Daemon built with DWARF debug information. In order to find functions that take a pointer to a Signal object as an argument, check the type information of all functions as follows:
However, at the moment, Binary Ninja does not handle DWARF information as robustly as IDA Pro does. Another issue with Binary Ninja is its failure to detect the “this” argument when analyzing C++ executables. As a result, argument detection will not be accurate, breaking our taint source analysis. An easy fix is to import type information from IDA Pro into Binary Ninja. For example, the Dblqh::prepareContinueAfterBlockedLab() method has the following type information as per IDA Pro:
The same function looks different in Binary Ninja. In this case, the “this” pointer is missing, and Signal becomes the first argument. Marking “arg1” as a taint source makes the entire analysis wrong.
Since we are only interested in the right argument position and type information of the Signal argument, we fix it using the scripts provided in ida2bn directory:
Once the type information is fixed, we are good to identify functions and mark taint sources using the Signal argument. More details on working with types in Binary Ninja are documented here Working with Types, Structures, and Symbols.
Taint Propagation and Filtering
The goals of taint propagation are simple: when a variable is assigned a value from the Signal data, mark it as tainted. If any other variable is derived from the tainted variable, also mark it tainted, and so on. The challenge comes when there are sanitizers. Say a variable is tainted, and in some code path there is a validation for that variable. In this case, the variable is no longer tainted in that code path. Taint propagation should be control-flow sensitive to avoid over tainting and false positives. This section details how I approached the problem using Binary Ninja’s IL and SSA form. For a thorough reading on the topic, please refer to blog posts Breaking Down Binary Ninja’s Low-Level IL and Vulnerability Modeling with Binary Ninja.
Binary Ninja ILs and SSA form
Binary Ninja supports a variety of Intermediate Languages (IL) like Low-Level IL (LLIL), Medium Level IL (MLIL), and High-Level IL (HLIL). Since MLIL abstracts away stack memory access with variables and has parameters associated with call sites, I found it more suitable to perform inter-procedure taint analysis. Moreover, it is better documented than HLIL.
Another powerful feature supported is the Single Static Assignment (SSA) form of the available ILs. In SSA form, each variable is defined only once. When the variable is reassigned to another value, a new version of the variable is created. Therefore, it is easy to track a tainted variable at any point in a function. Consider this minimalistic example: when variable x is reassigned a new value, a new version of the variable is created in the SSA form:
SSA variable def-use chain
Binary Ninja provides get_ssa_var_definition() and get_ssa_var_uses() APIs to get a variable’s definition site and their uses respectively. Consider the MLIL SSA code snippet of Thrman::execOVERLOAD_STATUS_REP() method below:
Here, arg2 is a pointer to a Signal object. At the address 0x00784165, the SSA variable “rax#1” is loaded with a tainted value from [arg2#0 + 0x28]. The MLIL instructions that use the tainted SSA variable rax#1 can be fetched as below:
These APIs form the building blocks of our taint analysis going further.
Taint propagation with SSA def-use chain
Binary Ninja’s ILs are structured as an expression tree such that operands of an operation can be composed of other operations. Consider the graph generated for the below MLIL SSA instruction by the BNIL Instruction Graph plugin:
The MLIL_SET_VAR_SSA operation marks the definition of a new SSA variable, which sets the dest variable to the result of the src expression. The src expression could be composed of many other operations. In this case, MLIL_ADD adds an offset 0x28 to the base address of Signal and then MLIL_LOAD_SSA reads the value from the address computed using MLIL_ADD. Effective taint propagation requires visiting all the MLIL SSA operations for every instruction expression. Josh Watson’s emILator and IL instruction counting by Jordan are good examples for visiting and processing MLIL SSA instruction expressions. What does the taint propagation algorithm look like?
• Visit all MLIL SSA instructions in the function linearly • For any MLIL_SET_VAR_SSA operation, resolve the src expression to check if it is tainted data • If the src operand returns tainted data, get the uses of the dest SSA variable with get_ssa_var_uses() • Visit the instructions that use the tainted SSA variable and propagate taint when MLIL_SET_VAR_SSA is encountered • Once an instruction taints a variable, mark it as visited and never visit again
Constraints on SSA variables
Once we have the taint propagation algorithm in place, how do we handle sanitizers on the tainted variables? We are only interested in code paths without any validations. With this in mind, let’s revisit our taint propagation algorithm, which relies on the def-use chain. Def-use chains are sequential statements of code; therefore, taint propagation is not control-flow sensitive. Here is an example to demonstrate the issue:
The “value” variable passed to the function is tainted and gets used in two different code paths. Along the code path executing the basic block at 0x1184, the variable is validated and considered clean. The get_ssa_var_uses() for the variable returns 3 instructions:
Processing these 3 instructions linearly would lead to the incorrect conclusion that the validation precedes both usages of the tainted value. In reality, only one instruction is protected. The other two are vulnerable. This problem can be solved by taking control flow into account.
Control-flow sensitive propagation using constraint graph
The MediumLevelILInstruction class has an il_basic_block property to get the basic block information of the MLIL instruction.
Using this property, we can fetch the basic blocks of SSA variable definition and SSA variable uses, which also includes the basic blocks where the validations are done. The basic blocks are also referred to as the “constraint” blocks. Some properties of these basic blocks are as follows:
• The definition block always dominates all uses of the SSA variable. • The basic block that has the definition can contain constraints. The same applies to any basic blocks of the def-use chain. • A definition block is always reachable and hence all the instructions in it are reachable too.
Considering this as a graph reachability problem, the question is, can we reach all the instructions in the def-use chain of the SSA variable in the presence of a constraint block? To answer this, we build a constraint graph from the CFG of the function and use a pathfinding algorithm on it:
• Remove the outgoing edges of constraint blocks from the CFG. This is our constraint graph. • Find if a path exists between the definition basic block and other basic blocks of the def-use chain in the constraint graph. • If any def-use basic blocks are not reachable, then those instructions are not used for taint propagation.
Since each assignment is unique in SSA representation, we maintain a per-variable dictionary of the necessary information including the constraint graph for later analysis. Here is a sample pseudocode to find reachable blocks in the presence of constraint blocks:
To find if an SSA variable is tainted at a given instruction, all we need to do is check its reachable def-use chain:
Arithmetic operations as filters
Other than explicit filters, there are also arithmetic operations that can also be taint filters. For example, AND or Logical Shift Right (LSR) operations may place constraints on a value. In such circumstances, a heuristic can be used to filter out undesired results. Consider the example below:
Here, the tainted value is not explicitly compared against anything, but operations such as LSR and AND limit the input range. This is where I found the possible_values property very useful. Binary Ninja’s data flow analysis can provide possible values for an expression:
Handling Transitively Tainted Variables
The first stage of analysis propagates taint data and generates information such as a list of tainted variables, constraints placed on each SSA variable, and their respective constraint subgraphs.
During the second stage of analysis, we explore the relationships between the tainted SSA variables. Why is this important? We are only looking for unbounded SSA variables. While any direct constraints placed on an SSA variable are already handled in the first stage, the constraints placed on SSA variables that are propagated transitively are not yet handled. Consider the example below:
The index#0 variable could be tainted and not constrained. However, the derived variable constrained_var#1 is validated, indirectly placing constraints on the index variables. Therefore index#3 is not tainted during the memory access at 0x11f2. Here is another example:
Here, index#1, index#2, rax#1, and constrained_var#1 are copies or direct assignments of the variable index#0. When variable constrained_var#1 is validated, the other variables are also validated. Not analyzing the effect of constraints on derived variables or copies of variables leads to false-positives. This section details ideas on handling constraints on related variables.
Constraints on transitively related SSA variables
After the taint propagation phase is over, we iterate through all the tainted variables that have constraints on them. For every variable with constraints, we find its child variables and parent variables.
• Variables that are derived from a given variable are called child variables. • Variables from which a given variable is derived are called parent variables.
To check if the constraints on the variable under consideration have any effect on its parent or child variables, we perform the below checks:
• Pick the constraint subgraph for the SSA variable under consideration. • Check if the definitions of child variables are reachable from the definition of the current variable. · If not, the constraint is placed before defining the child variable in the CFG, and therefore none of the basic blocks in the def-use chain are tainted. · If yes, the constraint is placed after defining the child variable in the CFG. In this case, also check if all basic blocks of the def-use chain of the child variable are reachable from the definition of child. Mark the non-reachable blocks as clean.
• For each parent variable, get its list of child variables. While all the child variables of the current variable are also child variables of the parent, parent variables might have other child variables too. The child variables already visited in the previous step can be skipped. Now check if the definitions of child variables are reachable from the definition of parent variable. For a yes or no, repeat the same as mentioned in the previous step to mark the non-reachable blocks as clean.
This way the non-reachable basic blocks are removed from tainted entries of variables related to a constrained variable. We can also choose to perform analysis on variables that are derived or just direct assignments using tags associated with a variable.
While propagating taint, two different tags were used – a direct memory load using MLIL_LOAD_SSA from tainted memory returns an offset, size pair as tag and it gets associated with the destination variable. Whereas for any derived variable, the destination variable is associated with a marker but not the offset, size pair. Consider the code:
The variable rcx_1#2 is tainted with a tag [0x2c, 0x4], which is the offset size pair. This is the same as the case with rbx#1, which is a direct assignment. However, rbx_1#2 derived from the expression rbx#1 u>> 5 is tainted with a tag [0xdeadbeef, 0xdeadbeef]. Using different tag type information, it is possible to identify the nature of taint propagation.
Constraints on SSA variables from multiple taint sources
While propagating taint, we mark a destination variable as tainted if any of the source variables are tainted, including the PHI function. During filtering in the second stage, if a variable is constrained, we apply the constraints to all is related variables. But, when the derived variable (child) is coming from more than one independent taint sources (parents) and only one of the parent variables is validated, the child variable is also considered validated. But this is not desirable. Consider the example below:
Let’s say x and y are coming from two independent taint sources and index is a sum of both, hence a derived variable. When x gets validated, index can still be tainted since y is not validated. The previous algorithm does not take this into account.
To solve this problem, I considered associating each derived tainted variable with the actual source variables referred to as root variables and maintain copies of def-use chain per root variable. For example, variable index#3 has two roots – x#0 and y#0. For each root, maintain a copy of reachable blocks in taint information associated with index#3. When x#1 is validated, only the x#0 copy of index#3 is marked not reachable and the y#0 copy is still considered tainted. A dependency graph of variables is built to establish these relationships.
Establishing SSA variable relationship using a dependency graph
In a variable dependency graph, any tainted variable in the function is represented as a node. When a variable is derived from another variable, it forms a directed edge from the parent variable (node) to the child variable (node).
In order to establish a relationship between variables, the definition site of all the tainted variables is visited using get_ssa_var_definition(). When any of the source variables in the MLIL expression are tainted, create an edge connection in the graph. A variable tainted during MLIL_LOAD_SSA operation does not have a parent node or incoming edges and therefore becomes the root node.
Such a dependency graph will have many weakly connected components because each memory load from the tainted memory region will be assigned to a new variable and therefore a new node in the graph. Put simply, each memory load creates a subgraph along with its derived variables. A subgraph might connect with another when a variable is derived out of more than one root node. Here is a sample dependency graph from the function Dbtux::execTUX_ADD_ATTRREQ():
Another property to note is that dependency graphs are not necessarily Directed Acyclic Graphs (DAG). This is because loops can be introduced by a circular dependency of variables in PHI functions. Consider the below SSA representation of a loop operation:
Here, the value of counter#2 depends on counter#1 or counter#4, which is a PHI function. The predecessor block decides the outcome of the function. Further down in the loop, counter#4 depends on counter#2. This relationship will be represented as a cycle in a dependency graph.
Once the dependency graph is generated, it is easy to get the root variables associated with any tainted variables. Moreover, child and parent variables for any given variable can be fetched for handling transitive relationships. The only missing part now is the forward propagation of tainted information to other functions.
Static Function Hooks and Inter-procedure Taint Propagation
All the MLIL_CALL_SSA and MLIL_TAILCALL_SSA instructions with tainted arguments are processed once the analysis of the current function is finished. For any CALL instructions with a known destination (e.g., MLIL_CONST_PTR), the symbol is fetched to check for static hooks. Here is the code snippet:
Static hooks are handlers to functions that we intend to handle differently compared to other functions. Consider a call to the libcmemcpy function, where taint propagation is not necessary but only interested in checking for tainted size, source, or destination arguments. In order to provide this information to the analyzer and make it configurable, a JSON config with function names and arguments is used as below:
The arguments to check are indexed from 0. In the case of memcpy, all 3 parameters are marked for analysis. The argument index provided in the JSON config is checked against the tainted SSA variables. For example, arg2 in the config maps to an SSA argument variable associated with memcpy’s size argument.
Static hooks can also be used to mark an output variable or return value of a function to be tainted and further propagated. However, this is not currently implemented since function-specific details are not considered. When necessary, the visitor handler for the MLIL_SET_VAR_SSA operation can be reused for implementing backward taint propagation during CALL operations. For any other function without hooks, taint information is propagated by marking the target function’s variable as tainted.
Tracing Vulnerabilities from Reachable Blocks
Once the taint propagation and filtering phases are over, the last phase of analysis involves iterating through all tainted variables and checking the reachable blocks for potential sinks. Based on the bugs already reported, I chose to look for vulnerabilities involving Out-Of-Bounds (OOB) memory access, buffer overflows during function calls to APIs such as memcpy, untrusted inputs casted to a pointer, and tainted loop counters. The rest of this section details additional detection strategies.
OOB reads and writes
The majority of vulnerabilities in MySQL Cluster were OOB read and write memory access bugs due to the missing validation of untrusted array indexes. To detect these bugs, we can specifically consider any MLIL_LOAD_SSA or MLIL_STORE_SSA instructions as sinks. Here is an example code from Dbdih::execGET_LATEST_GCI_REQ():
Here, rax#1 is tainted, hence the read operation using MLIL_LOAD_SSA can be considered an OOB read condition. Similarly, consider another case from Thrman::execOVERLOAD_STATUS_REP():
Here again, rax#1 is tainted, hence write operation using MLIL_STORE_SSA can be considered an OOB write condition.
API buffer overflows
Static function hooks are used to detect buffer overflows caused by a lack of validation of arguments passed to functions like memcpy, memmove, etc. Details regarding this are already detailed in the section “Static Function Hooks and Inter-procedure taint propagation” above. Essentially, if any of the interesting parameters of a hooked function are tainted, we log it as a potential vulnerability.
Untrusted pointer dereferences
In some cases, I noticed that MySQL Cluster converts untrusted input to a pointer then dereferences it. To identify this, I relied on Binary Ninja’s type information. The MLIL variable object has a Type property that returns the Type object associated with a variable. A Type object’s type can be accessed using the type_class property. Here the pattern is that the source points to a tainted memory region within a Signal structure, and the destination variable is of type PointerTypeClass. The Type object also has a confidence property, as seen below:
The maximum confidence value for a variable type is 255. To reduce false positives, the analyzer only considers type information having the maximum confidence.
Tainted control flow operations in a loop
Loop termination conditions depending on tainted variables can lead to interesting bugs. Binary Ninja’s MLIL does not provide information on loops, therefore the alternative was to rely on HLIL to detect tainted loop conditions. The HLIL of a loop in Cmvmi::execEVENT_SUBSCRIBE_REQ() looks like the example below:
The trouble here is that we have implemented the entire taint propagation using MLIL, and Binary Ninja does not provide a mapping between MLIL and HLIL. Therefore, even if loops can be detected, the challenge is to know if a tainted MLIL variable maps to a HLIL variable used in a loop condition.
As a workaround, the HLIL instruction has a condition property that fetches the condition statement associated with a loop. The address of this condition statement can be mapped to a MLIL_IF instruction.
Therefore, if any of the MLIL_IF instructions are tainted and are a part of a HLIL loop condition, then the analyzer logs it as a potential bug.
Experiments with Dominance Relationships
A dominance relationship provides information on the order of execution of some basic blocks. A basic block X is said to dominate another basic block Y if all paths to Y should go through X. Let’s take the example from Wikipedia:
In the provided graph, node B dominates the 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 full set of nodes that are dominated by node B is B, C, D, E and F. There is also a related concept called the strict dominator, which does not consider the node in question. Therefore, the set of all nodes that are strictly dominated by node B is C, D, E and F.
Binary Ninja’s BasicBlock object has dominators and strict_dominators properties which provides information regarding dominance relation in a function.
What about using the already available dominance properties in Binary Ninja for handling taint constraints instead of relying on graph reachability algorithms from networkx package?
Mapping constraints to dominator blocks
In order to check if any basic blocks in a def-use chain of an SSA variable are reachable, we can follow the steps below:
• Find all constraint blocks associated with a variable. • Get all the basic blocks that reference the variable using the def-use chain. • For each basic block, check if it is strictly dominated by a constraint block. If yes, the variable is considered validated for that basic block and considered not reachable.
Going back to the same example, the index gets validated in <mlil block: [email protected]> which dominates the <mlil block: [email protected]>. Therefore, by checking a constraint block against dominators it is possible to establish reachability.
False positives with dominators
While the dominance relationship was promising and gives good results, it does give rise to certain false positives. Consider the following CFG, where validation is done in two different program paths:
Here, the index is validated in two different program paths before hitting a potential sink block <mlil block: [email protected]>. However, none of the constraint blocks that perform validation <mlil block: [email protected]> and <mlil block: [email protected]> are dominators. In such cases, since constraint blocks cannot be mapped to any dominators, the potential sink block <mlil block: [email protected]> will be considered vulnerable on read access at address 0x11ba. This is a false-positive result.
The same is the case with the branch_dependence property, which returns a dictionary of branch instruction index and the branching decision taken to reach the instruction. When both the True and False branches dominate the instruction basic block, we do not get information regarding reachability.
A general observation from the scan result is that most constraints are part of dominator blocks. Very few are validated across multiple code paths, producing false positives. Since path-finding algorithms relying on the definition and usage of variables eliminate these false-positive results, I preferred it over dominators. However, the code is still in the repository for experimental purposes.
Notes on Analysis
The target ndbd executable is loaded in Binary Ninja to generate the BNDB analysis database. Then the analyzer is executed against ndbd.bndb for faster analysis:
Though not optimized for speed, the analyzer runs for about 4-5 minutes and returns 195 results. Some of the results are duplicates because a single vulnerability in a helper function might get used by multiple handlers. The analyzer was able to find most of the issues already known as well as a few that were not previously known: ZDI-CAN-15120, ZDI-CAN-15121 and ZDI-CAN-15122. However, there is a high triage cost associated with static analysis results, especially when the target is less familiar. Luckily, my colleague Lucas had already spent a fair amount of time on the codebase making it easier to triage the results.
I hope you have enjoyed this look at using Binary Ninja to find vulnerabilities through taint analysis. In a few days, I’ll be back to discuss using Clang Static Analyzer (CSA) for detecting untrusted pointer dereferences and tainted loop conditions. Until then, you can find me on Twitter @RenoRobertr, and follow the team for the latest in exploit techniques and security patches.
Static Taint Analysis using Binary Ninja: A Case Study of MySQL Cluster Vulnerabilities
Recently, the ZDI received multiple submissions of vulnerabilities in MySQL Cluster. MySQL Cluster is a clustering solution providing linear scalability and high availability for the MySQL database management system. The common attack vector identified in these reports is the open port for the cluster management node and data nodes. Attackers can utilize the protocol and interact with nodes without authentication.
After investigating these submissions, I realized that the code is very buggy, and the pattern of the vulnerabilities is simple. However, the codebase is too large for a manual review. Therefore, the question becomes, “Is it possible to identify all low-hanging-fruit bugs automatically and quickly?” Fuzzing works, but it depends on coverage and cannot precisely focus on a specific type of bug. Taint analysis is probably the more suitable answer for this question.
Two tools are chosen for taint analysis: Clang Static Analyzer and CodeQL. Although they have their own pros and cons, both can lead to positive results. This blog looks at both methods and shows how they can be used for taint analysis against this and other programs.
Here is an example of the kind of low-hanging-fruit bug we are looking for:
The Qmgr::execCM_REGREF function is a registered signal of the QMGR NDB kernel block. These registered signals can be invoked remotely. The signal->getDataPtr() at (1) returns a pointer to a buffer that contains untrusted input from the network. TaddNodeno at (2) is therefore a controlled 32-bit integer from the network, and it is subsequently used as an argument at (3). Finally, at (4) within BitmaskImpl::set, it is used as an array index. Since no validation has been performed on this value, this potentially produces an out-of-bounds (OOB) write.
MySQL Cluster registers around 1,400 signals (the number of calls to addRecSignal()) and around 6,500 accesses on untrusted input (the number of calls to getDataPtr() plus the number of calls to getDataPtrSend() plus the number of direct accesses of theData). Although the example above is not very challenging, the manual review is still very time consuming due to the required scale. It's time to introduce taint analysis.
There are 4 common terms used during taint analysis: SOURCE, SINK, PROPAGATION, and SANITIZER. SOURCE refers to where data originates. In the example above, signal->getDataPtr() at (1) is the SOURCE. SINK refers to where data ends. In the example above, the access of array index at (4) is a SINK. PROPAGATION refers to how the data flows. In our example, the assignment at (2) and the argument copy at (3) are considered PROPAGTIONs. SANITIZER indicates where data is either sanitized or validated. There is no SANITIZER on the above example, and that is the root cause of the bug. The task of taint analysis is to look for a flow from SOURCE to SINK where the flow did not meet SANITIZER during the PROPAGATION. By defining the suitable SOURCE, SINK, PROPAGATION, and SANITIZER, taint analysis should return the types of bugs we seek.
Two taint analysis tools were used to search for these types of bugs: Clang Static Analyzer and CodeQL. The scanning scope of source code is limited to storage/ndb/src/kernel/ only. We will restrict our search to low-hanging-fruit, which we define as two bug types only: (1) buffer overflows in memcpy-like functions and (2) array index OOB accesses. The version of MySQL Cluster we are using for our examples in this blog is 8.0.25.
Clang Static Analyzer
Clang Static Analyzer (CSA) has a checker, GenericTaintChecker, which provides the taint analysis feature. By default, it has a set of pre-defined SOURCE and PROPAGATION values. The default SINK will check some dangerous APIs and arguments, such as format string, command injection, buffer size in memcpy-like function, and so forth. GenericTaintChecker also shares tainted information with ArrayBoundCheckerV2 in order to recognize that the use of a value as an array index is a SINK. Users can also customize some simple SOURCE, SINK, PROPAGATION, and SANITIZER values by providing a config file. If the config file cannot satisfy your requirement, such as for a more complicated semantic, you may have to write a new CSA checker in C++.
Using CSA for taint analysis, we first must let the checker know our SOURCE at (1). The config file cannot define an access to a variable, and writing a new checker would be an unwise expense of effort. Instead, I modified the code base to be analyzed, so that all the accesses of untrusted input have been replaced with something recognized as a pre-defined SOURCE. Some examples are shown as below:
Another untrusted SOURCE is the return of SegmentedSectionPtr in the getSection() function.
The default SINK missed some functions, which can easily be added to the config file as below:
Then, we can scan the project and get the reports using the following commands:
The Makefile2 file specified the target scanning directory:
The reports can be viewed in a browser by running the scan-view command to start up a local web server.
There is some duplication in the output, where multiple reports flag the same line of code. Also, we are interested only in reports that show taints reaching memcpy-like functions and array indexes. In the end, I found approximately 100 interesting reports.
CodeQL also supports taint analysis. It refers to it as taint tracking. There are no pre-defined SOURCEs or SINKs. Users define these with the QL language. We defined our SOURCE and SINK as follows:
Once defined, we can scan the project with the following command line:
A quick cross-check of the scan results against the results from the Clang Static Analysis above showed that CodeQL was missing some bugs. After some investigation, the root cause was that PROPAGATION on some structure field accesses were not being recognized. A similar situation is discussed here, and I enhanced the PROPAGATION as follows:
The generated report became longer, but the number of bugs found was excessive. After reviewing the report, I found that in some cases, validation was being performed by ptrCheckGuard(), arrGuard(), or other bounds checking. SANITIZER can help here to reduce the number. The bounds checking is assumed when there is an if statement that includes >, <, data-preserve-html-node="true" >=, or <=. data-preserve-html-node="true" Make sure that your SANITIZER does not accidentally drop some real bugs before applying this modification.
We then scanned the project again. The scanning can also be done in Visual Studio Code with CodeQL extension. However, some complicated queries are too slow to process and may fail due to memory exhaustion.
Some reports are duplicated at the same line of code. After de-duplicating, the number of interesting reports is around 320. However, the number should be fewer since some of them are still similar or even identical.
After reviewing all the reports, I generated Proof of Concept (POC) manually to confirm each bug. CSA found 28 bugs. A total of 18 of these bugs are array index OOB vulnerabilities and 10 are overflows on memcpy-like functions. CodeQL found 34 bugs. This tool found 21 array index OOB bugs and 13 overflows on memcpy-like functions. Using these methods, we discovered 37 unique bugs, with 25 of them being found by both tools. Only nine of 37 of these bugs overlapped from ZDI submissions, which means 28 are new for us. These numbers not only mean that the taint analysis is useful in this scenario, but also mean that MySQL Cluster has quite a few bugs to be discovered.
Each of these two tools has its pros and cons. By using both Clang Static Analyzer and CodeQL, we can learn from their different feedback and improve the output from each tool. These variances can be compared to the concept of differential testing. The taint propagation provided by either tool has its deficiencies, but can still yield useful results.
The power of these tools could be extended further by adding additional bug classes in SINK. I recommend applying taint analysis to loop counters and pointer dereferences.
Due to the large-scale codebase and simple bug pattern present in MySQL Cluster, taint analysis was quite useful. It identified low-hanging-fruit bugs automatically and quickly. Each tool discussed has its own pros and cons, and we recommend trying more than one tool to get the best results. The difference can be the feedback, which can be used to improve the overall results. Furthermore, we cannot blindly trust the output of either tool and must verify them carefully.
Also, thanks to my colleague @RenoRobertr, who provided feedback and several contributions to this work. He will publish a write-up of additional work on MySQL Cluster soon with his advanced Binary Ninja skills. That blog should be available in a couple of days.
We are looking forward to seeing more submissions of this type in the future. Until then, you can find me on Twitter @_wmliang_, and follow the team for the latest in exploit techniques and security patches.
MindShaRE: When MySQL Cluster Encounters Taint Analysis
It’s the second patch Tuesday of 2022, which means the latest security updates from Adobe and Microsoft are here. Take a break from your regularly scheduled activities and join us as we review the details of their latest security offerings.
Adobe Patches for February 2022
For February, Adobe released five bulletins addressing 17 CVEs in Adobe Illustrator, Creative Cloud Desktop, After Effects, Photoshop, and Premiere Rush. Two of these 17 were reported by ZDI Vulnerability Researcher Mat Powell. The update for Illustrator fixes a total of 13 bugs, the most severe of which could allow arbitrary code execution through either a buffer overflow or an Out-Of-Bounds (OOB) Write. The patch for Creative Cloud Desktop also fixes a single, Critical-rated code execution bug.
The theme of Critical-rated code execution bugs continues with the fix for After Effects. This patch addresses an OOB write bug that exists within the parsing of 3GP files. The issue results from the lack of proper validation of user-supplied data, which can result in a write past the end of an allocated structure. The final Critical-rated patch from Adobe this month fixes a buffer overflow in Photoshop that could allow code execution.
The only Moderate-rated patch this month is the update for Premiere Rush. This patch fixes a bug that exists within the parsing of JPEG images. The issue results from the lack of proper validation of user-supplied data, which can result in a read past the end of an allocated buffer.
None of the bugs fixed by Adobe this month are listed as publicly known or under active attack at the time of release.
Microsoft Patches for February 2022
For February, Microsoft released 51 new patches addressing CVEs in Microsoft Windows and Windows Components, Azure Data Explorer, Kestrel Web Server, Microsoft Edge (Chromium-based), Windows Codecs Library, Microsoft Dynamics, Microsoft Dynamics GP, Microsoft Office and Office Components, Windows Hyper-V Server, SQL Server, Visual Studio Code, and Microsoft Teams. A total of five of these bugs came through the ZDI program. This is in addition to the 19 CVEs patched by Microsoft Edge (Chromium-based) earlier this month, which brings the February total to 70 CVEs.
This volume is in line with February releases from previous years, which (apart from 2020) tend to be around 50 CVEs. What’s more curious about this release is the complete lack of Critical-rated patches. Of the patches released today, 50 are rated Important and one is rated Moderate in severity. It may have happened before, but I can’t find an example of a monthly release from Microsoft that doesn’t include at least one Critical-rated patch. It certainly hasn’t happened in recent memory. Interestingly, Microsoft has chosen to provide some additional explanations of CVSS ratings in this month’s release, but there are still many details about the bugs themselves that are left obscured.
None of the bugs are listed as under active exploit this month, while one is listed as publicly known at the time of release. Last month, Microsoft also initially listed the release as having no active attacks only to revise CVE-2022-21882 two days post release to indicate “Microsoft was aware of limited, targeted attacks that attempt to exploit this vulnerability.” We’ll update this blog should they change their mind this month as well.
Let’s take a closer look at some of the more interesting updates for this month, starting with a significant bug in the Windows DNS Server:
- CVE-2022-21984 – Windows DNS Server Remote Code Execution Vulnerability This patch fixes a remote code execution bug in the Microsoft DNS server. The server is only affected if dynamic updates are enabled, but this is a relatively common configuration. If you have this setup in your environment, an attacker could completely take over your DNS and execute code with elevated privileges. Since dynamic updates aren’t enabled by default, this doesn’t get a Critical rating. However, if your DNS servers do use dynamic updates, you should treat this bug as Critical.
- CVE-2022-23280 – Microsoft Outlook for Mac Security Feature Bypass Vulnerability This Outlook bug could allow images to appear in the Preview Pane automatically, even if this option is disabled. On its own, exploiting this will only expose the target's IP information. However, it’s possible a second bug affecting image rendering could be paired with this bug to allow remote code execution. If you are using Outlook for Mac, you should double-check to ensure your version has been updated to an unaffected version.
- CVE-2022-21995 – Windows Hyper-V Remote Code Execution Vulnerability This patch fixes a guest-to-host escape in Hyper-V server. Microsoft marks the CVSS exploit complexity as High here stating an attacker, “must prepare the target environment to improve exploit reliability.” Since this is the case for most exploits, it’s not clear how this vulnerability is different. If you rely on Hyper-V servers in your enterprise, it’s recommended to treat this as a Critical update.
- CVE-2022-22005 – Microsoft SharePoint Server Remote Code Execution Vulnerability This patch fixes a bug in SharePoint Server that could allow an authenticated user to execute any arbitrary .NET code on the server under the context and permissions of the service account of SharePoint Web Application. An attacker would need “Manage Lists” permissions to exploit this, by default, authenticated users are able to create their own sites and, in this case, the user will be the owner of this site and will have all necessary permissions. This case came through the ZDI, and we’ll have additional details out about it in the near future.
Here’s the full list of CVEs released by Microsoft for February 2022:
Chromium: CVE-2022-0470 Out of bounds memory
access in V8
* Indicates this CVE had previously been released by a 3rd-party and is now being incorporated into Microsoft products.
Looking at the additional remote code execution bugs in this month’s patch release, the updates for HVEC and VP9 video extensions. Microsoft indicates this requires the exploit to be local. However, they also state viewing a specially crafted image file could result in Windows Explorer crashing. If this is the case, it stands to reason the image file could also be hosted on an SMB share, which would make this a remote exploit vector rather than local. The updates for these extensions can be found in the Microsoft Store, so you really only need to verify you have the updated versions unless you are in a disconnected environment.
In addition to those already mentioned, there are nine additional remote code execution-related patches this month. There’s an update for Roaming Security Rights Management Services, but Microsoft offers no information on how an attacker could exploit this vulnerability. There are also no details for the Windows Runtime or the Mobile Device Management bug. If you’re using Windows for MDM, definitely take this update seriously. There are also a couple of open-and-own Office bugs getting fixed. The RCE bugs are rounded out by updates for Dynamics 365 (on-prem) and Dynamics GP.
Speaking of Dynamics GP, there are three patches fixing elevation of privilege (EoP) bugs in the component. Those are three of the 18 EoP patches in this month’s release. This includes an update for the Windows Kernel that is listed as publicly known. The remaining patches are mostly in other Windows components and require a logged-on user to execute a specially crafted program. The other EoP updates that stand out fix vulnerabilities in the Windows Print Spooler. Ever since PrintNightmare, the print spooler has been an attractive target for attackers and researchers alike. Pay special attention to CVE-2022-21999 since it was reported during the Tianfu Cup. Other bugs associated with this contest have been used in active attacks.
Moving on to the Security Feature Bypass (SFB) updates, there are two in addition to the previously mentioned one in Outlook for Mac. The bug in OneDrive for Android requires physical access to an unlocked phone but could allow an attacker to access OneDrive files while bypassing authentication. Really, if an attacker has access to your unlocked Android, this bug is probably the least of your concerns. The SFB for SharePoint is more severe since it could allow an attacker to bypass the blocking of HTTP requests based on IP range.
There are five patches fixing Denial-of-Service (DoS) bugs in this month’s release, and the one for Microsoft Teams stands out. While Microsoft provides no details about the exploit, it does indicate all versions of Teams need an update, including iOS and Android versions. The DoS in Hyper-V server should also be noted as successful exploitation could affect functionality of a Hyper-V host. The DoS vulnerability in .NET affects applications using the Kestrel web server. If you aren’t familiar with it, Kestrel is a cross-platform server within ASP.NET Core and is enabled by default. If you’re using Kestrel as an Internet-facing server, definitely apply this patch to prevent a DoS while handling certain HTTP/2 and HTTP/3 requests.
The February release contains three patches for spoofing bugs. There’s a patch for Azure Data Explorer. To receive the update, you will need to restart the Kusto.Explorer application. Dynamics GP receives an update here that could almost be considered code execution. While the vulnerability is in the web server, successful exploitation could allow malicious scripts to execute in the user’s browser on the target machine. And while spoofing bugs in SharePoint usually mean some form, the bug getting patched this month is different. An authenticated attacker could manipulate a SharePoint page they control to trick targeted users into sending attacker-controlled requests to the server under the permissions context of the target.
The lone Moderate-rated patch this month addresses a tampering bug in the Edge (Chromium-based) web browser.
No new advisories were released this month. The latest servicing stack updates can be found in the revised ADV990001.
The next Patch Tuesday falls on March 8, and we’ll return with details and patch analysis then. Until then, stay safe, happy patching, and may all your reboots be smooth and clean!
Recently, Samba released a patch to address an Out-of-Bounds (OOB) Heap Read/Write vulnerability found in Samba versions prior to 4.13.17. This vulnerability was disclosed at Pwn2Own Austin 2021 by Nguyễn Hoàng Thạch (@hi_im_d4rkn3ss) and Billy Jheng Bing-Jhong (@st424204) of STAR Labs. After the event, Lucas Leong of Trend Micro Zero Day Initiative discovered additional variants of the vulnerability which were disclosed to Samba as part of this fix. This bug was also independently reported to Samba by Orange Tsai of DEVCORE.
This vulnerability allows remote attackers to execute arbitrary code on affected installations of Samba. Authentication is not required to exploit this vulnerability. The specific flaw exists within the parsing of EA metadata in the Samba server daemon (smbd) when opening a file. An attacker can leverage this vulnerability to execute code in the context of root.
Now that the patch has been made available, let’s take a more detailed look at the bugs involved and the patch released to fix them. Much of this information was derived from the white paper submitted by STARLabs as a part of their Pwn2Own entry.
Within Samba, the server daemon that provides the file sharing service is known as smbd. This analysis was conducted on smbd version 4.9.5, which can be downloaded here. While this isn’t the latest version of Samba, there are still quite a few vendors that incorporate this version or prior versions in their products. This was the case during Pwn2Own Austin 2021. Since Samba provides file sharing between devices, it is often enabled by default. The configuration of smbd is found in /etc/samba/smb.conf. Here’s a portion of an smb.conf file showing how Samba would be configured to support a Time Machine share for Apple devices:
In this section, you can see that guest ok = yes is declared, which allows guest authentication. The vfs objects list contains three modules: catia, fruit, and streams_xattr. The bugs we’re concerned with reside in the fruit module, which provides enhanced compatibility with Apple SMB clients. As stated by the vendor advisory, “The problem in vfs_fruit exists in the default configuration of the fruit VFS module using fruit:metadata=netatalk or fruit:resource=file. If both options are set to different settings than [sic] the default values, the system is not affected by the security issue.”
The fruit module that ships with Samba is designed to provide interoperability between Samba and Netatalk. Netatalk is an open-source implementation of the Apple Filing Protocol (AFP). It allows Unix-like systems to serve as file servers for Apple devices. Once a session is established, smbd allows an unauthenticated user to set extended file attributes of a file via SMB2_SET_INFO. This is done by the set_ea function found in “source3/smbd/trans2.c”. The name of the attribute must not be within the private Samba attribute name list, which includes user.SAMBA_PAI, user.DOSATTRIB, user.SAMBA_STREAMS, and security.NACL. With the exception of these attributes, an attacker can set arbitrary extended attributes.
The fruit module handles requests that access a file with the stream name :AFP_AfpInfo or :AFP_Resource. If using the stream name :AFP_AfpInfo, an attacker can open, read, and write Netatalk metadata of a file. Netatalk metadata is stored in a adouble structure, which is initialized by the ad_get/ad_fget functions.
The Netatalk metadata of a file is stored in the value of the extended attribute identified by the name org.netatalk.Metadata. The metadata will be parsed to fill the adouble (AppleDouble) structure. Since org.netatalk.Metadata isn't in the private Samba attribute name list discussed above, an attacker can set an arbitrary value for this attribute. Therefore, it's possible for an attacker to inject malformed metadata values. This can lead to multiple out-of-bounds memory accesses when the adouble structure is later used.
Let’s take a more detailed look at the bugs used to exploit this vulnerability during the Pwn2Own competition.
The fruit_pread function reads metadata of a file. Since our file stream is named :AFP_AfpInfo and the file type is ADOUBLE_META, the function chain fruit_pread_meta -> fruit_pread_meta_adouble will be executed.
Consider the following source code:
At line 4279, the ad_fget function creates an adouble structure containing attacker-controlled data.
At line 4285, the call to ad_get_entry returns the pointer to the ADEID_FINDERI entry. Since this is controllable by the attacker, they can make p point to the last byte of the ad->data buffer. This will cause the memcpy call at line 4300 to read past the end of the allocated buffer and dump up to thirty-one bytes of memory from the heap.
The fruit_pwrite function is used to write metadata to a file. Since we can already control an ADEID_FINDERI entry, we can leverage that to control a memcpy call, which allows us to write up to thirty-one bytes of data to the heap.
Consider the following source code:
At line 4657, the ad_fget function creates the adadouble structure from metadata. As mentioned before, an attacker could inject malformed metadata here and control the values within.
Later at line 4664, the ad_get_entry returns the pointer to the ADEID_FINDERI entry. Since this is controllable by the attacker, they can set p to point to the last byte of the ad->data buffer. This allows the memcpy call at line 4671 to write past the end of the ad->ad_data buffer. Since ad->ad_data is allocated from heap memory, the attacker can leverage this vulnerability to write up to 31 bytes of data past the end of the heap buffer.
When analyzing the bugs used during Pwn2Own, ZDI Vulnerability Researcher Lucas Leong noticed a variant of the vulnerability used at the contest.
In the case of the bugs used during Pwn2Own, Samba fails to validate the ADEID_FINDERI function, which leads to an OOB read and OOB write. Further analysis from Lucas found that Samba does not validate the ADEID_FILEDATESI entry either. This leads to OOB read in ad_getdate and an OOB write in ad_setdate. This leads to an overflow of three bytes, as seen in the code below:
An attacker can possibly leverage this vulnerability to execute code in the context of the smbd daemon.
The source code of the patch for CVE-2021-44142 can be found here. The primary change from the vendor was an update to two areas to mitigate this vulnerability.
First, Samba added the function ad_entry_check_size(), which validates the size of each entry when parsing the AppleDouble format.
Second, Samba added the Netatalk extended attribute AFPINFO_EA_NETATALK to the list of the private attribute name list. Since an attacker needs to set the malformed extended attribute on a file at the beginning stage of this exploit, this change effectively blocks any user attempting to set any Netatalk extended attribute. This is a generic mitigation for this attack vector.
Samba patched this and other bugs on January 31, 2022. They assigned CVE-2021-44142 to cover the bugs discussed in this report. In addition to 4.13.17, Samba 4.14.12 and 4.15.5 have been released to address this vulnerability. The vendor does list removing the fruit VFS module from the list of configured VFS in “smb.conf” as a workaround. However, this will severely impact the functionality of any macOS systems attempting to access the Samba server. Because of this, you should focus on testing and deploying the patch to remediate this vulnerability. It’s also recommended to reach out to any third-party vendors with devices on your enterprise to ensure they have consumed the patch and provided updates to their devices as well. It is expected that many different vendors will need to update the version of Samba they ship with their devices, so expect lots of additional patches to address these bugs.
Thanks again to Nguyễn Hoàng Thạch (@hi_im_d4rkn3ss) and Billy Jheng Bing-Jhong (@st424204) of STAR Labs for participating in Pwn2Own Austin 2021 and demonstrating this bug. At the contest, they won $45,000 from this exploit alone, and a total of $113,500 for the entire event. We certainly hope to see them at future competitions. Until then, follow the team for the latest in exploit techniques and security patches.
CVE-2021-44142: Details on a Samba Code Execution Bug Demonstrated at Pwn2Own Austin