Skip to content
KitploitKITPLOIT
도구블로그
Log in
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2024-20698 — 취약점 분석 | Kitploit
도구/GitHubGitHub/romanrybachek/cve-2024-20698
Vulnerability AnalysisCode AnalysisExploitationReverse EngineeringBinary Analysis
GitHubromanrybachek/cve-2024-20698

CVE-2024-20698

취약점 분석

저장소 보기
517132년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2024-20698

이 취약점에 대해: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-20698

패치 분석

ntoskrnl.exe 에는 두 개의 패치된 함수가 있습니다: sub_1406AE224 및 WbAddLookupEntryEx. 취약한 함수는 WbAddLookupEntryEx입니다. 이 함수에 대한 경로:

그림

이 함수를 호출하려면 첫 번째 인수 0xb9와 함께 NtQuerySystemInformation을 호출해야 합니다. 사용자가 두 번째 인수로 제공하는 버퍼의 첫 번째 바이트는 이 switch의 옵션입니다:

switch ( first_byte_in_usermod_buf )
{
    case 1:
      status_1 = WbDecryptEncryptionSegment(item, copy_of_usermod_buf, NumberOfBytes_1);
      goto set_status_and_return;
    case 2:
      status_1 = WbReEncryptEncryptionSegment(item, copy_of_usermod_buf, NumberOfBytes_1);
      goto set_status_and_return;
    case 3:
      status_1 = WbHeapExecuteCall(item, copy_of_usermod_buf, usermod_buffer, NumberOfBytes_1);
      goto set_status_and_return;
    case 4:
      if ( !copy_of_usermod_buf )
      {
        status_1 = patched_case4_no_user_buffer(item, another_item);
set_status_and_return:
        status = status_1;
        goto return;
      }
      break;
    case 5:
    case 6:
      status = usermod_buffer != 0i64 ? STATUS_NOT_IMPLEMENTED : STATUS_INVALID_PARAMETER;
      goto return;
    case 7:
      status_1 = WbRemoveWarbirdProcess(item->proc_handle);
      goto set_status_and_return;
    case 8:
      status_1 = WbProcessStartup(item, copy_of_usermod_buf, NumberOfBytes_1);
      goto set_status_and_return;
    case 9:
      status_1 = WbProcessModuleUnload(item, copy_of_usermod_buf, NumberOfBytes_1);
      goto set_status_and_return;
}

인수 0xb9와 함께 NtQuerySystemInformation을 사용하는 각 프로세스에 대해, 프로세스가 종료될 때까지 메모리에 저장될 구조체가 생성됩니다. 저는 이 구조체를 item_instance라고 명명했습니다. 먼저, sub_1406AF294 함수가 다른 유사한 구조체들 중에서 해당 프로세스의 구조체를 찾으려고 시도합니다. 이 구조체에 대한 포인터들은 프로세스 ID 순서로 메모리에 저장됩니다. 구조체가 발견되지 않으면 WbCreateWarbirdProcess에 의해 생성됩니다. 그런 다음 이 구조체에 대한 포인터는 취약한 WbAddLookupEntryEx를 사용하여 배열에 추가됩니다.
패치 전 WbAddLookupEntryEx의 코드:

NTSTATUS WbAddLookupEntryEx(
        items_info *items_info,
        __int64 new_item_pointer,
        __int64 not_used,
        unsigned int new_item_index)
{
  unsigned int last_item_index;
  NTSTATUS status;
  unsigned int old_items_count;
  unsigned int size_of_item;

  last_item_index = items_info->last_item_index;
  status = 0;
  old_items_count = items_info->old_items_count;

  if ( last_item_index + 1 >= old_items_count )
  {
    status = WbReAlloc(
               items_info->vuln_buffer,
               old_items_count * items_info->size_of_item,
               items_info->size_of_item * (old_items_count + items_info->count_of_new_items),
               &items_info->vuln_buffer);

    if ( status < 0 )
      return status;

    items_info->old_items_count += items_info->count_of_new_items;
    old_items_count = items_info->old_items_count;
    last_item_index = items_info->last_item_index;
  }

  if ( new_item_index > last_item_index || !old_items_count )
    return STATUS_INVALID_PARAMETER;
  memmove(
    (char *)items_info->vuln_buffer + (new_item_index + 1) * items_info->size_of_item,
    (char *)items_info->vuln_buffer + new_item_index * items_info->size_of_item,
    items_info->size_of_item * (last_item_index - new_item_index));

  size_of_item = items_info->size_of_item;
  ++items_info->last_item_index;
  *(_QWORD *)((char *)items_info->vuln_buffer + new_item_index * size_of_item) = new_item_pointer;
  return status;
}

포인터 배열을 재할당하고 새 포인터를 삽입합니다.

패치는 다음과 같은 보안 검사를 추가합니다:

status = RtlULongMult(old_items_count, items_info->size_of_item, &size_of_old_items);
if ( status < 0 )
  return status;
status = RtlULongAdd(old_items_count, items_info->count_of_new_items, &sum_result);
if ( status < 0 )
  return status;
status = RtlULongMult(sum_result, mb_item_size, result_size_8byte);
if ( status < 0 )
  return status;

이로 인해 덧셈과 곱셈 연산이 오버플로우에 대해 안전해집니다. 따라서 패치되지 않은 버전에서는 다음 경우에 정수 오버플로우가 발생할 수 있습니다:

  • old_items_count * size_of_item > 0xffffffff
  • old_items_count + count_of_new_items > 0xffffffff
  • (old_items_count + count_of_new_items) * size_of_item > 0xffffffff

정수 오버플로우 후 포인터 배열이 재할당되지만, 더 작은 크기로 재할당됩니다. 그런 다음 memmove가 새 요소를 위한 공간을 만들기 위해 요소들을 이동시키려고 시도합니다. 따라서 새로 할당된 청크 뒤에 있는 청크들이 손상됩니다. 정수 오버플로우를 트리거하려면 0xffffffff / size_of_item + 1 개의 구조체를 생성해야 합니다. size_of_item은 항상 8입니다. 따라서 0x20000001 개의 구조체를 생성해야 합니다. 각 구조체는 하나의 프로세스를 나타냅니다. 따라서 0x20000001 (536870913) 개의 동시 프로세스가 필요합니다. 제 가상 머신에서는 최대 12492개의 동시 프로세스를 생성할 수 있었고, 호스트 머신에서는 39652개를 생성할 수 있었습니다.

도구 다운로드