Saturday, September 21, 2019

The Time I Chased a Cab (File): Zip Slip and Certificate Cloning

While doing research for a pretty large and complicated thick client assessment recently, I ended up diving down a rabbit hole involving cabinet files (.cab) as I noticed the application performing some interesting sequential functions.

In a nutshell, the application would do the following with elevated processes:
  1. Retrieve a cab file
  2. Extract the cab file
  3. Run an application-specific executable 
This blog entry will focus on two different aspects of cabinet files that aided in exploiting the above functionality to spawn a reverse shell:
  • Susceptibility to 'Zip Slip'
  • Cloning cab file certificates

What is a .cab file?

A .cab file, short for 'cabinet' file is a special archive format for Windows. They are often used for updating applications, system drivers, and other fun stuff.[1]

Hacker mentality 101: "What would happen if..."

While I had absolutely no knowledge about these files, as soon as I saw 'archive', spidey senses started to tingle and I started to wonder if cab files could be susceptible to "Zip Slip"[2]: arbitrary file writes due to archive extraction typically associated with zip files.

I did not see any explicit reports of cab files being affected by this vulnerability, so I decided to give it a shot and created a test cab file to see if this was possible.

I created a new cab file using lcab[3], which contained a valid file name as well as file that had a directory traversal as the file name.
Investigating the code of the thick client, I found that it was using a DLL called "Microsoft.Deployment.Compression DLL", which I discovered is part of the WiX Toolset by FireGiant.

Analyzing the function for extraction, I  saw that it takes the full file name and simply concatenates it with the destination path. As there is no sanitization or validation occurring, a file named with a directory traversal string (like I generated) should theoretically be extracted to the path indicated in the directory traversal.

// Microsoft.Deployment.Compression.ArchiveInfo
// Token: 0x0600002C RID: 44 RVA: 0x00002700 File Offset: 0x00001700
public void Unpack(string destDirectory, EventHandler<ArchiveProgressEventArgs> progressHandler)
{
 using (CompressionEngine compressionEngine = this.CreateCompressionEngine())
 {
  compressionEngine.Progress += progressHandler;
  compressionEngine.Unpack(new ArchiveFileStreamContext(this.FullName, destDirectory, null)
  {
   EnableOffsetOpen = true
  }, null);
 }
}

I took the code that was hypothesized to be vulnerable and created a basic C# application to perform an extraction test.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Deployment.Compression;
using Microsoft.Deployment.Compression.Cab;


namespace CabSlip
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("Usage: <cab file> <dst dir>");
                return;
            }
            Console.WriteLine("Cab extraction test for zip slip.");

            string fileName = args[0];
            string destination = args[1];

            Console.WriteLine("Extracting " + fileName + " to " + destination);

            new CabInfo(fileName).Unpack(destination);            
            

        }
    }
}

After running this in conjunction with my malicious cab file, I confirmed that it was indeed susceptible to Zip Slip.


Switching back to the thick client, I put some breakpoints in dnSpy so I could swap in my malicious cab file to verify that this could be replicated, and after continuing code execution--it worked--the cab file was extracted and I successfully wrote a file to C:\windows\system32.

The vulnerability in the DLL was reported to FireGiant, and it has been remediated as referenced in CVE-2019-16511.[4]

Rain falling on the parade

This was when I started to get quite excited that I might have something interesting to play with, but when I tried to have the application run through everything without any breakpoints set, my cab file was being rejected.

To my dismay, multiple protection checks were put in place to ensure the integrity of the cab file that was going to be extracted was maintained:
  • Digital signature verification
  • Certificate authority chain validation
  • CN name check on certificate
The checkpoint that hurt the most was the chain validation as this was from a X509 Windows API call that was reaching out for several confirmations that the chain was valid and the certificate was not revoked.

While Sigthief [5] exists for cloning signatures and injecting them into portable executables, no methods or tools existed for doing the same for cab files, and I wasn't ready to give up on this exploit chain just yet, so I decided it was time to explore how cab files are constructed at the byte level to see if cloning the signature was possible.

Forging Certificates 

Luckily, certificates are just appended to the end of the actual cab file data, and by reading the documentation on how cab file headers are constructed, I discovered that it was possible to clone certificates onto cab files by switching byte values in the header.

By calculating offsets to data and cloning certain special bytes from the cab file whose certificate is the target, the header can be reconstructed to fit the data of a new, malicious cab file.

Example cab file header:
While I will not go into the full nitty-gritty on each and every byte that needs to be cloned and/or modified (Feel free to read the documentation and my tool comments though for a bit more information!), the labeled portions are most of the key areas that need to be calculated or cloned from the original source cab file.

A.  Offset to certificate data
B.  Length of the file included in the archive
C.  Extra data flag, which indicates there is a certificate at the end
D.  Start of data
E.  Check sum (in most cases this can be arbitrary)
F.  Size of uncompressed and compressed data in the archive. (This has a maximum of 0x8000, and when a file is bigger than this, the file is chunked, and this value is an offset to the next chunk.)

With the above in mind, I developed the "Cab Cloning Factory" tool which allows for the cloning of cab file certificates.

Github link:
https://github.com/Keramas/CabCloningFactory

This allowed me to create a cab file with a reverse shell payload that bypassed all of the certificate protection checks mentioned in the previous section, and ultimately get a shell with elevated privileges by overwriting the executable that would subsequently be executed after the cab files extraction process completed.

Conclusion

This came about due to my stubbornness to not give up on exploiting what I found. Spending a sleepless night or two for research and development to get this going was well worth it. It was a lot of trial and error, and while the generic cloning tool is not quite 100% yet, I hope others take a look and find it useful. I am curious to see how many times I run into cab files moving forward...

With all of that said, the takeaway is that signature and certificate checks are not a panacea for ensuring data integrity, and this should be kept in mind for applications using these types of validations for protection.

References:

[1]https://en.wikipedia.org/wiki/Cabinet_(file_format)
[2]https://snyk.io/research/zip-slip-vulnerability
[3]http://manpages.ubuntu.com/manpages/bionic/man1/lcab.1.html
[4]https://www.firegiant.com/blog/2019/9/18/wix-v3.11.2-released/
[5]https://github.com/secretsquirrel/SigThief

Vulnerability disclosure timeline:

Disclosure to Firegiant for WiX Toolset - 8/23
Received reply from Firegiant - 8/23
Vulnerability remediated by FireGiant and publicized - 9/18
WiX Toolset vulnerability confirmed as CVE-2019-16511 - 9/18






Powered by Blogger.