了解PSexec
PSExec允许用户连接到远程计算机并通过命名管道执行命令。命名管道是通过一个随机命名的二进制文件建立的,该文件被写入远程计算机上的ADMIN $共享,并被SVCManager用来创建新服务。
您可以想象此步骤正在运行:sc create [serviceName] binPath= "C:\Windows\[uploaded-binary].exe"。
建立命名管道后,您与远程计算机之间的所有命令输入和输出都通过SMB协议(445 / TCP)进行通信。
如果未开启共享 需要开启注册表的方式开启共享
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
AutoShareWks && AutoShareServer 修改为 1
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
restrictanonymous 修改为 1
我们拿一个普通web用户登录看看
可以看见日志4624后又紧跟着4634直接注销了,注销是因为web用户没有访问Admin$共享的权限
有关NTML的知识如果不熟悉的同学可以看
https://www.anquanke.com/post/id/210323
由此可以见普通的用户是没有访问admin$共享的权限的
我们接下来用Administrator尝试,查看数据包结果总结出来的流程
1192.168.1.102用192.168.1.100administartor进行NTML认证成功
2建立IPC$共享成功
3连接admin$共享
4向192.168.1.100admin$共享写入PE文件
5创建启动此文件的服务
6启动服务
7删除服务
8删除文件
1这是向admin$共享写入文件的步骤
我们需要知道的是传输文件这整个过程 与其交互的仅仅是445端口
但是我们发现这里为什么使用了DCE/RPC和EPM走了135端口,那么必须一定要走一次135吗?这里调用DCE/RPC和EPM的作用又是什么?我们带着问题继续思考
可以知道DCE/RPC协议是基于MSRPC协议的,而DCERPC并没有创建服务,只是一个远程调用协议。
https://stackoverflow.com/questions/51346269/understanding-smb-and-dcerpc-for-remote-command-execution-capabilities
那么EPM协议又是什么呐?
https://wiki.wireshark.org/EPM
https://help.stonesoft.com/onlinehelp/StoneGate/SMC/6.3.0/GUID-1DDB90C6-0BC1-45C1-8ED8-F56A98513F28.html
我们接下来关闭135端口看能不能psexec成功,可以看见在只有445端口开放的情况下,还是能成功psexec,我们继续抓包看看和之前135开放的包有什么区别
可以看见这里的DCERPC协议的作用和开放135端口情况下的DCERPC协议的作用是不相同的,
然后紧接着安装psexesvc服务
这里又创建了一些列的命名管道
首先,我们需要清楚的是,命名管道基于smb协议,smb,smb而不是tcp进行通信。重要的事情说了三遍。它用于在两个进程之间进行通信。这两个进程可以是本地进程或远程进程。命名管道有点类似于套接字连接。它们用于传输数据。可以设置特定的权限,以便具有指定权限的进程可以连接到命名管道。从理论上讲,每个程序都可以连接到命名管道,但是它们在连接后可以做不同的事情。可以完成的操作取决于服务器的配置。
以下总结了几点:
1.命名管道是C / S体系结构,服务器上的进程必须首先创建一个命名管道。
2.可以通过满足权限的任何进程访问命名管道,并且可以自定义可以访问哪些权限。
3.客户端可以是本地进程,也可以是远程进程。本地进程访问\。\ pipe \ pipename中的命名管道,而远程进程访问\ ip \ pipe \ pipename。
上面的psexesvc管道是用于服务本身的,但是下面这三个管道则不是
更具以上分析搞了一个自己的psexec demo
Mypsexec.cs
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Text;
//All the above are namespaces, similar to import in python namespace Server //Namespace declaration
{
class Server
{
static void Main(string[] args) //Program entry point
{
/**When you are not sure what type of variable is, use var. The NamedPipeServerStream class is
Under the System.IO.Pipes namespace. Using it in the way of using is equivalent to with in python
Like opening a file, to a certain extent, to prevent forgetting to release some resources, you can also avoid using using.
**/ using (var pipe = new NamedPipeServerStream(
"Mypsexec",
PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances,
PipeTransmissionMode.Message))
/**Set the pipe name to psexecsvc, the pipe communication mode is two-way communication, both parties can send information
You can also receive information. The maximum number of connections is the default maximum number of connections. The last parameter represents
Use information flow to transfer data, not byte stream, remember to use information flow, because whenever
Using byte streams, the other party may not be able to receive all the information that has been sent, and the information stream can be guaranteed
All data sent by the certificate can be received.
**/
{
Console.WriteLine("[*] Waiting for client connection...");
pipe.WaitForConnection();//Waiting for the connection from the other end of the pipeline
Console.WriteLine("[*] Client connected.");
while (true)
{
/**
Pass the byte type array received from the named pipe to messageBytes, this word
The section array is the binary form of the data sent by the client.
**/
var messageBytes = ReadMessage(pipe);
//Store the string generated by UTF-8 decoding of the byte type array into the line
var line = Encoding.UTF8.GetString(messageBytes);
Console.WriteLine("[*] Received: {0}", line);
//Convert the received string to consumer agreement, if the content is exit, exit the program.
if (line.ToLower() == "exit") return; /**
Create a ProcessStartInfo class, this class is used to specify the relevant attributes of a process.
**/
var processStartInfo = new ProcessStartInfo
{
//Start cmd
FileName = "cmd.exe",
//The parameter is /c + line, line is the data received from the named pipe
Arguments = "/c " + line,
//From the standard output of Dingxi
RedirectStandardOutput = true,
//Redirect standard error output
RedirectStandardError = true,
//By setting this attribute to false, standard input, output and error streams can be redirected.
UseShellExecute = false
};
try
{
/**
Start the process with the information previously defined, and jump to the catch block if an error occurs. What returned is
A process class, my understanding is that this process class is a program handle, you can
Allows you to perform specified operations on the program, such as opening and closing.
**/
var process = Process.Start(processStartInfo); /**
Read all the standard output of the process, and combine the standard error output and standard output into one
Strings.
**/
var output = process.StandardOutput.ReadToEnd();
output += process.StandardError.ReadToEnd();
//Waiting for the end of the thread can be understood as waiting for the end of the above command
process.WaitForExit();
//If output is equal to empty or null, assign a newline character to it.
if (string.IsNullOrEmpty(output))
{
output = "\n";
}
//Encode the output as a byte array in UTF.
var response = Encoding.UTF8.GetBytes(output);
//Write all the data of this byte array to the pipe in the named pipe.
pipe.Write(response, 0, response.Length);
}
catch (Exception ex)
{
/**If a line of code in the try block runs incorrectly, catch the error. This error is
Represented by string type, convert this error into a byte array and output to the named pipe
In.
**/
Console.WriteLine(ex);
var response = Encoding.UTF8.GetBytes(ex.Message);
pipe.Write(response, 0, response.Length);
}
}
}
} private static byte[] ReadMessage(PipeStream pipe)
{
byte[] buffer = new byte[1024];//Create an array that can store 1024 bytes of data
//Create a memory stream class for data transfer
using (var ms = new MemoryStream())
{
do
{
/**Read data from the named pipe, read byte blocks from 0, read at most
buffer.Length is 1024, and then the number of bytes read out is returned to
redBytes, write the read data to the buffer.
**/
var readBytes = pipe.Read(buffer, 0, buffer.Length);
/**
Read data from 0 byte from the buffer, read the redBytes byte, and then
Then write these data to the current memory stream.
**/
ms.Write(buffer, 0, readBytes);
}
//If the information in the named pipe has not been read, it will always perform the read operation.
while (!pipe.IsMessageComplete); return ms.ToArray();
/**
Write the data in the memory stream to the array and return a Byte class
Type array.
**/
}
}
}
}
psexec.cs
/*using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;
using System.IO.Pipes;
using System.Text; namespace ExtremeMirror
{
public class PinvokeWindowsNetworking
{
static void Main(string[] args)
{
connectToRemote("\\\\192.168.1.100", "localhost", "123456789789");
//Connect to the named pipe on the local computer, the mode of bidirectional data transmission, the pipe name is psexecsvc
using (var pipe = new NamedPipeClientStream("192.168.1.100",
"psexecsvc", PipeDirection.InOut))
{
//Connect to the named pipe, the supermarket time is 5000 milliseconds
pipe.Connect(5000);
//Set the data reading method to message
pipe.ReadMode = PipeTransmissionMode.Message;
do
{
Console.Write("MyPsexec> ");
//Receive data from the command line
var input = Console.ReadLine();
//If the received data is empty or null, jump out of this loop
if (String.IsNullOrEmpty(input)) continue;
//Convert the output string to byte array type and store
byte[] bytes = Encoding.Default.GetBytes(input);
//Write the converted data to the named pipe
pipe.Write(bytes, 0, bytes.Length);
//Change the conceit of the output to lowercase and then determine whether it is equal to exit, if it is, exit the program
if (input.ToLower() == "exit") return;
//Read data from the named pipe
var result = ReadMessage(pipe);
//Output Data
Console.WriteLine(Encoding.UTF8.GetString(result));
Console.WriteLine();
} while (true);
}
} private static byte[] ReadMessage(PipeStream pipe)
{
byte[] buffer = new byte[1024];
using (var ms = new MemoryStream())
{
do
{
var readBytes = pipe.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, readBytes);
}
while (!pipe.IsMessageComplete); return ms.ToArray();
}
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateService(
IntPtr hSCManager,
string lpServiceName,
string lpDisplayName,
uint dwDesiredAccess,
uint dwServiceType,
uint dwStartType,
uint dwErrorControl,
string lpBinaryPathName,
string lpLoadOrderGroup,
string lpdwTagId,
string lpDependencies,
string lpServiceStartName,
string lpPassword);
#region Consts
const int RESOURCE_CONNECTED = 0x00000001;
const int RESOURCE_GLOBALNET = 0x00000002;
const int RESOURCE_REMEMBERED = 0x00000003; const int RESOURCETYPE_ANY = 0x00000000;
const int RESOURCETYPE_DISK = 0x00000001;
const int RESOURCETYPE_PRINT = 0x00000002; const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005; const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
const int RESOURCEUSAGE_CONTAINER = 0x00000002; const int CONNECT_INTERACTIVE = 0x00000008;
const int CONNECT_PROMPT = 0x00000010;
const int CONNECT_REDIRECT = 0x00000080;
const int CONNECT_UPDATE_PROFILE = 0x00000001;
const int CONNECT_COMMANDLINE = 0x00000800;
const int CONNECT_CMD_SAVECRED = 0x00001000; const int CONNECT_LOCALDRIVE = 0x00000100;
#endregion #region Errors
const int NO_ERROR = 0; const int ERROR_ACCESS_DENIED = 5;
const int ERROR_ALREADY_ASSIGNED = 85;
const int ERROR_BAD_DEVICE = 1200;
const int ERROR_BAD_NET_NAME = 67;
const int ERROR_BAD_PROVIDER = 1204;
const int ERROR_CANCELLED = 1223;
const int ERROR_EXTENDED_ERROR = 1208;
const int ERROR_INVALID_ADDRESS = 487;
const int ERROR_INVALID_PARAMETER = 87;
const int ERROR_INVALID_PASSWORD = 1216;
const int ERROR_MORE_DATA = 234;
const int ERROR_NO_MORE_ITEMS = 259;
const int ERROR_NO_NET_OR_BAD_PATH = 1203;
const int ERROR_NO_NETWORK = 1222; const int ERROR_BAD_PROFILE = 1206;
const int ERROR_CANNOT_OPEN_PROFILE = 1205;
const int ERROR_DEVICE_IN_USE = 2404;
const int ERROR_NOT_CONNECTED = 2250;
const int ERROR_OPEN_FILES = 2401; private struct ErrorClass
{
public int num;
public string message;
public ErrorClass(int num, string message)
{
this.num = num;
this.message = message;
}
} // Created with excel formula:
// ="new ErrorClass("&A1&", """&PROPER(SUBSTITUTE(MID(A1,7,LEN(A1)-6), "_", " "))&"""), "
private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"),
new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"),
new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"),
new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"),
new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"),
new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"),
new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"),
new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"),
new ErrorClass(ERROR_MORE_DATA, "Error: More Data"),
new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"),
new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"),
new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"),
new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"),
new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"),
new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"),
new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"),
}; private static string getErrorForNumber(int errNum)
{
foreach (ErrorClass er in ERROR_LIST)
{
if (er.num == errNum) return er.message;
}
return "Error: Unknown, " + errNum;
}
#endregion [DllImport("Mpr.dll")]
private static extern int WNetUseConnection(
IntPtr hwndOwner,
NETRESOURCE lpNetResource,
string lpPassword,
string lpUserID,
int dwFlags,
string lpAccessName,
string lpBufferSize,
string lpResult
); [DllImport("Mpr.dll")]
private static extern int WNetCancelConnection2(
string lpName,
int dwFlags,
bool fForce
); [StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public int dwScope = 0;
public int dwType = 0;
public int dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = "";
public string lpRemoteName = "";
public string lpComment = "";
public string lpProvider = "";
} public static string connectToRemote(string remoteUNC, string username, string password)
{
return connectToRemote(remoteUNC, username, password, false);
} public static string connectToRemote(string remoteUNC, string username, string password, bool promptUser)
{
NETRESOURCE nr = new NETRESOURCE();
nr.dwType = RESOURCETYPE_DISK;
nr.lpRemoteName = remoteUNC;
// nr.lpLocalName = "F:"; int ret;
if (promptUser)
ret = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
else
ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null); if (ret == NO_ERROR) return null;
return getErrorForNumber(ret);
} public static string disconnectRemote(string remoteUNC)
{
int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false);
if (ret == NO_ERROR) return null;
return getErrorForNumber(ret);
}
}
}*/ using System;
using System.Runtime.InteropServices;
using System.Threading; /// <summary>
/// <para>
/// Sources:
/// <para>https://stackoverflow.com/questions/358700/how-to-install-a-windows-service-programmatically-in-c </para>
/// <para>https://www.c-sharpcorner.com/article/create-windows-services-in-c-sharp/</para>
/// </para>
///
/// <para>
/// Installs and starts the service
/// ServiceInstaller.InstallAndStart("MyServiceName", "MyServiceDisplayName", "C:\\PathToServiceFile.exe");
/// </para>
/// <para>
/// Removes the service
/// ServiceInstaller.Uninstall("MyServiceName");
/// </para>
/// <para>
/// Checks the status of the service
/// ServiceInstaller.GetServiceStatus("MyServiceName");
/// </para>
/// <para>
/// Starts the service
/// ServiceInstaller.StartService("MyServiceName");
/// </para>
/// <para>
/// Stops the service
/// ServiceInstaller.StopService("MyServiceName");
/// </para>
/// <para>
/// Check if service is installed
/// ServiceInstaller.ServiceIsInstalled("MyServiceName");
/// </para>
/// </summary>
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;
using System.IO.Pipes;
using System.Text;
public static class ServiceInstaller
{
static void Main(string[] args)
{
connectToRemote("\\\\192.168.1.100", "system\\administrator", "123456");
Console.WriteLine("连接成功");
File.Copy(@"Mypsexec.exe", "\\\\192.168.1.100\\c$\\programdata\\Mypsexec.exe");
Install("Dce", "Dce", "c:\\programdata\\Mypsexec.exe");
StartService("Dce"); //Connect to the named pipe on the local computer, the mode of bidirectional data transmission, the pipe name is psexecsvc
using (var pipe = new NamedPipeClientStream("192.168.1.100",
"Mypsexec", PipeDirection.InOut))
{
//Connect to the named pipe, the supermarket time is 5000 milliseconds
pipe.Connect(5000);
//Set the data reading method to message
pipe.ReadMode = PipeTransmissionMode.Message;
do
{
Console.Write("MyPsexecCMd> ");
//Receive data from the command line
var input = Console.ReadLine();
//If the received data is empty or null, jump out of this loop
if (String.IsNullOrEmpty(input)) continue;
//Convert the output string to byte array type and store
byte[] bytes = Encoding.Default.GetBytes(input);
//Write the converted data to the named pipe
pipe.Write(bytes, 0, bytes.Length);
//Change the conceit of the output to lowercase and then determine whether it is equal to exit, if it is, exit the program
if (input.ToLower() == "exit") return;
//Read data from the named pipe
var result = ReadMessage(pipe);
//Output Data
Console.WriteLine(Encoding.UTF8.GetString(result));
Console.WriteLine();
} while (true);
}
} private static byte[] ReadMessage(PipeStream pipe)
{
byte[] buffer = new byte[1024];
using (var ms = new MemoryStream())
{
do
{
var readBytes = pipe.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, readBytes);
}
while (!pipe.IsMessageComplete); return ms.ToArray();
}
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateService(
IntPtr hSCManager,
string lpServiceName,
string lpDisplayName,
uint dwDesiredAccess,
uint dwServiceType,
uint dwStartType,
uint dwErrorControl,
string lpBinaryPathName,
string lpLoadOrderGroup,
string lpdwTagId,
string lpDependencies,
string lpServiceStartName,
string lpPassword);
#region Consts
const int RESOURCE_CONNECTED = 0x00000001;
const int RESOURCE_GLOBALNET = 0x00000002;
const int RESOURCE_REMEMBERED = 0x00000003; const int RESOURCETYPE_ANY = 0x00000000;
const int RESOURCETYPE_DISK = 0x00000001;
const int RESOURCETYPE_PRINT = 0x00000002; const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005; const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
const int RESOURCEUSAGE_CONTAINER = 0x00000002; const int CONNECT_INTERACTIVE = 0x00000008;
const int CONNECT_PROMPT = 0x00000010;
const int CONNECT_REDIRECT = 0x00000080;
const int CONNECT_UPDATE_PROFILE = 0x00000001;
const int CONNECT_COMMANDLINE = 0x00000800;
const int CONNECT_CMD_SAVECRED = 0x00001000; const int CONNECT_LOCALDRIVE = 0x00000100;
#endregion #region Errors
const int NO_ERROR = 0; const int ERROR_ACCESS_DENIED = 5;
const int ERROR_ALREADY_ASSIGNED = 85;
const int ERROR_BAD_DEVICE = 1200;
const int ERROR_BAD_NET_NAME = 67;
const int ERROR_BAD_PROVIDER = 1204;
const int ERROR_CANCELLED = 1223;
const int ERROR_EXTENDED_ERROR = 1208;
const int ERROR_INVALID_ADDRESS = 487;
const int ERROR_INVALID_PARAMETER = 87;
const int ERROR_INVALID_PASSWORD = 1216;
const int ERROR_MORE_DATA = 234;
const int ERROR_NO_MORE_ITEMS = 259;
const int ERROR_NO_NET_OR_BAD_PATH = 1203;
const int ERROR_NO_NETWORK = 1222; const int ERROR_BAD_PROFILE = 1206;
const int ERROR_CANNOT_OPEN_PROFILE = 1205;
const int ERROR_DEVICE_IN_USE = 2404;
const int ERROR_NOT_CONNECTED = 2250;
const int ERROR_OPEN_FILES = 2401; private struct ErrorClass
{
public int num;
public string message;
public ErrorClass(int num, string message)
{
this.num = num;
this.message = message;
}
} // Created with excel formula:
// ="new ErrorClass("&A1&", """&PROPER(SUBSTITUTE(MID(A1,7,LEN(A1)-6), "_", " "))&"""), "
private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"),
new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"),
new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"),
new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"),
new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"),
new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"),
new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"),
new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"),
new ErrorClass(ERROR_MORE_DATA, "Error: More Data"),
new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"),
new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"),
new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"),
new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"),
new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"),
new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"),
new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"),
}; private static string getErrorForNumber(int errNum)
{
foreach (ErrorClass er in ERROR_LIST)
{
if (er.num == errNum) return er.message;
}
return "Error: Unknown, " + errNum;
}
#endregion [DllImport("Mpr.dll")]
private static extern int WNetUseConnection(
IntPtr hwndOwner,
NETRESOURCE lpNetResource,
string lpPassword,
string lpUserID,
int dwFlags,
string lpAccessName,
string lpBufferSize,
string lpResult
); [DllImport("Mpr.dll")]
private static extern int WNetCancelConnection2(
string lpName,
int dwFlags,
bool fForce
); [StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public int dwScope = 0;
public int dwType = 0;
public int dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = "";
public string lpRemoteName = "";
public string lpComment = "";
public string lpProvider = "";
} public static string connectToRemote(string remoteUNC, string username, string password)
{
return connectToRemote(remoteUNC, username, password, false);
} public static string connectToRemote(string remoteUNC, string username, string password, bool promptUser)
{
NETRESOURCE nr = new NETRESOURCE();
nr.dwType = RESOURCETYPE_DISK;
nr.lpRemoteName = remoteUNC;
// nr.lpLocalName = "F:"; int ret;
if (promptUser)
ret = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
else
ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null); if (ret == NO_ERROR) return null;
return getErrorForNumber(ret);
} public static string disconnectRemote(string remoteUNC)
{
int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false);
if (ret == NO_ERROR) return null;
return getErrorForNumber(ret);
}
private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
private const string SERVICES_ACTIVE_DATABASE = null; private class SERVICE_STATUS
{
public int dwServiceType = 0;
public ServiceState dwCurrentState = 0;
public int dwControlsAccepted = 0;
public int dwWin32ExitCode = 0;
public int dwServiceSpecificExitCode = 0;
public int dwCheckPoint = 0;
public int dwWaitHint = 0;
} #region OpenSCManagerW
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr OpenSCManagerW(string machineName, string databaseName, ScmAccessRights dwDesiredAccess);
#endregion #region OpenService
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceAccessRights dwDesiredAccess);
#endregion #region CreateService
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceAccessRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword);
#endregion #region CloseServiceHandle
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseServiceHandle(IntPtr hSCObject);
#endregion #region QueryServiceStatus
[DllImport("advapi32.dll")]
private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus);
#endregion #region DeleteService
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteService(IntPtr hService);
#endregion #region ControlService
[DllImport("advapi32.dll")]
private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus);
#endregion #region StartService
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int StartService(IntPtr hService, int dwNumServiceArgs, int lpServiceArgVectors);
#endregion public static void Uninstall(string serviceName)
{
IntPtr scm = OpenSCManagerW("192.168.1.100", SERVICES_ACTIVE_DATABASE, ScmAccessRights.AllAccess); try
{
IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess);
if (service == IntPtr.Zero)
throw new ApplicationException("Service not installed."); try
{
StopService(service);
if (!DeleteService(service))
throw new ApplicationException("Could not delete service " + Marshal.GetLastWin32Error());
}
finally
{
CloseServiceHandle(service);
}
}
finally
{
CloseServiceHandle(scm);
}
} public static bool ServiceIsInstalled(string serviceName)
{
IntPtr scm = OpenSCManagerW("192.168.1.100", SERVICES_ACTIVE_DATABASE, ScmAccessRights.AllAccess); try
{
IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus); if (service == IntPtr.Zero)
return false; CloseServiceHandle(service);
return true;
}
finally
{
CloseServiceHandle(scm);
}
} public static void InstallAndStart(string serviceName, string displayName, string fileName)
{
IntPtr scm = OpenSCManagerW("192.168.1.100", SERVICES_ACTIVE_DATABASE, ScmAccessRights.AllAccess); try
{
IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess); if (service == IntPtr.Zero)
service = CreateService(scm, serviceName, displayName, ServiceAccessRights.AllAccess, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Normal, fileName, null, IntPtr.Zero, null, null, null); if (service == IntPtr.Zero)
throw new ApplicationException("Failed to install service."); try
{
StartService(service);
}
finally
{
CloseServiceHandle(service);
}
}
finally
{
CloseServiceHandle(scm);
}
} public static void Install(string serviceName, string displayName, string fileName)
{
IntPtr scm = OpenSCManagerW("192.168.1.100", SERVICES_ACTIVE_DATABASE, ScmAccessRights.AllAccess); try
{
IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess); if (service == IntPtr.Zero)
service = CreateService(scm, serviceName, displayName, ServiceAccessRights.AllAccess, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Ignore, fileName, null, IntPtr.Zero, null, null, null); if (service == IntPtr.Zero)
throw new ApplicationException("Failed to install service.");
}
finally
{
CloseServiceHandle(scm);
}
} public static void StartService(string serviceName)
{
IntPtr scm = OpenSCManagerW("192.168.1.100", SERVICES_ACTIVE_DATABASE,ScmAccessRights.Connect); try
{
IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.AllAccess);
if (service == IntPtr.Zero)
throw new ApplicationException("Could not open service."); try
{
StartService(service);
}
finally
{
CloseServiceHandle(service);
}
}
finally
{
CloseServiceHandle(scm);
}
} public static void StopService(string serviceName)
{
IntPtr scm = OpenSCManagerW("192.168.1.100", SERVICES_ACTIVE_DATABASE, ScmAccessRights.AllAccess); try
{
IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus | ServiceAccessRights.Stop);
if (service == IntPtr.Zero)
throw new ApplicationException("Could not open service."); try
{
StopService(service);
}
finally
{
CloseServiceHandle(service);
}
}
finally
{
CloseServiceHandle(scm);
}
} private static void StartService(IntPtr service)
{
SERVICE_STATUS status = new SERVICE_STATUS();
StartService(service, 0, 0);
var changedStatus = WaitForServiceStatus(service, ServiceState.StartPending, ServiceState.Running);
if (!changedStatus)
throw new ApplicationException("Unable to start service");
} private static void StopService(IntPtr service)
{
SERVICE_STATUS status = new SERVICE_STATUS();
ControlService(service, ServiceControl.Stop, status);
var changedStatus = WaitForServiceStatus(service, ServiceState.StopPending, ServiceState.Stopped);
if (!changedStatus)
throw new ApplicationException("Unable to stop service");
} public static ServiceState GetServiceStatus(string serviceName)
{
IntPtr scm = OpenSCManagerW("192.168.1.100", SERVICES_ACTIVE_DATABASE, ScmAccessRights.AllAccess); try
{
IntPtr service = OpenService(scm, serviceName, ServiceAccessRights.QueryStatus);
if (service == IntPtr.Zero)
return ServiceState.NotFound; try
{
return GetServiceStatus(service);
}
finally
{
CloseServiceHandle(service);
}
}
finally
{
CloseServiceHandle(scm);
}
} private static ServiceState GetServiceStatus(IntPtr service)
{
SERVICE_STATUS status = new SERVICE_STATUS(); if (QueryServiceStatus(service, status) == 0)
throw new ApplicationException("Failed to query service status."); return status.dwCurrentState;
} private static bool WaitForServiceStatus(IntPtr service, ServiceState waitStatus, ServiceState desiredStatus)
{
SERVICE_STATUS status = new SERVICE_STATUS(); QueryServiceStatus(service, status);
if (status.dwCurrentState == desiredStatus) return true; int dwStartTickCount = Environment.TickCount;
int dwOldCheckPoint = status.dwCheckPoint; while (status.dwCurrentState == waitStatus)
{
// Do not wait longer than the wait hint. A good interval is
// one tenth the wait hint, but no less than 1 second and no
// more than 10 seconds. int dwWaitTime = status.dwWaitHint / 10; if (dwWaitTime < 1000) dwWaitTime = 1000;
else if (dwWaitTime > 10000) dwWaitTime = 10000; Thread.Sleep(dwWaitTime); // Check the status again. if (QueryServiceStatus(service, status) == 0) break; if (status.dwCheckPoint > dwOldCheckPoint)
{
// The service is making progress.
dwStartTickCount = Environment.TickCount;
dwOldCheckPoint = status.dwCheckPoint;
}
else
{
if (Environment.TickCount - dwStartTickCount > status.dwWaitHint)
{
// No progress made within the wait hint
break;
}
}
}
return (status.dwCurrentState == desiredStatus);
} private static IntPtr OpenSCManagerW(ScmAccessRights rights)
{
IntPtr scm = OpenSCManagerW(null, null, rights);
if (scm == IntPtr.Zero)
throw new ApplicationException("Could not connect to service control manager."); return scm;
}
} public enum ServiceState
{
Unknown = -1, // The state cannot be (has not been) retrieved.
NotFound = 0, // The service is not known on the host server.
Stopped = 1,
StartPending = 2,
StopPending = 3,
Running = 4,
ContinuePending = 5,
PausePending = 6,
Paused = 7
} [Flags]
public enum ScmAccessRights
{
Connect = 0x0001,
CreateService = 0x0002,
EnumerateService = 0x0004,
Lock = 0x0008,
QueryLockStatus = 0x0010,
ModifyBootConfig = 0x0020,
StandardRightsRequired = 0xF0000,
AllAccess = (StandardRightsRequired | Connect | CreateService |
EnumerateService | Lock | QueryLockStatus | ModifyBootConfig)
} [Flags]
public enum ServiceAccessRights
{
QueryConfig = 0x1,
ChangeConfig = 0x2,
QueryStatus = 0x4,
EnumerateDependants = 0x8,
Start = 0x10,
Stop = 0x20,
PauseContinue = 0x40,
Interrogate = 0x80,
UserDefinedControl = 0x100,
Delete = 0x00010000,
StandardRightsRequired = 0xF0000,
AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig |
QueryStatus | EnumerateDependants | Start | Stop | PauseContinue |
Interrogate | UserDefinedControl)
} public enum ServiceBootFlag
{
Start = 0x00000000,
SystemStart = 0x00000001,
AutoStart = 0x00000002,
DemandStart = 0x00000003,
Disabled = 0x00000004
} public enum ServiceControl
{
Stop = 0x00000001,
Pause = 0x00000002,
Continue = 0x00000003,
Interrogate = 0x00000004,
Shutdown = 0x00000005,
ParamChange = 0x00000006,
NetBindAdd = 0x00000007,
NetBindRemove = 0x00000008,
NetBindEnable = 0x00000009,
NetBindDisable = 0x0000000A
} public enum ServiceError
{
Ignore = 0x00000000,
Normal = 0x00000001,
Severe = 0x00000002,
Critical = 0x00000003
}
总结
学习完成后总结的Psexec流程
1进行ntml认证建立ipc$连接
2访问admin$文件共享传送文件
3创建服务和管道
4运行服务
5与管道进行交互获取回显 自己的psexec过程
1进行ntml认证建立ipc$
2传输文件创建服务
3启动服务
4与管道进行交互获取回显 踩坑:1:创建服务1053错误(能创建但是不能启动)
参考
https://www.anquanke.com/post/id/210323
https://www.codenong.com/51346269/
https://stackoverflow.com/questions/51346269/understanding-smb-and-dcerpc-for-remote-command-execution-capabilities
https://blog.f-secure.com/endpoint-detection-of-remote-service-creation-and-psexec/
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d35f8e7e-ebb1-43cb-b1f1-c09c716a26f4
https://www.contextis.com/en/blog/lateral-movement-a-deep-look-into-psexec
https://www.programmersought.com/article/57217175834/
https://github.com/poweradminllc/PAExec/search?q=1053
https://cpp.hotexamples.com/zh/examples/-/-/CreateService/cpp-createservice-function-examples.html
https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicew
https://payloads.online/archivers/2020-04-02/1
renfer
https://www.anquanke.com/post/id/210323
https://www.codenong.com/51346269/
https://stackoverflow.com/questions/51346269/understanding-smb-and-dcerpc-for-remote-command-execution-capabilities
https://blog.f-secure.com/endpoint-detection-of-remote-service-creation-and-psexec/
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d35f8e7e-ebb1-43cb-b1f1-c09c716a26f4
https://www.contextis.com/en/blog/lateral-movement-a-deep-look-into-psexec
https://www.programmersought.com/article/57217175834/
https://github.com/poweradminllc/PAExec/search?q=1053
https://cpp.hotexamples.com/zh/examples/-/-/CreateService/cpp-createservice-function-examples.html
https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicew
https://payloads.online/archivers/2020-04-02/1
了解PSexec的更多相关文章
- 妙用psexec分析关机一直挂起的Windows update 更新
Windows 更新服务对每个IT运维人员来说都不会陌生,而且很多情况下出现的一些不兼容,产品问题通过更新都可很好的解决掉. 小弟近日为一台老爷机服务器安装Windows 产品更新就遇到了意见事情,特 ...
- PowerShell vs. PsExec for Remote Command Execution
Posted by Jianpeng Mo / January 20, 2014 Monitoring and maintaining large-scale, complex, highly dis ...
- 有关于psExec的使用
psExec是微软pstools工具包中最常用的一个工具,也是在内网渗透中的免杀渗透利器. psExec能够在命令行下在对方没有开启telnet服务的时候返回一个半交互的命令行,像telnet客户端一 ...
- 玩转PowerShell第二节——【利用PsExec进行远程调用】-技术&分享
概述 PowerShell用的最多的地方就是远程调用,在远程机器上执行脚本,监控远程机器的状态,如NLB状态,EventLog,SqlServer DataBase状态等. 本篇将讲到用PsExec. ...
- PsExec.exe执行远程程序
PsExec.exe \\192.168.1.1 -u username -p password -i -d -s c:\Windows\system32\NETSTAT.exe -a
- MSF实现RID劫持和MSF实现PsExec执行命令
msf实现rid劫持 rid劫持原理: 每个帐户都有一个指定的RID来标识它.与域控制器不同,Windows工作站和服务器会将大部分数据存储在HKLM\SAM\SAM\Domains\Account\ ...
- 使用PsExec获取shell执行命令
PsExec PsExec是pstools工具组套件的一部分,确成为了渗透利器,下载地址:点击这里下载 连接shell 我的Windows Server 2012默认打开域网络防火墙的时候,是不能连接 ...
- PSexec以及xcopy的简单使用
1. 远程执行命令. 有时候不想远程但是想执行一些命令, 比较简单的方法是: 下载systeminternals 然后解压缩后可以讲目录放到path环境变量中 然后打开命令行工具 输入 如下的命令 p ...
- Resolve PSExec "Access is denied"
PSExec拒绝访问的解决办法 Just modify Windows Registry, and reboot. psexec_fix.reg: Windows Registry Editor Ve ...
- pstools psexec mimikatz
Psexec原理 - oneVs1的专栏 - 博客频道 - CSDN.NET 在远程终端(3389.mstsc.exe).虚拟桌面中抓取密码的方法: 通常你在远程终端中运行该程序会提示:存储空间不足, ...
随机推荐
- VuePress & Markdown Slot
VuePress & Markdown Slot refs https://vuepress.vuejs.org/zh/guide/markdown-slot.html#为什么需要-markd ...
- color recognition by image
color recognition by image 通过图像进行颜色识别 https://imagecolorpicker.com/ unknown color origin pic grey bl ...
- server sent events
server sent events server push https://html5doctor.com/server-sent-events/ https://developer.mozilla ...
- js 如何获取某一个月的第一天是周几
js 如何获取某一个月的第一天是周几 calendar ??? padding dates // day = 1 const firstMonthDate = new Date(year + mont ...
- js 监听ajax请求
function hookSend(hook) { if (!XMLHttpRequest.prototype._oldSend) XMLHttpRequest.prototype._oldSend ...
- NGK内存爆发式增长,看Baccarat将怎样打造全新的全场景金融生态
从数字货币抵押借贷业务出发,DeFi已经形成了覆盖全场景的全新金融生态. 可以说,除了信贷等少数对现实世界信息存在较多依赖的实体业务,DeFi已经实现了传统金融业务的全面链上迁移.大多数传统金融行业存 ...
- Azure Functions(二)集成 Azure Blob Storage 存储文件
一,引言 上一篇文章有介绍到什么是 SeverLess ,ServerLess 都有哪些特点,以及多云环境下 ServerLess 都有哪些解决方案.在这众多解决方案中就包括 Function App ...
- keepalived-1.3.5+MHA部署mysql集群
MHA: MHA工作原理总结为以下几条: 从宕机崩溃的master保存二进制日志事件(binlog events): 识别含有最新更新的slave: 应用差异的中继日志(relay log)到其他sl ...
- Python学习笔记_类
class Animal(object): # 定义父类animal def __init__(self,name,sound): # 初始化属性 name sound self.name = nam ...
- ArrayList的简单实现
class AList<E>{ //属性:数组和实际元素个数 private Object[] data; private int size; //构造函数:有参.无参 public AL ...