了解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用户登录看看

了解PSexec

 

 可以看见日志4624后又紧跟着4634直接注销了,注销是因为web用户没有访问Admin$共享的权限

了解PSexec

 有关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$共享写入文件的步骤了解PSexec

 

 我们需要知道的是传输文件这整个过程 与其交互的仅仅是445端口

了解PSexec

 

 但是我们发现这里为什么使用了DCE/RPC和EPM走了135端口,那么必须一定要走一次135吗?这里调用DCE/RPC和EPM的作用又是什么?我们带着问题继续思考

了解PSexec

 可以知道DCE/RPC协议是基于MSRPC协议的,而DCERPC并没有创建服务,只是一个远程调用协议。

https://*.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开放的包有什么区别

了解PSexec

 

 可以看见这里的DCERPC协议的作用和开放135端口情况下的DCERPC协议的作用是不相同的,

了解PSexec

 

 

然后紧接着安装psexesvc服务

了解PSexec

 

 这里又创建了一些列的命名管道

首先,我们需要清楚的是,命名管道基于smb协议,smb,smb而不是tcp进行通信。重要的事情说了三遍。它用于在两个进程之间进行通信。这两个进程可以是本地进程或远程进程。命名管道有点类似于套接字连接。它们用于传输数据。可以设置特定的权限,以便具有指定权限的进程可以连接到命名管道。从理论上讲,每个程序都可以连接到命名管道,但是它们在连接后可以做不同的事情。可以完成的操作取决于服务器的配置。
以下总结了几点:
1.命名管道是C / S体系结构,服务器上的进程必须首先创建一个命名管道。
2.可以通过满足权限的任何进程访问命名管道,并且可以自定义可以访问哪些权限。
3.客户端可以是本地进程,也可以是远程进程。本地进程访问\。\ pipe \ pipename中的命名管道,而远程进程访问\ ip \ pipe \ pipename。

了解PSexec

上面的psexesvc管道是用于服务本身的,但是下面这三个管道则不是

了解PSexec

 

 

更具以上分析搞了一个自己的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://*.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://*.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://*.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

 

上一篇:天池大赛——天猫用户复购预测


下一篇:JS中click失效的可能原因!!!!