Named Pipe Pass-the-Hash

Original text by s3cur3th1ssh1t

This post will cover a little project I did last week and is about Named pipe Impersonation in combination with Pass-the-Hash (PTH) to execute binaries as another user. Both techniques used are not new and often used, the 

 thing I did here is combination and modification of existing tools. The current public tools all use PTH for network authentication only. The difference to this “new” technique is therefore, that you can also spawn a new shell or C2-Stager as the PTH user for local actions 
 network authentication

2.05.2021: Update

Unfortunately I learned, that my technique can only be used for local actions, but not for network authentication, as Impersonation Tokens are restricted to that.

Introduction — why another PTH tool?

I faced certain Offensive Security project situations in the past, where I already had the NTLM-Hash of a 

low privileged
 user account and needed a shell for that user on the current compromised system — but that was not possible with the current public tools. Imagine two more facts for a situation like that — the NTLM Hash could not be cracked and there is no process of the victim user to execute shellcode in it or to migrate into that process. This may sound like an absurd edge-case for some of you. I still experienced that multiple times. Not only in one engagement I spend a lot of time searching for the right tool/technique in that specific situation. Last week, @n00py1 tweeted exactly the question I had in mind in those projects:

So I thought: Other people in the field obviously have the same limitations in existing tools.

My personal goals for a tool/technique were:

  • Fully featured shell or C2-connection as the victim user-account
  • It must to able to also Impersonate 
    low privileged
     accounts — depending on engagement goals it might be needed to access a system with a specific user such as the CEO, HR-accounts, SAP-administrators or others
  • The tool has to be used on a fully compromised system without another for example linux box under control in the network, so that it can be used as C2-module for example

The Tweet above therefore inspired me, to again search for existing tools/techniques. There are plenty of tools for network authentication via Pass-the-Hash. Most of them have the primary goal of code execution on remote systems — which needs a privileged users Hash. Some of those are:

If we want to have access to an administrative account and a shell for that account, we can easily use the WMI, DCOM and WinRM PTH-tools, as commands are executed in the users context. The python tools could be executed over a SOCKS tunnel via C2 for example, the Powershell scripts work out-of-the-box locally. SMB PTH tools execute commands as 

, so user impersonation is not possible here. One of my personal goals was not fulfilled — the impersonation of 
low privileged
 accounts. So I had to search for more possibilities.

The best results for local PTH actions are in my opinion indeed Mimikatz’s 

 and Rubeus’s 
 features. I tested them again to start software via PTH or inject a Kerberos ticket into existing processes and realized, that they 
 provide network authentication for the PTH-user. Network authentication Only? Ok, I have to admit, in the most cases network authentication is enough. You can read/write the Active Directory via LDAP, access network shares via SMB, execute code on remote systems with a privileged user (SMB, WMI, DCOM, WinRM) and so on. But still — the 
edge case
 to start an application as the other user via Pass-the-Hash is not possible. I thought to myself, that it might be possible to modify one of those tools to archieve the specific goal of an interactive shell. To do that, I had to first dig into the code to understand it. Modifying Rubeus was no opion for me, because 
 uses a Kerberos ticket, which is as far as I know only used for network authentication. That won’t help us authenticating on the localhost for a shell. So I took a look at the Mimikatz feature in the next step.

Mimikatz’s sekurlsa::pth feature

This part will only give some background information to the 

 Mimikatz module. If you already know about it feel free to skip. Searching for 
 internals resulted in two good blog posts for me, which I recommend reading for a deeper look into the topic, as I will only explain the high-level process:

A really short high-level overview of the process is as follows:

  • MSV1_0 and Kerberos are Windows two Authentication providers, which handle authentication using provided credential material
  • The LSASS process on a Windows Operating System contains a structure with MSV1_0 and Kerberos credential material
  • Mimikatz 
     creates a new process with a dummy password for the PTH user. The process is first created in the SUSPENDED state
  • Afterwards it creates a new MSV and Kerberos structure with the user provided NTLM hash and overwrites the original structure for the given user
  • The newly created process is RESUMED, so that the specified binary like for example 
     is executed

This part is copy & paste from the part II blog: Overwriting these structures does not change the security information or user information for the local user account. The credentials stored in LSASS are associated with the logon session used for network authentication and not for identifying the local user account associated with a process.

Those of you, who read my other blog posts know, that C/C++ is not my favorite language. Therefore I decided to work with @b4rtik’s SharpKatz code, which is a C# port of the in my opinion most important and most used Mimikatz functions. Normally, I don’t like blog posts explaining a topic with code. Don’t ask me why, but this time I did it myself here. The PTH module first creates a structure for the credential material called 

 from the class 

The NtlmHash of this new structure is filled with our given Hash:

                if (!string.IsNullOrEmpty(rc4))
                    ntlmHashbytes = Utility.StringToByteArray(rc4);

                if (!string.IsNullOrEmpty(ntlmHash))
                    ntlmHashbytes = Utility.StringToByteArray(ntlmHash);

                if (ntlmHashbytes.Length != Msv1.LM_NTLM_HASH_LENGTH)
                    throw new System.ArgumentException();

                data.NtlmHash = ntlmHashbytes;

A new process in the 

 state is opened. Note, that our PTH username is chosen with an empty password:

                    if(CreateProcessWithLogonW(user, "", domain, @"C:\Windows\System32", binary, arguments, CreationFlags.CREATE_SUSPENDED, ref pi))

In the next step, the process is opened and the 

 of the new process is copied into our credential material object, which is related to our PTH username.

Afterwards, the function 

 is called. This function first searches for and afterwards overwrites the MSV1.0 and Kerberos credential material with our newly created structure:

If that resulted in success, the process is resumed via 


Named Pipe Impersonation

Thinking about alternative ways for PTH user Impersonation I asked @EthicalChaos about my approach/ideas and the use-case. Brainstorming with you is always a pleasure, thanks for that! Some ideas for the use-case were:

  • NTLM challenge response locally via InitializeSecurityContext / AcceptSecurityContext
  • Impersonation via process token
  • Impersonation via named pipe identity
  • Impersonation via RPC Identity

I excluded the first one, because I simply had no idea about that and never worked with it before. Impersonation via process token or RPC Identity required an existing process for the target user to steal the token from. A process for the target user doesn’t exist in my szenario, so only Named Pipe Impersonation was left. And I thought cool, I already worked with that to build a script to get a 

 shell — NamedPipeSystem.ps1. So I’m not completely lost in the topic and know what it is about.

For everyone out there, who doesn’t know about Named Pipe Impersonation I can recommend the following blog post by @decoder_it:

Again, I will give a short high-level overview for it. Named Pipes are ment to be used for asynchronous or synchronous communication between processes. It’s possible to send or receive data via Named Pipes locally or over the network. Named Pipes on a Windows Operating System are accessible over the 

 network share. One Windows API call, namely 
 allows the server to impersonate any client connecting to it. The 
 thing you need for that is the 
 privilege. Local administrators and many service-accounts have this privilege by default. So opening up a Named Pipe with this privileges enables us to Impersonate any user connecting to that Pipe via 
 and open a new process with the token of that user-account.

My first thought about Named Pipe Impersonation in combination with PTH was, that I could spawn a new 

 process via 
 Pass-the-Hash and connect to the Named Pipe over 
 in the new process. If the network credentials are used for that, we would be able to fulfill all our goals for a new tool. So I opened up a new Powershell process via PTH and SharpKatz with the following command:

.\SharpKatz.exe --Command pth --User testing --Domain iPad --NtlmHash 7C53CFA5EA7D0F9B3B968AA0FB51A3F5 --Binary "\WindowsPowerShell\v1.0\powershell.exe"

What happens in the background? That is explained above. To test, that we are really using the credentials for the user 

 we can connect to a linux boxes SMBServer: -ip -smb2support testshare /mnt/share

After opening up the server we can connect to it via simply echoing into the share:

And voila, the authentication as 

 came in, so this definitely works:

@decoder_it’s wrote a Powershell script — pipeserverimpersonate.ps1 — which let’s us easily open up a Named Pipe Server for user Impersonation and to open 

 afterwards with the token of the connecting user. The next step for me was to test, if connections from this new process connect to the Named Pipe Server with the network credentials. It turned out, that this unfortunately is not the case:

I tried to access the Pipe via
External IP
, but the same result in every case:

I also tried using a NamedPipeClient via Powershell — maybe this would result in network authentication with the user 

 — still no success:

At this point I had no clue on how I could trigger network authentication to localhost for the Named Pipe access. So I gave up on Mimikatz and SharpKatz — but still learned something by doing that. And maybe some of you also learned something in this section. This was a dead end for me.

But what happens exactly when network authentication is triggered? To check that, I monitored the network interface for SMB access from one Windows System to another one:

  1. The TCP/IP Three-way-handshake is done (SYN,SYN/ACK,ACK)
  2. Two Negotiate Protocol Requests and Responses
  3. Session Setup Request, 
  4. Tree Connect Request to 
  5. Create Request File 

During my tool research I took a look at @kevin_robertson’s Invoke-SMBExec.ps1 code and found, that this script contains exactly the same packets and sends them manually. So by modifying this script, it could be possible to skip the Windows default behaviour and just send exactly those packets manually. This would simulate a remote system authenticating to our Pipe with the user 


I went through the SMB documentation for some hours, but that did not help me much to be honest. But than I had the idea to just monitor the default 

 traffic for the testing user. Here is the result:

Comparing those two packet captures results in only one very small difference. 

 tries to access the Named Pipe 
. We can easily change that in line 1562 and 2248 for the 
 stage, by using different hex values for another Pipe name. So if we only change those bytes to the following, a 
 request is send to our attacker controlled Named Pipe:

$SMB_named_pipe_bytes = 0x74,0x00,0x65,0x00,0x73,0x00,0x74,0x00,0x70,0x00,0x69,0x00,0x70,0x00,0x65,0x00 # \testpipe

The result is an local authentication to the Named Pipe as the user 


To get rid of the error message and the resulting timeout we have to do some further changes to the 

 code. I therefore modified the script, so that after the 
 packet is send instead of the default code execution stuff for Service creation and so on. I also removed all Inveigh Session stuff, parameters and so on.

But there still was one more thing to fix. I got the following error from 

 when impersonating the user 
 via network authentication:

This error didn’t pop up, when a 

 was opened with the password, accessing the Pipe afterwards.

Googling this error results in many many crap answers ranging from 

corrupted filesystem, try to repair it
install DirectX 11
Disable Antivirus
. I decided to ask the community via Twitter and got a fast response from @tiraniddo, that the error code is likely due to not being able to open the Window Station. A solution for that is changing the 
 DACL to grant everyone access. I would have never figured this out, so thank you for that! 🙂 @decoder_it also send a link to RoguePotato, especially the code for setting correct WinSta/Desktop permissions is included there.

Modifying RoguePotato & building one script as PoC

Taking a look at the 

 code from RoguePotato I decided pretty fast, that porting this code to Powershell or C# is no good idea for me as I would need way too much time for that. So my idea was, to modify the RoguePotato code to get a PipeServer which sets correct permissions for 
. Doing this was straight forward as I mostly had to remove code. So I removed the RogueOxidResolver components, the IStorageTrigger and so on. The result is the PipeServerImpersonate code.

Testing the server in combination with our modified Invoke-SMBExec script resulted in no shell at first. The 

 function did not open up the desired binary even though the token had 
 privileges. I ended up using 
 as dwCreationFlags, which worked perfectly fine. Opening up the Named Pipe via modified RoguePotato and connecting to it via Invoke-NamedPipePTH.ps1 resulted in successfull Pass-the-Hash to a Named Pipe for Impersonation and binary execution with the new token:

Still — this is not a perfect solution. Dropping PipeServerImpersonate to disk and executing the script in another session is one option, but a single script doing everything is much better in my opinion. Therefore I build a single script, which leverages Invoke-ReflectivePEInjection.ps1 to execute PipeServerImpersonate from memory. This is done in the background via 

, so that 
 can connect to the Pipe afterwards. It’s possible to specify a custom Pipe Name and binary for execution:

This enables us to use it from a C2-Server as module. You could also specify a C2-Stager as binary, so that you will get a new agent with the credentials of the PTH user.

Further ideas & improvements

I see my code still as PoC, because it is far away from being OPSEC safe and I didn’t test that much possible use-cases. Using Syscalls for PipeServerImpersonate and PE-Injection instead of Windows API functions would further improve this for example.

For those of you looking for a C# solution: Sharp-SMBExec is a C# port of 

 which can be modified the same way I did here to get a C# version for the PTH to the Named Pipe part. However, the PipeServerImpersonate part should also be ported, which in my opinion is more work todo.

2.05.2021: Update

I also wrote a C# version based on this idea. It can be found here:

The whole project gave me the idea, that it would be really cool to also add an option to impacket’s
 to relay connections to a Named Pipe. Imagine you compromised a single host in a customer environment and this single host didn’t gave any valuable credentials but has 
SMB Signing disabled
. Modifying PipeServerImpersonate, so that the Named Pipe is not closed but re-opened again after executing a binary would make it possible to get a C2-Stager for every single incoming NetNTLMV2 connection. This means raining shells. The connections only need to be relayed to 
 to get a shell or C2-connection.

2.05.2021: Update

This idea was nice with the background thought, that we have local 

 network authentication for the new process. But we can only do stuff locally with an Impersonation token. This is also explained in the next part. Therefore the raining shells would not help us to move anywhere.

Having @itm4n’s article about PrintSpoofer — — in mind, I also had the idea, if it’s possible to relay a Domain Controllers Computer-Account Hash to our Named Pipe via Spoolsample. This can be done with the MS-RPRN part of the by using 

 instead of 
 for the target system like this:

MS-RPRN.exe \\DomainControllerFQDN \\OutCompromisedSystemFQDN/pipe/pipename

This works perfectly fine, and we therefore can get a shell as Domain Controller computer account:

Using TokenViewer gives us the possibility to see, which Token Type and Impersonation Level we have:

I learned after writing this post and fiddling around with the new impersonated users shells, that 

Impersonation Tokens
 are restricted to Operating System local actions only. Processes with this Token Type cannot access ressources in the network like LDAP, SMB, HTTP or whatever else. Therefore, our DC shell for example is useless.

Until someone finds a way to get an 

Delegation Token
 from a process with an 
Impersonation Token
 for example. If the impersonated user is logged on interactively, you can also create a sheduled task for that user and trigger it. This would for example result in network access for that newly created task.


This is the first time, that I created somehow a new technique. At least I didn’t see anyone else using a combination of PTH and Named Pipe Impersonation with the same goal. For me, this was a pretty exciting experience and I learned a lot again.

I hope, that you also learned something from that or at least can use the resulting tool in some engagements whenever you are stuck in a situation described above. The script/tool is released with this post, and feedback is as always very welcome!

20.04.2021: Update

I’m pretty sure, that I before publication of the tool tested the content of Start-Job Scriptblocks for AMSI scans/blocks. And it was not scanned neither blocked. After the publication, Microsoft obviously decided to activate this feature, because the standalone script didn’t work anymore with Defender enabled even after patching 

 in memory for the process:

Therefore, I decided to switch from the native 

 function to the 
 function, which again bypasses Defender because its executed in the same process:

If this description is true, 

 should have scanned and blocked scripts before because it’s another process. But here we stay in the same process, therefore a bypass works:

РубрикиБез рубрики

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *