了解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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM