[하루한줄] CVE-2026-49177: Windows TCPIP driver의 Out Of Bounds Read 취약점

URL

Target

  • TCP/IP 10.0.26100.8457 버전

Explain

Windows tcpip.sys는 IPv4/IPv6 TCP/IP 스택의 주요 기능을 구현하는 커널 모드 네트워크 드라이버입니다. NDIS 미니포트 드라이버, 필터 드라이버, WFP, Winsock/AFD 및 기타 네트워킹 구성 요소와 함께 작동하여 애플리케이션과 네트워크 어댑터 사이의 트래픽을 전달합니다.

{
			int32_t* KeyBuffer = *(uint64_t*)((char*)arg1 + 0x10); // [1]
			uint128_t* rsi = *(uint64_t*)((char*)arg1 + 0x38);
			
			if (!Ipv6Global)
			   return 0xc00000bb;
			
			[...]
			
			if (!*(uint32_t*)KeyBuffer || rax_5)
			{
			  memset(rsi, 0, 0x4658);
			  rbx = IppCreateSortedAddressPairsEx(rax_1, KeyBuffer[0xdae], rsi, 
			    &rsi[0x36b], &KeyBuffer[1], KeyBuffer[0xdad], 
			    (char*)rsi + 0x36b4, (char*)rsi + 0x4654);  // [2]
			}

IOCTL 코드가 0x120007인 IRP가 전달되면, 요청 처리 과정에서 IpGetAllSortedAddressParameters 함수가 호출됩니다.

[1] 사용자가 제어할 수 있는 0x36BC 크기의 버퍼keyBuffer 포인터를 가져오고 [2] KeyBuffer 버퍼 값 세 가지를 인자로 IppCreateSortedAddressPairsEx 함수를 호출합니다. 이때, 여섯 번째 인자는 MaxDestCount를 나타냅니다.

int32_t MaxDestCount_1 = MaxDestCount;
int64_t P_2 = 0;
*(uint32_t*)arg4 = 0;
int32_t rbx;

if (!MaxDestCount) // [3]
  rbx = 0;
else
{
  int64_t* rax_1 = IppFindCompartmentById(&Ipv4Global, *(uint32_t*)rdi);
  rsi = rax_1;
  IppQualifyAddresses(rdi, &MaxDestCount_1, keybuf_off4, nullptr); // [4]

  int32_t rax_2;

[3] IppCreateSortedAddressPairsEx 함수에서 MaxDestCount가 0이 아닌 경우, 목적지 주소를 필터링하기 위해 [4] IppQualifyAddresses 함수를 호출합니다. 이때, KeyBuffer의 base 주소 + 4바이트 포인터를 IppQualifyAddresses에 전달합니다.

{
    int32_t* result = MaxDestCount;
    uint64_t MaxDestCount_1 = (uint64_t)*(uint32_t*)MaxDestCount;
                [...]

    if ((uint32_t)MaxDestCount_1)
    {
        char* r8 = (char*)keybuf_off4 + 9;

        do // [5]
        {
            char rcx = r8[-1];

            if (rcx == 0xfe)
            {
                if ((*(uint8_t*)r8 & 0xc0) != 0xc0)
                {
                    if (rcx == 0xfe && (*(uint8_t*)r8 & 0xc0) == 0x80)
                    {
                        r15 = (uint64_t)(uint8_t)r15;

                 [...]
            }

            i += 1;
            r8 = &r8[0x1c];
        } while (i < (uint32_t)MaxDestCount_1);  // [6]
    }

[5] do-while 문을 통해 KeyBuffer 버퍼 내용을 read하며 처음 read하는 위치는 (char*)KeyBuffer + 4 +0x8 이며 0x1c만큼 read하는 위치가 증가합니다.

[6] 하지만 MaxDestCount 값에 대한 검증이 없어 아래와 같이 MaxDestCount 값이 0x1f4 보다 클 경우 out of bound read가 발생합니다.

(0x36bc - 4 - 8) // 0x1c = 0x1f4