Last time, we talked about MS12-024 (CVE-2012-0151), which states that a vulnerability in the way WinVerifyTrust operates could allow an attacker to modify a signed executable so that it runs arbitrary code, but the signature remains verifiable. We now give more details on the patch for Windows XP SP3.
Looking at the files changed by the patch, we see that we only have 2 files to analyze: wintrust.dll and imagehlp.dll. We run the patch through the command prompt, using the /x switch, so as to simply extract the embedded files and not to install them. The directory of interest is SP3GDR, as the files in it contain only security patches (i.e., they don’t contain any other changes that may have been made by Microsoft, like the files in the SP3QFE directory do). The version information for the patched files and the files currently installed is this:
- wintrust.dll: Current: 5.131.2600.5922. Patch: 5.131.2600.6198.
- imagehlp.dll: Current: 5.1.2600.5512. Patch: 5.1.2600.6198.
A simple binary comparison between the wintrust.dll files shows that, excluding timestamps, checksums and version information, the two files are virtually the same, other than 20 (16 + 2×2) unaccounted for bytes. These 20 bytes might be of some significance, otherwise there was really no point in replacing wintrust.dll.
Moving on to imagehlp.dll, we can see more substantial differences:
DllMain simply makes sure that each loaded instance of the DLL starts with fresh markers for invalid certificates (more on that later). ImageGetDigestStream, ImageGetCertificateHeader, ImageRemoveCertificate and ImageGetCertificateData simply add another parameter to the call to FindCertificate. The new FindCertificate gets an additional parameter, a boolean flag, which indicates whether the size of the output buffer provided is bigger than 8 bytes.
The real changes were made to the functions ImageEnumerateCertificates and FindCertificate. We detail these changes below. As a side note, in the process of understanding what the patch does, a possible buffer overflow and a memory leak were found. And then you wonder…
ImageGetCertificateData
A check was added. Errors reported by the new check function, subCheckCertsLocation_76C9A779:
- The certificate directory’s RVA + size overflows.
- The certificate directory is not the last thing in the file.
- The sections’ start RVA + sections’ size overflows or is more than the file’s size.
- numSections == 0 and the certs dir’s RVA < the sections' start RVA (i.e., it overlaps with the headers).
- One of the sections contains a null pointer to raw data.
- One of the sections’ ptr to raw data + raw data size overflows.
- One of the sections’ ptr to raw data + raw data size exceeds the file’s size.
- The certificate directory starts before one of the sections ends.
Basically, the check is that the certificate directory is last, and that it doesn’t overlap with a section or with the headers.
FindCertificate
First, FindCertificate calls the same check routine, subCheckCertsLocation_76C9A779. If the check fails, FindCertificate returns with an error.
As mentioned earlier, FindCertificate gets an additional parameter, blOutputSizeCheck, that is set to 1 (true) if the length of the output buffer (provided to ImageGetCertificateData, for example) is bigger than 8 bytes, or set to 0 (false) otherwise. If the flag is false, FindCertificate continues normally. However, if the flag is true, an additional check is performed, and what an interesting check it is…
It appears that Microsoft decided that several values (called markers) are not allowed inside a WIN_CERTIFICATE structure representing an Authenticode signature. We can only deduce two things out of this:
- Valid certificates can suddenly, and with no good reason, become invalid. The worst case happens when one of the markers is found inside a company’s public key, and then the company has a real problem (though the chances of that happening are pretty slim).
- Microsoft probably came to one of these conclusions (or to both of them):
- It might be the case that this vulnerability is exploited in the wild (contrary to published material, even by Microsoft).
- The vulnerability can’t really be closed due to design choices and algorithms that can’t be changed, and so Microsoft must try to specifically invalidate certificates that try to exploit this vulnerability. This might mean there’s some room for exploitation, even after the patch is applied.
So it all boils down to what’s in the markers array. To initialize the markers array, a search in the registry is performed. The key is HKLM\Software\Microsoft\Cryptography\Wintrust\Config, and the value is PECertInvalidMarkers. If the key doesn’t exist (as is probably the case), default values are used to populate the markers array. By default, there are 50 different markers, virtually all of them denote an invalid certificate (as per Microsoft). To decide that a certificate is invalid, it’s enough to find a single marker anywhere within it. For each marker, the short form of the marker (by default, 4 bytes) is looked for in the certificate. If it’s found, that point in the certificate is matched against the real, full marker. If there’s a match, the WIN_CERTIFICATE structure is considered invalid. If no marker was found, FindCertificate continues as usual.
Here’s a list of the default (short) markers (the bytes appear as they do in the file, i.e., this is big-endian):
|
1 2 3 4 5 6 7 8 9 10 11 12 |
DWORD dwShortMarkers[50] = {
0x504B0102, 0x504B0506, 0x504B0304, 0x504B0708, 0x52617221
0x7ABCAF27, 0x2A2A4143, 0x213C6172, 0x4D534346, 0xEFBEADDE
0x496E6974, 0x7A6C621A, 0x4B47425F, 0x4B474232, 0x4B474232
0x454E4300, 0x6469736B, 0x3E2D1C0B, 0x49536328, 0x536D6172
0xAE014E61, 0x3B214049, 0x45474741, 0x41724301, 0x53747566
0x2D737178, 0x504B090A, 0x220B010B, 0x2D6C6830, 0x2D6C6831
0x2D6C6832, 0x2D6C6833, 0x2D6C6834, 0x2D6C6835, 0x2D6C6836
0x2D6C6837, 0x2D6C6838, 0x2D6C6839, 0x2D6C6861, 0x2D6C6862
0x2D6C6863, 0x2D6C6864, 0x2D6C6865, 0x2D6C7A73, 0x2D6C7A32
0x2D6C7A33, 0x2D6C7A34, 0x2D6C7A35, 0x2D6C7A37, 0x2D6C7A38
}; |
Some notable markers include 0xEFBEADDE (i.e., 0xDEADBEEF in little-endian), “KGB2″, “Initializing Wise Installation Wizard”, “PK” (+ version), “Rar”, “**ACE**”, “NanoZip”, “StuffIt!”, “-lh?-” (where “?” is a hex digit, excluding F), and “-lz?-” (where “?” is a decimal digit between 2 and 8, inclusive). You get the point.
Some Other Things
The Microsoft Authenticode Portable Executable Signature Format specification might have you believe that the file’s digest is computed using ImageGetDigestStream from imagehlp.dll. If you check what ImageGetDigestStream does, you’ll come to the conclusion that this is not the case (alternatively, just set a breakpoint there and see that it’s never called when validating a PE’s Authenticode information).
In fact, the real function that computes the PE’s digest is imagehack_AuImageGetDigestStream in wintrust.dll. This function also has some checks in place, even in the unpatched version (the patched DLL doesn’t modify this function). The function checks that the certificate directory doesn’t overlap with any section or with the header, that it’s the last thing in the file, and that the certificate directory’s size is not “negative” (that is, overflows a DWORD when added to the directory’s virtual address). If all the checks pass, the checksum, certificate directory info (VA + size) and the certificate directory itself are masked out, and the entire file is hashed.
I hope this gives you enough information to try and exploit MS12-024. Good luck!



Check this out:
Injecting custom payload into signed Windows executables – Analysis of the CVE-2012-0151 vulnerability
http://recon.cx/2012/schedule/events/246.en.html
Thanks. Read it when they twitted about it several weeks ago.