Takes a pipe name and returns the owning process and access rights. The primary motivation for this artifact is a vulnerability in RemCom. RemCom is most notably used by impacket psexec.py. It creates a null DACL for its communication pipe. This means a low privileged user could use a stale pipe to get remote execution as SYSTEM. If you uncover any named pipes with the name RemCom_communication, investigate the owning proc and remove it from the system. #impacket
name: Windows.Detection.PipeHunter
author: ACEResponder.com
description: |
Takes a pipe name and returns the owning process and access rights. The primary
motivation for this artifact is a vulnerability in RemCom. RemCom is most
notably used by impacket psexec.py. It creates a null DACL for its
communication pipe. This means a low privileged user
could use a stale pipe to get remote execution as SYSTEM. If you uncover any
named pipes with the name RemCom_communication, investigate the owning proc
and remove it from the system.
#impacket
reference:
- https://twitter.com/bugch3ck
parameters:
- name: pipe_name
default: "RemCom_communicaton"
sources:
- precondition:
SELECT OS From info() where OS = 'windows'
query: |
LET ps = '''Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class Kernel32
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateFile(
string filename,
System.IO.FileAccess access,
System.IO.FileShare share,
IntPtr securityAttributes,
System.IO.FileMode creationDisposition,
uint flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetNamedPipeServerProcessId(IntPtr hPipe, out int ClientProcessId);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CloseHandle(IntPtr hObject);
}
"@
$remcom=$null
$pipeOwner=0
try {
#gci directly on the pipe does not work in some versions of posh for some reason
$remcom = Get-ChildItem -ErrorAction Stop \\.\pipe\ -Filter '''
LET ps2='''
$output = New-Object PSObject -Property @{
ProcessId = $null;
ProcessName = $null;
NamedPipe = $remcom.FullName;
AccessControlType = $null;
IdentityReference = $null;
}
try {
$acl = $remcom.GetAccessControl();
$output.AccessControlType = $acl.Access.AccessControlType;
$output.IdentityReference = $acl.Access.IdentityReference.Value;
}
catch {
}
$hPipe = [Kernel32]::CreateFile($remcom.FullName, [System.IO.FileAccess]::Read, [System.IO.FileShare]::None, [System.IntPtr]::Zero, [System.IO.FileMode]::Open, [System.UInt32]::0x80, [System.IntPtr]::Zero);
$pipeOwnerFound = [Kernel32]::GetNamedPipeServerProcessId([System.IntPtr]$hPipe, [ref]$pipeOwner);
if ($pipeOwnerFound) {
# Now that we have the process id, Get process name
$processName = Get-WmiObject -Query "SELECT Caption FROM Win32_Process WHERE ProcessID = $pipeOwner" | select -ExpandProperty Caption;
# Add to the name and ID to output
$output.ProcessID = $pipeOwner;
$output.ProcessName = $processName;
}
if($output.NamedPipe){
$output | ConvertTo-JSON
}
#close the handle to the pipe
$closed = [Kernel32]::CloseHandle($hPipe);
}
catch {
write-host $_;
}
'''
SELECT * FROM execve(argv=["Powershell", "-ExecutionPolicy",
"unrestricted", "-c", ps+pipe_name+ps2])