SEC760 Patch diffing

During the SEC760 course, we're asked to patch diff an old IPV6 MS14-006 vuln which is a DDOS impacting IPV6 on Windows 8. The security bulletin can be found [here](https://learn.microsoft.com/en-us/security-updates/SecurityBulletins/2014/ms14-006?redirectedfrom=MSDN) . This was a pretty old patch and the Intra-Package Delta files require that you have the previous kernel files. I didn't want to spend time installing windows 8 in a VM so I thought I'd look at CVE-2024-38063 which is also an IPV6 DDOS but on windows 11 and for which MalwareTech did a nice [write-up](https://malwaretech.com/2024/08/exploiting-CVE-2024-38063.html). These are mostly my notes from this experience. If you want to know more about this vuln, reading the belowis probably a bad idea and you'd be better served reading the blog Malwaretech wrote.

I pulled the tcpip.sys file from https://winbindex.m417z.com/?file=tcpip.sys for KB5041585

I wanted to get a nice diffing experience so I thought I'd diff it against the previous version of the file on windbindex. So I diffed: 10.0.22621.3958 hash:

7cfb330c436cf064755961a3ed4f304148a2af19d325ef30a91f217958de55e7

with: 10.0.22621.4036

a97b657e0a6c89e8f49dbc59f99fa66242b6b3e20b2c90c2800b9fe33823675e

Opening this up in Bindiff, we quickly get similar results to MalwareTech. One function really differs: IPV6pProcessOptions. The graph view shows two new basic blocks added to the bottom of the function:

We quickly see in the above that the updated function now performs a check before calling IppSendErrorList. We now call Feature_1223761209__private_IsEnabledDeviceUsage which according to MalwareTech is something Microsoft adds to check a global flag and roll back a patch if needed.

 if ( !(unsigned int)IppDiscardReceivedPackets((unsigned int)&Ipv6Global, v6, a1, 0, 0i64, 0, v7) && v1 )
  {
    v27 = Feature_1223761209__private_IsEnabledDeviceUsage();
    LOBYTE(v28) = 4;
    LOBYTE(v29) = 1;
    v30 = _byteswap_ulong(v8);
    if ( v27 )
      IppSendError(v29, (unsigned int)&Ipv6Global, a1, v28, v4, v30, v3);
    else
      IppSendErrorList(v29, (unsigned int)&Ipv6Global, a1, v28, v4, v30, v3);
  }
  return v6;
}

Then we either call IppSendErrorList (old code) or IppSendError (new patched code).

We can look at IppSendErrorList and rename it's args in IDA:

__int64 __fastcall IppSendErrorList(
    char      errorType,
    int       errorCode,
    _QWORD   *errorListHead,   
    char      flagA,
    char      flagB,
    int       extraValue,
    char      flagC)
{
    _QWORD *currentNode = errorListHead;
    __int64 result = 0;

    // Traverse linked list
    while (currentNode)
    {
        result = IppSendError(
            errorType,
            errorCode,
            (unsigned int)currentNode,
            flagA,
            flagB,
            extraValue,
            flagC);

        currentNode = (_QWORD *)*currentNode;  // move to next node in list
    }

    return result;
}

I didn't really go any further than this because I didn't have the right kernel version to go as far as Marcus and debug what was going on. From this point, if I was taking this further and had a lab set-up, I'd go ahead and spam packets with IPV6Options; Marcus goes into more detail as to how this quickly fills up the list in IppSendError.

Last updated