A lot of blog posts I have read go over interesting vulnerabilities and exploits but do not typically share the process behind discovery. I want to show how sometimes just manually poking around can quickly uncover vulnerabilities you might miss with other approaches to vulnerability discovery.
In my previous blog, I highlighted a tool named IO Ninja and shared why it is helpful when working with Inter-Process Communications (IPC). In this blog, I would like to show you how this tool helped me find two vulnerabilities: CVE-2021-4198 and CVE-2021-4199 in Bitdefender’s antivirus software on Windows. The exploit I wrote targets a named pipe used by the Vulnerability.scan.exe process. The first vulnerability results in a denial-of-service on almost any process within the AV. The second results in local privilege escalation by exploiting a link following issue.
Now you might be thinking, wait a minute… how does a tool that lets you communicate with named pipes allow you to find a link following vulnerability? That is what we are going to dive into next.
The pipelist tool from Sysinternals reveals that Bitdefender uses several pipes for IPC.
Figure 1 – Output of the pipelist utility from the Sysinternals tool suite.
bdservicehost.exe is one of the executables that runs as SYSTEM after installing Bitdefender. It uses these pipes to communicate with other processes on the system and might be an interesting target.
Figure 2 – List of named pipes used by bdservicehost.exe
Using IO Ninja, we can spawn a pipe server as our standard user to see if we can trigger a connection from the client. Without reading any code, we can poke around the agent GUI to see what IPC connections are being created and what the traffic looks like.
Figure 3 – Bitdefender Total Security GUI
The screenshot below shows that we receive a connection from the client of the pipe that sends data to our named pipe server every time we open the agent GUI. This can be done by double clicking the Bitdefender icon in the system tray or opening it from the start menu.
Figure 4 – Connection from client to our named pipe server
What is interesting here is that the connection remains open. This allows us to send data back to the client. I took the first 16 bytes of data that was being sent to the server and echoed it back to the client multiple times to see if anything interesting would happen. I was also looking to see if the pipe connection would remain open after sending the data.
Figure 5 – Pipe client disconnects after sending data to it
After sending several messages, the client disconnects, and we get a popup box from Bitdefender informing the user that something went wrong within the AV. Take note of the “x” at the top right for dismissing the dialog box. This will become relevant later.
Figure 6 – Bitdefender telling us that we broke something.
After seeing this message, I knew that debugging information in some shape or form must be getting saved or logged. I fired up Process Monitor from Sysinternals to see if a crash dump file, which I can further analyze in a debugger, was created.
As it turns out, an executable named “BDReinit.exe”, which is Bitdefender’s own crash handler, produces a crash dump file for us on the system.
Figure 7 – Process Monitor showing crash dump files being created by BDReinit.exe.
Another interesting discovery here was finding out that the folder to which the .dmp file is being written to is readable and writeable by standard users.
Figure 8 – Permissions of the directory storing the dump files.
Unfortunately, after looking at the dump file, I concluded the crash alone was not very interesting, and the process being crashed runs as our current user. At this point, I knew I had a potential local DoS on the AV but there had to be more to chew on here.
Figure 9 – NULL pointer dereference: CVE-2021-4198
After crashing this first process “seccenter.exe,” which is Bitdefender’s main GUI interface, I realized that I was still getting connections to my named pipe server. I was able to crash almost any process related to the AV by simply spamming the incoming pipe connections with those 16 bytes as soon as a client connected. I sat in front of my computer, watching the AV processes fall like dominos one after the other in process explorer.
I knew that kicking off a “Vulnerability Scan” in the GUI would spawn vulnerability.scan.exe, which ran as SYSTEM. I quickly tried to see if I could also crash this privileged process.
Figure 10 – Process Monitor showing crash dump files being created by BDReinit.exe, this time running as SYSTEM.
Ahh, the same “BDReinit.exe” process runs again, but this time it runs as SYSTEM. Based on the file name of the dump, we know we can also crash “Vulnerability.scan.exe,” and it writes the dump to disk as SYSTEM.
When looking for link following vulnerabilities, there are a few directories that are of immediate interest.
I often look for privileged file writes and delete operations in these directories.
In this case, a .dmp file is being written to this directory as SYSTEM when a highly privileged process that is part of the AV crashes. This alone is not very interesting as we do not control the contents of the dump being written, and it’s the same exact crash from before.
I further analyzed the Process Monitor log and discovered that “BDReinit.exe” was doing two very dangerous things. First, it was writing a very permissive DACL to a file with a predictable name in a different directory. This directory also allowed a standard user read and write access, and the DACL write happened every time a crash occurred.
Figure 11 – Read and write access for everyone
The permissive DACL would get written to this file as SYSTEM if you crashed a process running as SYSTEM within Bitdefender. In this case, I just chose to again crash “Vulnerability.scan.exe” because of how easy it was to trigger. All I had to do was kick off a vulnerability scan in the GUI, and I would get a connection to my named pipe server from this process.
Figure 12 – Kicking off a vulnerability scan
Figure 13 – BDReinit.exe ACL write after crashing Vulnerability.scan.exe
One of my favorite parts about logic bugs like this is that exploiting them is typically very quick and easy. All we need to do to escalate to SYSTEM is redirect the permissive DACL write to a DLL used by the system, modify the contents of that DLL, and then have it get loaded. To do this redirection we just need one symbolic link and a target DLL.
One great candidate for the job is:
This is because a standard user can easily trigger a print job which will force svchost.exe to load our modified DLL as SYSTEM.
Figure 14 – Creating Symbolic link
Figure 15 – Redirecting BDReinit.exe DACL write
Figure 16 – Svchost.exe Loading modified DLL
Putting this all together, the following screenshot demonstrates executing code at SYSTEM using the techniques described.
Figure 17 – Putting it all together
The second major issue I found was related to the crash dump itself. If you clicked the “x” at the top right of the popup box I showed earlier, “BDReinit.exe” or “BdSubWiz.exe” which is the submission wizard, would delete the crash dump as your current user. If the user waited or ignored it for a while, the dialog box would timeout and delete the dump file as SYSTEM if the process that crashed was running as SYSTEM!
Figure 18- Log of BDReinit.exe arbitrary file deletion PoC
In the above screenshot, you can see how we can redirect this highly privileged file deletion to any file on the system. You can also use the techniques described in this blog to achieve privilege escalation and execute code at SYSTEM. Again, this is because the crash dump was being written and deleted from a location that our standard user had read and write access to regardless of the user that was running the crashed process. Furthermore, the files in that folder were not protected at all, so deleting them and replacing one with our link before the timeout was not an issue.
Figure 19 – Unrestricted file permissions
Sometimes vulnerability discovery isn’t super methodical and that’s okay! I did not spend any time reversing the functions responsible for IPC in this application to figure out what data to send over the pipe. However, I identified an attack surface and started poking around. This led me to an entirely different attack surface where there were some critical vulnerabilities.
I hope this blog inspires and enables you to do the same with your targets. Furthermore, I hope it reminds you to look at custom crash handlers and their dialog boxes – both for bugs and to make sure you aren’t unintentionally giving away your research. 😀
Below is a Procmon filter I use that you can download and import to search for link-following vulnerabilities. Just be sure to either change your username to “lowpriv,” or edit the filter before you use it. You can download it here.
Keep an eye out for future blogs where I will share details on other vulnerabilities I have found. Until then, you can follow me @izobashi and the team @thezdi on Twitter for the latest in exploit techniques and security patches.
– IO Ninja
– Symboliclink Testing Tools
Zero Day Initiative – Blog