certutil is a build-in tool on windows systems that is used to manage certificates. However certutil could be used to base64 encode/decode, calculate file hashes and download files from the internet. In this blog we will take a look at the artifacts generated by certutil when downloading a file, specifically the metadata file, analyze it's structure and write a parser for it.
In this example we will download a file using certutil and observe the files written to the system. The following command will download mimkatz from github and save it to the current directory (C:\windows\temp):
certutil.exe -urlcache -split -f "https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20200816/mimikatz_trunk.7z" m.7z
After executing the above command we can see in procmon that is writing to two files:
Both files have the same name but on different directories. The file name BC456035A9E2885290EDC953764CC761 is the MD5 hash for the URL UTF-16LE encode:
The file located on C:\Users\u0041\AppData\LocalLow\Microsoft\CryptnetUrlCache\Content\BC456035A9E2885290EDC953764CC761 contains the actual file:
However C:\Users\u0041\AppData\LocalLow\Microsoft\CryptnetUrlCache\MetaData\BC456035A9E2885290EDC953764CC761 contains UTF-16LE encode URL and MD5 hash for the downloaded file in addition to some binary data:
The URL and the MD5 hash can be extracted easily, But what about the header (116 bytes) ? the following summarize my findings:
|-||x00||x0C||byte||Unknown. x70x00x00x00 might be the header length (112 bytes).|
|urlSize||x0C||x04||uint32||The size for the UTF-16LE encoded URL|
|Timestamp||x10||x08||uint64||The last time the file was downloaded in FILETIME format.|
|hashSize||x64||x04||uint32||The size for the UTF-16LE encode hash|
|fileSize||x70||x04||uint32||The downloaded file size in bytes|
|URL||x74||urlSize||UTF-16LE String||The URL from where the file was downloaded|
|MetadataHash||x74 + urlSize||hashSize||UTF-16LE String|
The hash for the downloaded file. The following are some of the hashing algorithms observed during analysis:
In some cases the hash value is empty.
As you can see the metadata file contains a lot of useful information, However there is a lot more data that is unknown (highlighted with red color). I am still researching what that data might be, If you want to help please leave a comment on this blog or send me a DM on twitter @A__ALFAIFI.
I wrote a parser that output the above data in readable format (CSV, JSON or JSONL). You can find it here CryptnetURLCacheParser. The following is the parser output in JSON format: