1. 개요
2024년 10월, Microsoft는 Windows 커널의 TOCTOU(Time-of-Check Time-of-Use) Race Condition 취약점인 CVE-2024-43511을 패치했다. 이 패치는 RtlSidHashInitialize() 함수 호출 시 유저가 제어 가능한 버퍼에서 값을 읽는 대신, 커널 구조체(TOKEN)의 멤버에서 직접 값을 읽도록 수정하는 방식이었다.
그러나 이 패치는 불완전했다. RtlSidHashInitialize() 함수 내부에서 여전히 커널 주소를 유저 버퍼에 저장하는 동작이 존재했고, 이로 인해 새로운 Race Condition 기반의 커널 주소 leak 취약점(CVE-2025-53136)이 발생하게 되었다.
2. 취약점 근본 원인 분석
항목 | 내용 |
취약점 번호 | CVE-2025-53136 |
취약점 이름 | NT OS Kernel Information Disclosure Vulnerability |
취약점 종류 | Information Disclosure |
CVSS | 5.5(/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N) |
2.1. 함수 호출 순서
취약점이 발생하는 함수 호출 흐름은 다음과 같다.
NtQueryInformationToken(TokenAccessInformation) ← 유저가 syscall 호출
│
▼
SepCopyTokenAccessInformation() ← caller 함수 (토큰 정보 복사)
│
▼
RtlSidHashInitialize() ← 취약 함수 (커널주소를 유저버퍼에 저장)
Plain Text
복사
[코드 1] 취약점 발생 함수 호출 흐름
함수명 | 역할 |
NtQueryInformationToken() | 토큰 정보를 조회하는 NT syscall |
SepCopyTokenAccessInformation() | 토큰의 접근 정보를 유저 버퍼에 복사 |
RtlSidHashInitialize() | SID 해시 테이블 초기화 (취약점 발생 지점) |
2.2. 취약한 버전 분석 (CVE-2025-53136 패치 전)
2.2.1. SepCopyTokenAccessInformation() 함수
__int64 __fastcall SepCopyTokenAccessInformation(__int64 Token, __int64 a2, ...)
{
// ... 생략 ...
IsEnabledDeviceUsage = sub_1403F8F98();
UserAndGroupCount = *(_DWORD *)(Token + 0x7C); // 토큰에서 그룹 개수 획득
UserPtr = (_QWORD *)(a2 + 0x58); // 유저 버퍼 포인터 설정
if ( IsEnabledDeviceUsage )
{
// 취약한 호출: 커널 주소가 UserPtr에 저장됨
RtlSidHashInitialize(
*(__int64 **)(Token + 0x98), // Token->UserAndGroups (커널 주소)
UserAndGroupCount, // 그룹 개수
UserPtr // 유저 버퍼 ← 여기에 커널 주소가 저장
);
*(_QWORD *)(a2 + 0x60) = v24; // 다른 오프셋을 덮어씀
}
// ... 생략 ...
}
C
복사
[코드 2] SepCopyTokenAccessInformation() 함수 (취약 버전)
RtlSidHashInitialize() 함수가 리턴한 후에도 UserPtr[1]에 저장된 커널 주소가 덮어씌워지지 않고 그대로 남아있다. *(_QWORD *)(a2 + 0x60) = v24는 다른 오프셋을 수정하는 것이므로, 커널 주소가 저장된 UserPtr[1] (= a2 + 0x60)과 무관하다.
2.2.2 RtlSidHashInitialize() 함수
__int64 __fastcall RtlSidHashInitialize(
__int64 *Array, // 첫 번째 파라미터: 커널 주소 (Token->UserAndGroups)
unsigned int Count, // 두 번째 파라미터: 그룹 개수
_QWORD *UserPtr // 세 번째 파라미터: 유저 버퍼
)
{
if ( !UserPtr )
return 0xC000000Di64;
memset(UserPtr, 0, 0x110ui64); // 유저 버퍼 초기화
if ( Array && Count )
{
UserPtr[1] = Array; // 커널 주소를 유저 버퍼에 저장
*(_DWORD *)UserPtr = Count;
if ( Count > 0x40 )
Count = 0x40;
v6 = 1i64;
v7 = Count;
// === 해시 계산 루프 (수십~수백 CPU 사이클 소요) ===
do
{
v8 = *Array;
Array += 2;
v9 = *(unsigned __int8 *)(v8 + 4i64 * *(unsigned __int8 *)(v8 + 1) + 4);
v10 = *(_BYTE *)(v8 + 4i64 * *(unsigned __int8 *)(v8 + 1) + 4) & 0xF;
UserPtr[v10 + 2] |= v6;
UserPtr[((unsigned __int64)v9 >> 4) + 18] |= v6;
v6 = __ROL8__(v6, 1);
--v7;
}
while ( v7 );
// === 루프 종료: 이 동안 UserPtr[1]에 커널 주소 노출 ===
}
return 0i64;
}
C#
복사
[코드 3] RtlSidHashInitialize() 함수 (취약 버전)
취약점 발생 지점 UserPtr[1] = Array에서 커널 주소(Token->UserAndGroups 포인터)가 유저가 접근 가능한 버퍼에 저장된다. 이후 해시 계산 루프가 실행되는 동안 커널 주소가 계속 노출된 상태로 유지된다.
2.3. 패치된 버전 분석 (CVE-2025-53136 패치 후)
2.3.1 SepCopyTokenAccessInformation() 함수 (패치 후)
__int64 __fastcall SepCopyTokenAccessInformation(__int64 a1, __int64 a2, ...)
{
// ... 생략 ...
IsEnabledDeviceUsage = Feature_693672248__private_IsEnabledDeviceUsage();
UserAndGroupCount = *(_DWORD *)(a1 + 124);
Token_UserAndGroupCount = *(__int64 **)(a1 + 152);
if ( IsEnabledDeviceUsage )
{
RtlSidHashInitialize(Token_UserAndGroupCount, UserAndGroupCount, UserPtr);
// 패치 추가: 함수 리턴 직후 즉시 memset으로 초기화
memset((void *)(a2 + 0x5C), 0, 0x10Cui64);
v28 = &UserPtr[2];
*(_DWORD *)(a2 + 88) = UserPtr[0];
}
// ... 생략 ...
}
C
복사
[코드 4] SepCopyTokenAccessInformation() 함수 (패치 버전)
RtlSidHashInitialize() 함수 호출 직후 memset((void *)(a2 + 0x5C), 0, 0x10Cui64)를 추가하여 유저 버퍼를 즉시 0으로 초기화한다. 이로써 커널 주소가 노출되는 시간(Race Window)을 줄였다.
2.4. 취약한 버전 vs 패치된 버전 비교
구분 | 취약한 버전 | 패치된 버전 |
함수 호출 | 동일 | 동일 |
함수 내부 | UserPtr[1] = 커널주소 | UserPtr[1] = 커널주소 |
함수 리턴 후 | 다른 오프셋만 덮어씀 | 즉시 memset으로 0 초기화 |
Race Window | 함수 실행 중 + 리턴 후 계속 | 함수 실행 중만 (짧음) |
2.5. Race Condition 타임라인
2.5.1. 취약한 버전
Thread A (syscall 호출) Thread B (버퍼 읽기) UserPtr[1] 상태
────────────────────────────────────────────────────────────────────────────────
NtQueryInformationToken() 호출 0x0000000000000000
│
▼
RtlSidHashInitialize() 진입 0x0000000000000000
│
▼
UserPtr[1] = 커널주소 저장 ────────→ 읽기 시도 ────────────────→ 0xFFFF800123456789 ← LEAK
│ │
▼ ▼
해시 계산 루프 실행 중 ────────────→ 읽기 성공 ───────────────→ 0xFFFF800123456789 ← LEAK
│
▼
함수 리턴 0xFFFF800123456789 ← 노출 유지
│
▼
다른 오프셋 덮어씀 ────────────────→ 읽기 가능 ────────────────→ 0xFFFF800123456789 ← 계속 노출
Plain Text
복사
[코드 5] Race Condition 타임라인 (취약 버전)
취약한 버전에서는 함수 리턴 후에도 커널 주소가 유저 버퍼에 남아있어 Race Window가 매우 넓다.
2.5.2. 패치된 버전
Thread A (syscall 호출) Thread B (버퍼 읽기) UserPtr[1] 상태
────────────────────────────────────────────────────────────────────────────────
NtQueryInformationToken() 호출 0x0000000000000000
│
▼
RtlSidHashInitialize() 진입 0x0000000000000000
│
▼
UserPtr[1] = 커널주소 저장 ────────→ 읽기 시도? ───────────────→ 0xFFFF800123456789 ← 짧은 window
│
▼
해시 계산 루프 실행 중 ────────────→ 읽기 시도? ───────────────→ 0xFFFF800123456789 ← 짧은 window
│
▼
함수 리턴
│
▼
memset으로 즉시 초기화 ────────────→ 읽기 시도 ────────────────→ 0x0000000000000000 ← 이미 초기화됨
Plain Text
복사
[코드 6] Race Condition 타임라인 (패치 버전)
3. 공격 영향
1.
KASLR 우회
•
Windows 11/Server 2022 24H2부터 Microsoft는 NtQuerySystemInformation(SystemModuleInformation) 등 기존 커널 주소 leak 기법을 차단했다. CVE-2025-53136은 이러한 보호를 우회하여 커널 주소를 획득할 수 있는 새로운 기법을 제공한다.
2.
낮은 권한에서 악용 가능
•
이 취약점은 NT syscall을 통해 트리거되므로 Low Integrity Level 또는 AppContainer 환경에서도 악용 가능하다.
3.
익스플로잇 체이닝
•
획득한 커널 주소를 Write-What-Where 취약점과 결합하면 TOKEN 구조체의 Privileges 필드를 덮어써 **Local Privilege Escalation (LPE)**을 달성할 수 있다.
4. 완화 및 권고사항
1.
패치 적용
•
Microsoft에서 제공하는 최신 보안 업데이트를 즉시 적용한다.
2.
공격 표면 축소
•
AppContainer 및 Low IL 프로세스에 대한 모니터링 강화
•
토큰 관련 syscall 호출 패턴 모니터링
3.
심층 방어
•
Exploit Guard, HVCI(Hypervisor-protected Code Integrity) 활성화
•
커널 익스플로잇 탐지 솔루션 도입
5. 결론
CVE-2025-53136은 CVE-2024-43511 패치의 불완전함에서 비롯된 취약점이다. Microsoft는 caller 함수(SepCopyTokenAccessInformation)에서 memset을 추가하여 Race Window를 줄이려 했으나, 핵심 함수(RtlSidHashInitialize) 내부의 취약한 동작을 수정하지 않았다.
이로 인해 공격자는 두 스레드를 이용한 Race Condition 공격으로 커널 주소를 leak할 수 있으며, 이는 Windows 24H2에서 강화된 KASLR 보호를 우회하는 강력한 프리미티브가 된다. 다른 커널 취약점과 체이닝될 경우 완전한 권한 상승이 가능하므로, 영향받는 시스템에 대한 즉각적인 패치 적용이 필요하다.
6. 참고자료
•
Microsoft Security Update Guide
•
MITRE CVE Database


