vcsjones / AuthenticodeLint

Lints an authenticode signed binary.
MIT License
36 stars 16 forks source link

Smuggling a URL in the MS-DOS stub is not detected #33

Open joshudson opened 2 years ago

joshudson commented 2 years ago

1) make a new MS-DOS stub that is 256 bytes long (we need more room). You will need 16 bit dev tools for this. Message to print should be https://yourdomain.com/phonehome$ and lots of zeros 2) link binary with /STUB to use alternate stub. You can use /emittoolversioninfo:no as well to get the space back. 3) sign binary 4) Watermark binary by appending ?nonce to the URL in the stub and correct PE checksum 5) Profit

Authenticode doesn't even notice something's wrong, nor does authenticode lint. Setting EnableCertPaddingCheck does nothing, as expected.

Incidentally, I find it hilarious from this thread https://developercommunity.visualstudio.com/t/add-linker-option-to-strip-rich-stamp-from-exe-hea/740443 that MS doesn't seem to know this would work.

lennybacon commented 2 years ago

What is the attack vector? Could you provide a repro-(script)?

joshudson commented 2 years ago

@lennybacon To verify, take any signed binary and use a hex editor to change the error message "This program cannot be run in DOS mode" to something else and observe the signature is still valid.

The reason is the same as https://github.com/vcsjones/AuthenticodeLint/blob/main/AuthenticodeLint/Rules/10009-NoUnknownUnsignedAttibuteRule.cs ; binary can be watermarked without disturbing signature.

Program would do

int main(int argc, char **argv)
{
    /* Opening the file again is kind of kludge. The DOS header actually is in memory but it's annoying to get its address */
    char url[192];
    FILE *me = fopen(argv[0] /* windows always gives a full path here */, "rb");
    fseek(me, 48);
    fread(url, 192, 1, me);
    for (int i = 0; i < 192; i++)
        if (url[i] == '$') {
            url[i] = 0;
            break;
        }
     CURL *curl;
     CURLcode res;

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url); /* upload watermark to server */
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    /* Continue */
}
lennybacon commented 2 years ago

@joshudson Thanks for the explanation!

The spec says the digest for the signature is created as follows.

The Win32 ImageGetDigestStream function supports several methods to compute a PE file's hash value. Authenticode uses only one of these methods. The procedure for calculating the image hash value is described later in this section. It is a simplified version of the procedure performed by ImageGetDigestStream and calculates the correct hash value for almost all Authenticode-signed PE files. To summarize, the hash calculation procedure includes: • Hashing the PE Header, omitting the file's checksum and the Certificate Table entry in Optional Header Data Directories (Steps 3 through 7). • Sorting and hashing the PE sections (steps 8 through 13). • Omitting Attribute Certificate Table from the hash calculation and hashing any remaining data (steps 14 and 15). https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx

Which looks like it is by design. On the other hand the specification continues with:

Figure 1, in “Introduction,” provides a visual representation of the PE format and shows which PE objects are excluded from the Authenticode hash value calculation. The hash value calculation omits these parts of the PE file because they are modified by the act of adding an Authenticode signature to the file. If the hash calculation did not omit these parts of the file, signing the file would change the file's hash value and invalidate the Authenticode signature.

Where the "Figure 1" is:

image

And this DOES NOT show the "MS-DOC 2.0 Section" with a gray background.

The ImageGetDigestStream could be fed with a DigestFunction which will then have access to the stream to be hashed. Would be an option to validate which parts of the file are actually used for the digest.