Certutil Artifacts Analysis
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.
Analysis
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:
Field Name | Offset | Size | Type | Description |
---|---|---|---|---|
- | 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. |
- | x18 | x4C | byte | Unknown |
LastModificationTimeHeader | x58 | x08 | uint64 | EDIT 1: The file last modification time header from the reponse (Thanks toĀ @mrAn61Ā on Twitter for pointing that out) |
hashSize | x64 | x04 | uint32 | The size for the UTF-16LE encode hash |
- | x68 | x08 | byte | Unknown |
fileSize | x70 | x04 | uint32 | The downloaded file size in bytes |
URL | x74 | urlSize | UTF-16LE String | The URL from where the file was downloaded |
E-Tag | x74 + urlSize | hashSize | UTF-16LE String | The hash for the downloaded file. The following are some of the hashing algorithms observed during analysis: - MD5 - SHA1 - SHA256 - Unkown hash (ex. 57f3c9cf-1514ce)Ā In some cases the hash value is empty. EDIT 1: This is the E-Tag header of the file from the HTTP response. E-Tag is used to identify a specific version of a file, If the file changes then theĀ E-Tag changes. |
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 send me a DM on twitterĀ @A__ALFAIFI.
CryptnetURLCacheParser
I wrote a parser that output the above data in readable format (CSV, JSON or JSONL). You can find it here for the Python versionĀ CryptnetURLCacheParserĀ and hereĀ CryptnetURLCacheParser-rsĀ for the Rust version. The following is the parser output in JSON format:
{
"Timestamp": "2020-09-11T16:53:07.297208",
"URL": "https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20200816/mimikatz_trunk.7z",
"FileSize": 875252,
"MetadataHash": "5abdd836d4458370a804f2974431c993",
"FullPath": "C:\\Users\\u0041\\AppData\\LocalLow\\Microsoft\\CryptnetUrlCache\\MetaData\\BC456035A9E2885290EDC953764CC761",
"MD5": "5abdd836d4458370a804f2974431c993"
}
Edit 1
I have identified a couple of stuff in the metadata structure, the table above is updated to the latest findings. The following is the summery:
- TheĀ MetadataHashĀ field is actually theĀ E-TagĀ header from the HTTP response.
- Another timestamp is recorded which is theĀ LastModificationTimeĀ header from the HTTP response (Thanks toĀ @mrAn61Ā on Twitter for pointing that out).
- Created another parser for this artifact bu in Rust! you can find it hereĀ CryptnetURLCacheParser-rs.