[하루한줄] CVE-2024-38077: Windows Remote Desktop Licensing Service의 Heap-based Buffer Overflow로 인한 PreAuth RCE 취약점
URL
https://github.com/CloudCrowSec001/CVE-2024-38077-POC/blob/main/CVE-2024-38077.md
Target
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-38077
- Windows Server 2016 < 10.0.14393.7159
- Windows Server 2019 < 10.17763.6054
- Windows Server 2022 23H2 < 10.0.25398.1009
- Windows Server 2022 < 10.0.20384.2582
- …
Explain
원격 데스크톱 라이선싱(RDL) 서비스는 원격 데스크톱 서비스에 대한 라이선스를 관리하고 발급하여 원격 애플리케이션과 데스크톱에 대한 안전한 액세스를 보장하는 Windows Server의 컴포넌트입니다.
RDL 서비스는 원격 데스크탑 서비스가 활성화된 머신에서 널리 사용되고 있으며 기본적으로는 동시에 두 개의 세션을 허용합니다. 3개 이상의 세션을 사용하고 싶다면 라이선스를 추가적으로 구매해야하고 RDL 서비스는 이러한 라이선스를 관리하는 역할을 합니다.
Terminal Service Licensing Procedure는 유저나 디바이스에서 서버에 연결하기 위해 사용되는 Terminal Server CAL(Client Access Lisence)를 관리하기 위해 디자인되었는데 이 과정에서 호출되는 아래의 CDataCoding::DecodeData
함수에서 취약점이 발생했습니다.
__int64 __fastcall CDataCoding::DecodeData(
CDataCoding *this,
const unsigned __int16 *a2,
unsigned __int8 **a3,
unsigned int *a4)
{
// ...
v4 = 0;
v8 = 0;
if ( a3 )
{
v9 = dwBytes;//[1]
*a3 = 0i64;
*a4 = 0;
ProcessHeap = GetProcessHeap();
v11 = (unsigned __int8 *)HeapAlloc(ProcessHeap, 8u, v9);//[2]
v12 = v11;
if ( v11 )
{
memset_0(v11, 0, (unsigned int)dwBytes);
while ( *a2 )//[3]
{
// Str is BCDFGHJKMPQRTVWXY2346789
// a2 is user-controlled buffer
v13 = wcschr_0(Str, *a2);
if ( !v13 )
{
v4 = 13;
v18 = GetProcessHeap();
HeapFree(v18, 0, v12);
return v4;
}
// here change the integer a2 from base 24 to base 10
// but does not check the length of a2
v14 = v13 - Str;
v15 = v12;
v16 = (unsigned int)(v8 + 1);
do{
v17 = dword_1800D61C8 * *v15 + v14;
*v15++ = v17;
LODWORD(v14) = v17 >> 8;
--v16;
}while ( v16 );
if ( (_DWORD)v14 )
v12[++v8] = v14;
++a2;
}
*a4 = dwBytes;
*a3 = v12;
}
else
{
return 8;
}
}
else
{
return 87;
}
return v4;
}
[1]에서 v9
에 값으로 사용되는 dwbytes
는 아래의 CDataCoding::SetInputEncDataLen
함수에서 값이 21로 설정된 전역 변수입니다.
void __fastcall CDataCoding::SetInputEncDataLen(CDataCoding *this)
{
// ...
dword_1800D61D0 = 35;
v1 = log10_0((double)dword_1800D61C8) * 35.0;
v2 = v1 / log10_0(2.0);
v3 = (int)v2 + 1;
v4 = 0;
if ( v2 <= (double)(int)v2 )
v3 = (int)v2;
LOBYTE(v4) = (v3 & 7) != 0;
LODWORD(dwBytes) = (v3 >> 3) + v4; // dwBytes is a fixed value 21
}
이후 [2]에서 21 바이트 크기의 힙 메모리가 할당되고 [3]의 while
루프에서 24진수 숫자가 문자열로 저장되어 있는 a2
를 10진수로 변환해서 할당된 메모리에 저장합니다.
하지만 이 과정에서 사용자가 제공한 데이터인 a2
의 길이를 검사하지 않아 Heap Overflow 취약점이 발생했고 이는 인증 과정 이전에 발생하기 때문에 이를 통해 Preauth RCE가 가능했습니다.
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.