In a previous , I described how I bypassed the patch for the first fix for CVE-2018-15422. That bypass was also discovered by other researchers as well. You can check that out in Cisco’s .
Now, WebExec was the name given to that first vulnerability by that and . The second vulnerability (a DLL hijacking) was found by several researchers, but gave it the name of WebExec Reloaded (you can check his blog post on WebExec Reloaded ). To continue the tradition of honoring “The Matrix”, I named this third vulnerability WebExec Revolutions.
The WebEx version that fixed the DLL hijacking vulnerability was 220.127.116.11. After that version the application was updated several times over: 18.104.22.168, 22.214.171.124, 126.96.36.1994, 188.8.131.52, 184.108.40.206, 220.127.116.11, 18.104.22.1689, 22.214.171.124, 126.96.36.199, 188.8.131.522, 184.108.40.206 and 220.127.116.11. (18.104.22.168 was the latest version at the time of my first tests) This vulnerability includes all the listed versions, except for 22.214.171.124, 126.96.36.1994, and the 33.9.X versions. All the 33.8.X require a two-stage attack to work. As you’ll see later, version 188.8.131.522 (and later) rendered this attack unusable.
After the release of a patched version, I tested it again to see if the issue had been fixed. After I installed the patched version for the DLL Hijacking vulnerability (184.108.40.206), and was able to prove that the bug was fixed, I got really interested in this update service and I decided to take a look under the hood.
In the previous attack, we used “install” as the first parameter for the service, but if you look at the main function of WebExService.exe, you’ll see that you can also pass “uninstall” or a third value, which could be “WebexService”.
I have renamed the called function to PreDownFParam (the address for the function is 0x403700). That function first extracts the installation path from the registry in order to obtain a full path to the ptUpdate.exe executable. Then it counts the number of passed parameters. Finally, we get to the really interesting part: 0x403A02
In image 3, you can see that the function of interest is DownloadFileParam.
The function takes 5 parameters. The first parameter (int) is checked:
Then it concatenates the value with “/DownloadFile” and all the rest of the parameters. Nnotice the PathQuoteSpacesW function calls!:
Later, it takes the token from winlogon.exe:
And finally runs ptUpdate.exe as SYSTEM with CreateProcessAsUserW using the duplicated token:
After learning all that, I realized I could run something like this…
sc start webexservice WebexService 1 989898 "C:\Users\McFly"
As I did before, I launched a Windows 10 x86-64 VM, with version 220.127.116.11 installed, Process Explorer and Process Monitor running (and logging only File System Activity) and tried the previous command:
Looks like we’ve found something good! The updater is trying to open ptUpdate.xml. Now, I needed to figure out the structure of that file.
To make life easier I connected the VM to the internet, launched the application, and logged in. After a few seconds, a new update message appeared. In that moment, I found out that the application already had downloaded all the files for the new version, and that the current version was 18.104.22.168.
In the temp path for the current user a folder named “ptools” was created, containing inside another folder called “ptools-<GUID>” where <GUID> is a value like “FE456789-2457-3678-2EDF-FFFFFF234568”.
Inside that folder there were a lot of .7z files, along with the file that I needed, ptUpdate.xml:
Our xml is found. Now, another file is requested:
Looking in the “ptools-<GUID>” folder, I found it. One curious thing is that when I tried to open it with 7zip, I noticed that the file wasn’t compressed:
In fact, that file turned out to be a library which is used to decompress the other files of the update. I figured that out by looking the exported functions of the library:
Next, I reverted to the saved snapshot and copied this file to my folder and started again the service:
The file was found this time and was copied to the temp folder of the current user. Since the updater is running as SYSTEM, the temp folder is C:\Windows\Temp.
Other than the above, nothing else happened.
The first thing I needed to know was if the update was working. In order to do that, I needed to copy to my controlled folder all the files that were listed in the xml. I needed to try something else because if the update works, I had no way to confirm it (unless I revert to the snapshot that had the previous version. A thing that was too boring, since I took that snapshot in not a “clean way”).
So, I decided to test a simple trick in order to fool the update mechanism: take the updater itself (ptUpdate.exe) and change it with the one in the previous version. The current version for the binary was 3307.1.1811.1500. My previous version was 3306.4.1811.1600.
I reverted the snapshot, and after copying all the files to my controlled folder, I compressed the previous ptUpdate.exe. I checked the compression settings used to create the .7z file with the current ptUpdate.7z:
That’s “Normal” compression level and “LZMA” compression method in 7zip GUI. The command line for 7z.exe is:
7z.exe a ptUpdate.7z ptUpdate.exe -m0=BCJ -m1=LZMA:d=21
Also, I updated the values of “Size”, “PackagedSize” and “Version” for the new binary in the ptUpdate.xml.
I ran the service again and went to see if the update (and our trick) worked by checking the version of the ptUpdate.exe binary:
I couldn’t believe my eyes: The updater was updated with its previous version!
At this point, knowing that we had an updater that downgrades itself, maybe we could replace it with the version that was vulnerable to DLL Hijacking (version 3306.0.1809.2900)
To test that theory I created a smaller ptUpdate.xml with the same previous data, but only 2 “FileInfo” entries: one for ptUpdate.exe and one for wbxtrace.dll (our previous malicious DLL). Notice that the DLL must have the value “Common” for the “SectionName” tag.
Once again I reverted the snapshot and copied the 3 files to my controlled folder; I took the atgpcdec.dll file from the application’s installation folder, since it’s not compressed, and renamed it to atgpcdec.7z.
But after running the service, I realized that the attack didn’t work…*sigh*
I decided to test again, but this time with the updater version that worked. But this updater was not vulnerable to DLL hijacking, so I checked for another DLL that could be loaded by the updater itself or by another process with SYSTEM privileges. Also, it cannot be any of the DLLs that are signed by Cisco. The answer was the Visual Studio C (VC) runtime DLL: vcruntime140.dll.
Again I compressed the previous, and working, version of the updater. I created another DLL that executes “notepad.exe” on load, but this time I had to add all the exported functions of the VC runtime. Once the xml was updated with the changes, I reverted the snapshot and copied the 3 files into my controlled folder (remember how I mentioned that you can copy the atgpcdec.7z file from the application’s installation folder).
And, after running the service one more time, I got…