csharp/0xthirteen/SharpRDP/SharpRDP/SharpRDP/Client.cs

Client.cs
using System;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using AxMSTSCLib;
using MSTSCLib;

namespace SharpRDP
{
    public clast Client
    {
        private Dictionary keycode;
        private IMsRdpClientNonScriptable keydata;
        private int LogonErrorCode { get; set; }
        private int DisconnectCode { get; set; }
        private string cmd;
        private string execwith;
        private string target;
        private string runtype;
        private bool isdrive;
        private bool takeover;
        private bool networkauth;
        private enum LogonErrors : uint
        {
            ARBITRATION_CODE_BUMP_OPTIONS = 0xFFFFFFFB,
            ARBITRATION_CODE_CONTINUE_LOGON = 0xFFFFFFFE,
            ARBITRATION_CODE_CONTINUE_TERMINATE = 0xFFFFFFFD,
            ARBITRATION_CODE_NOPERM_DIALOG = 0xFFFFFFFA,
            ARBITRATION_CODE_REFUSED_DIALOG = 0xFFFFFFF9,
            ARBITRATION_CODE_RECONN_OPTIONS = 0xFFFFFFFC,
            ERROR_CODE_ACCESS_DENIED = 0xFFFFFFFF,
            LOGON_FAILED_BAD_PastWORD = 0x0,
            LOGON_FAILED_OTHER = 0x2,
            LOGON_FAILED_UPDATE_PastWORD = 0x1,
            LOGON_WARNING = 0x3,
            STATUS_ACCOUNT_RESTRICTION = 0xC000006E,
            STATUS_LOGON_FAILURE = 0xC000006D,
            STATUS_PastWORD_MUST_CHANGE = 0xC0000224
        }
        private enum DisconnectReasons : uint
        {
            disconnectReasonAtClientWinsockFDCLOSE = 0x904,
            disconnectReasonByServer = 0x3,
            disconnectReasonClientDecompressionError = 0xC08,
            disconnectReasonConnectionTimedOut = 0x108,
            disconnectReasonDecryptionError = 0xC06,
            disconnectReasonDNSLookupFailed = 0x104,
            disconnectReasonDNSLookupFailed2 = 0x508,
            disconnectReasonEncryptionError = 0xB06,
            disconnectReasonGetHostByNameFailed = 0x604,
            disconnectReasonHostNotFound = 0x208,
            disconnectReasonInternalError = 0x408,
            disconnectReasonInternalSecurityError = 0x906,
            disconnectReasonInternalSecurityError2 = 0xA06,
            disconnectReasonInvalidEncryption = 0x506,
            disconnectReasonInvalidIP = 0x804,
            disconnectReasonInvalidServerSecurityInfo = 0x606,
            disconnectReasonInvalidSecurityData = 0x406,
            disconnectReasonInvalidIPAddr = 0x308,
            disconnectReasonLicensingFailed = 0x808,
            disconnectReasonLicensingTimeout = 0x908,
            disconnectReasonLocalNotError = 0x1,
            disconnectReasonNoInfo = 0x0,
            disconnectReasonOutOfMemory = 0x106,
            disconnectReasonOutOfMemory2 = 0x206,
            disconnectReasonOutOfMemory3 = 0x306,
            disconnectReasonRemoteByUser = 0x2,
            disconnectReasonServerCertificateUnpackErr = 0x706,
            disconnectReasonSocketConnectFailed = 0x204,
            disconnectReasonSocketRecvFailed = 0x404,
            disconnectReasonTimeoutOccurred = 0x704,
            disconnectReasonTimerError = 0x608,
            disconnectReasonWinsockSendFailed = 0x304,
            SSL_ERR_ACCOUNT_DISABLED = 0xB07,
            SSL_ERR_ACCOUNT_EXPIRED = 0xE07,
            SSL_ERR_ACCOUNT_LOCKED_OUT = 0xD07,
            SSL_ERR_ACCOUNT_RESTRICTION = 0xC07,
            SSL_ERR_CERT_EXPIRED = 0x1B07,
            SSL_ERR_DELEGATION_POLICY = 0x1607,
            SSL_ERR_FRESH_CRED_REQUIRED_BY_SERVER = 0x2107,
            SSL_ERR_LOGON_FAILURE = 0x807,
            SSL_ERR_NO_AUTHENTICATING_AUTHORITY = 0x1807,
            SSL_ERR_NO_SUCH_USER = 0xA07,
            SSL_ERR_PastWORD_EXPIRED = 0xF07,
            SSL_ERR_PastWORD_MUST_CHANGE = 0x1207,
            SSL_ERR_POLICY_NTLM_ONLY = 0x1707,
            SSL_ERR_SMARTCARD_CARD_BLOCKED = 0x2207,
            SSL_ERR_SMARTCARD_WRONG_PIN = 0x1C07
        }

        public void CreateRdpConnection(string server, string user, string domain, string pastword, string command, string execw, string runelevated, bool condrive, bool tover, bool nla)
        {
            keycode = new Dictionary();
            KeyCodes();
            runtype = runelevated;
            isdrive = condrive;
            cmd = command;
            target = server;
            execwith = execw;
            takeover = tover;
            networkauth = nla;

            void ProcessTaskThread()
            {
                var form = new Form();
                form.Opacity = 0;
                form.Visible = false;
                form.WindowState = FormWindowState.Minimized;
                form.ShowInTaskbar = false;
                form.FormBorderStyle = FormBorderStyle.None;
                form.Width = Screen.PrimaryScreen.WorkingArea.Width;
                form.Height = Screen.PrimaryScreen.WorkingArea.Height;
                form.Load += (sender, args) =>
                {
                    var rdpConnection = new AxMsRdpClient9NotSafeForScripting();
                    form.Controls.Add(rdpConnection);
                    var rdpC = rdpConnection.GetOcx() as IMsRdpClientNonScriptable5;
                    IMsRdpExtendedSettings rdpc2 = rdpConnection.GetOcx() as IMsRdpExtendedSettings;
                    rdpC.AllowPromptingForCredentials = false;
                    rdpC.AllowCredentialSaving = false;
                    rdpConnection.Server = server;
                    rdpConnection.Domain = domain;
                    rdpConnection.UserName = user;
                    rdpConnection.AdvancedSettings9.allowBackgroundInput = 1;
                    rdpConnection.AdvancedSettings9.BitmapPersistence = 0;
                    if(condrive == true)
                    {
                        rdpConnection.AdvancedSettings5.RedirectDrives = true;
                    }
                    if (pastword != string.Empty || user != string.Empty)
                    {
                        rdpConnection.UserName = user;
                        rdpConnection.AdvancedSettings9.ClearTextPastword = pastword;
                    }
                    else
                    {
                        rdpc2.set_Property("RestrictedLogon", true);
                        rdpc2.set_Property("DisableCredentialsDelegation", true);
                    }
                    rdpConnection.AdvancedSettings9.EnableCredSspSupport = true;
                    if(networkauth == true)
                    {
                        rdpC.NegotiateSecurityLayer = true;
                    }
                    if (true)
                    {
                        rdpConnection.OnDisconnected += RdpConnectionOnOnDisconnected;
                        rdpConnection.OnLoginComplete += RdpConnectionOnOnLoginComplete;
                        rdpConnection.OnLogonError += RdpConnectionOnOnLogonError;
                    }
                    rdpConnection.Connect();
                    rdpConnection.Enabled = false;
                    rdpConnection.Dock = DockStyle.Fill;
                    Application.Run(form);
                };
                form.Show();
            }

            var rdpClientThread = new Thread(ProcessTaskThread) { IsBackground = true };
            rdpClientThread.SetApartmentState(ApartmentState.STA);
            rdpClientThread.Start();
            while (rdpClientThread.IsAlive)
            {
                Task.Delay(500).GetAwaiter().GetResult();
            }
        }

        private void RdpConnectionOnOnLogonError(object sender, IMsTscAxEvents_OnLogonErrorEvent e)
        {
            LogonErrorCode = e.lError;
            var errorstatus = Enum.GetName(typeof(LogonErrors), (uint)LogonErrorCode);
            Console.WriteLine("[-] Logon Error           :  {0} - {1}", LogonErrorCode, errorstatus);
            Thread.Sleep(1000);

            if(LogonErrorCode == -5 && takeover == true)
            {
                // it doesn't go to the logon event, so this has to be done here
                var rdpSession = (AxMsRdpClient9NotSafeForScripting)sender;
                Thread.Sleep(1000);
                keydata = (IMsRdpClientNonScriptable)rdpSession.GetOcx();
                Console.WriteLine("[+] Another user is logged on, asking to take over session");
                SendElement("Tab");
                Thread.Sleep(500);
                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");
                Thread.Sleep(500);
                Console.WriteLine("[+] Sleeping for 30 seconds");
                Task.Delay(31000).GetAwaiter().GetResult();
                Marshal.ReleaseComObject(rdpSession);
                Marshal.ReleaseComObject(keydata);
            }
            else if (LogonErrorCode != -2)
            {
                Environment.Exit(0);
            }
        }

        private void RdpConnectionOnOnLoginComplete(object sender, EventArgs e)
        {
            var rdpSession = (AxMsRdpClient9NotSafeForScripting)sender;
            Console.WriteLine("[+] Connected to          :  {0}", target);
            Thread.Sleep(1000);
            keydata = (IMsRdpClientNonScriptable)rdpSession.GetOcx();

            if (LogonErrorCode == -2)
            {
                Console.WriteLine("[+] User not currently logged in, creating new session");
                Task.Delay(10000).GetAwaiter().GetResult();
            }

            string privinfo = "non-elevated";
            if (runtype != string.Empty)
            {
                privinfo = "elevated";
            }
            Console.WriteLine("[+] Execution priv type   :  {0}", privinfo);
            Thread.Sleep(1000);

            SendElement("Win+R+down");
            Thread.Sleep(500);
            SendElement("Win+R+up");
            Thread.Sleep(1000);

            if (execwith == "cmd")
            {
                RunConsole("cmd.exe");
            }
            else if (execwith == "powershell" || execwith == "ps")
            {
                RunConsole("powershell.exe");
            }
            else
            {
                RunRun();
            }

            Thread.Sleep(1000);
            Console.WriteLine("[+] Disconnecting from    :  {0}", target);
            rdpSession.Disconnect();
        }

        private void RdpConnectionOnOnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
        {
            DisconnectCode = e.discReason;
            var dire = Enum.GetName(typeof(DisconnectReasons), (uint)DisconnectCode);
            Console.WriteLine("[+] Connection closed     :  {0}", target);
            if(e.discReason != 1)
            {
                Console.WriteLine("[-] Disconnection Reason  :  {0} - {1}", DisconnectCode, dire);
            }
            Environment.Exit(0);
        }

        private void RunRun()
        {
            if(runtype == "taskmgr")
            {
                Console.WriteLine("[+] Running task manager");
                Thread.Sleep(500);
                SendText("taskmgr");
                Thread.Sleep(1000);

                Thread.Sleep(500);
                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");

                SendElement("Alt+F");
                Thread.Sleep(1000);

                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");
                Thread.Sleep(500);
            }

            Console.WriteLine("[+] Executing {0}", cmd.ToLower());
            SendText(cmd.ToLower());
            Thread.Sleep(1000);

            if (runtype == "taskmgr")
            {
                SendElement("Tab");
                Thread.Sleep(500);
                SendElement("Space");
                Thread.Sleep(500);
            }

            if(runtype == "winr")
            {
                //Currently bugged - does not run elevated
                SendElement("Ctrl+Shift+down");
                Thread.Sleep(500);
                SendElement("Enter+down");
                Thread.Sleep(250);
                SendElement("Enter+up");
                Thread.Sleep(500);
                SendElement("Ctrl+Shift+up");
                Thread.Sleep(500);
            }
            else
            {
                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");
                Thread.Sleep(250);
            }

            if (isdrive == true)
            {
                SendElement("Left");
                Thread.Sleep(500);
                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");
            }
            
            if (runtype == "winr")
            {
                SendElement("Left");
                Thread.Sleep(500);
                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");
            }
            if (runtype == "taskmgr")
            {
                Thread.Sleep(250);
                SendElement("Alt+F4");
            }
        }

        private void RunConsole(string consoletype)
        {
            if (runtype == "taskmgr")
            {
                Console.WriteLine("[+] Executing task manager");
                Thread.Sleep(500);
                SendText("taskmgr");
                Thread.Sleep(1000);

                Thread.Sleep(500);
                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");

                SendElement("Alt+F");
                Thread.Sleep(1000);

                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");
                Thread.Sleep(500);
            }

            Console.WriteLine("[+] Executing {0} from {1}", cmd.ToLower(), consoletype);
            SendText(consoletype);
            Thread.Sleep(1000);

            if (runtype == "taskmgr")
            {
                SendElement("Tab");
                Thread.Sleep(500);
                SendElement("Space");
                Thread.Sleep(250);
            }

            if (runtype == "winr")
            {
                //Currently bugged - does not run elevated
                SendElement("Ctrl+Shift+down");
                Thread.Sleep(500);
                SendElement("Enter+down");
                Thread.Sleep(250);
                SendElement("Enter+up");
                Thread.Sleep(500);
                SendElement("Ctrl+Shift+up");
                Thread.Sleep(500);
            }
            else
            {
                SendElement("Enter+down");
                Thread.Sleep(500);
                SendElement("Enter+up");
                Thread.Sleep(250);
            }

            Thread.Sleep(500);
            SendText(cmd.ToLower());

            Thread.Sleep(1000);

            SendElement("Enter+down");
            Thread.Sleep(500);
            SendElement("Enter+up");

            Thread.Sleep(500);
            SendText("exit");

            SendElement("Enter+down");
            Thread.Sleep(500);
            SendElement("Enter+up");

            if(runtype == "taskmgr")
            {
                Thread.Sleep(250);
                SendElement("Alt+F4");
                Thread.Sleep(250);
            }
        }

        public void SendText(String text)
        {
            foreach (var t in text)
            {
                var symbol = t.ToString();
                keydata.SendKeys(keycode[symbol].length, ref keycode[symbol].bools[0], ref keycode[symbol].ints[0]);
                Thread.Sleep(10);
            }
        }

        private void SendElement(String curchars)
        {
            var current = keycode[curchars];
            keydata.SendKeys(current.length, ref current.bools[0], ref current.ints[0]);
            Thread.Sleep(10);
        }

        private void KeyCodes()
        {
            keycode["Esc"] = new Code(new[] { false, true }, new[] { 0x01 });
            keycode["Enter+down"] = new Code(new[] { false }, new[] { 0x1c });
            keycode["Enter+up"] = new Code(new[] { true }, new[] { 0x1c });
            keycode["Win"] = new Code(new[] { false, true }, new[] { 0x15b });
            keycode["Down"] = new Code(new[] { false, true }, new[] { 0x150 });
            keycode["Right"] = new Code(new[] { false, true }, new[] { 0x14d });
            keycode["Left"] = new Code(new[] { false, true }, new[] { 0x14b });
            keycode["Alt"] = new Code(new[] { false, true }, new[] { 0x38 });
            keycode["Shift"] = new Code(new[] { false, true }, new[] { 0x2a });
            keycode["Space"] = new Code(new[] { false, true }, new[] { 0x39 });
            keycode["Tab"] = new Code(new[] { false, true }, new[] { 0x0f });

            keycode["Calc"] = new Code(new[] { false, true }, new[] { 0x121, 0x121 });
            keycode["Paste"] = new Code(new[] { false, true }, new[] { 0x10a, 0x10a });

            keycode["1"] = new Code(new[] { false, true }, new[] { 0x02 });
            keycode["2"] = new Code(new[] { false, true }, new[] { 0x03 });
            keycode["3"] = new Code(new[] { false, true }, new[] { 0x04 });
            keycode["4"] = new Code(new[] { false, true }, new[] { 0x05 });
            keycode["5"] = new Code(new[] { false, true }, new[] { 0x06 });
            keycode["6"] = new Code(new[] { false, true }, new[] { 0x07 });
            keycode["7"] = new Code(new[] { false, true }, new[] { 0x08 });
            keycode["8"] = new Code(new[] { false, true }, new[] { 0x09 });
            keycode["9"] = new Code(new[] { false, true }, new[] { 0x0a });
            keycode["0"] = new Code(new[] { false, true }, new[] { 0x0b });
            keycode["-"] = new Code(new[] { false, true }, new[] { 0x0c });

            keycode["a"] = new Code(new[] { false, true }, new[] { 0x1e });
            keycode["b"] = new Code(new[] { false, true }, new[] { 0x30 });
            keycode["c"] = new Code(new[] { false, true }, new[] { 0x2e });
            keycode["d"] = new Code(new[] { false, true }, new[] { 0x20 });
            keycode["e"] = new Code(new[] { false, true }, new[] { 0x12 });
            keycode["f"] = new Code(new[] { false, true }, new[] { 0x21 });
            keycode["g"] = new Code(new[] { false, true }, new[] { 0x22 });
            keycode["h"] = new Code(new[] { false, true }, new[] { 0x23 });
            keycode["i"] = new Code(new[] { false, true }, new[] { 0x17 });
            keycode["j"] = new Code(new[] { false, true }, new[] { 0x24 });
            keycode["k"] = new Code(new[] { false, true }, new[] { 0x25 });
            keycode["l"] = new Code(new[] { false, true }, new[] { 0x26 });
            keycode["m"] = new Code(new[] { false, true }, new[] { 0x32 });
            keycode["n"] = new Code(new[] { false, true }, new[] { 0x31 });
            keycode["o"] = new Code(new[] { false, true }, new[] { 0x18 });
            keycode["p"] = new Code(new[] { false, true }, new[] { 0x19 });
            keycode["q"] = new Code(new[] { false, true }, new[] { 0x10 });
            keycode["r"] = new Code(new[] { false, true }, new[] { 0x13 });
            keycode["s"] = new Code(new[] { false, true }, new[] { 0x1f });
            keycode["t"] = new Code(new[] { false, true }, new[] { 0x14 });
            keycode["u"] = new Code(new[] { false, true }, new[] { 0x16 });
            keycode["v"] = new Code(new[] { false, true }, new[] { 0x2f });
            keycode["w"] = new Code(new[] { false, true }, new[] { 0x11 });
            keycode["x"] = new Code(new[] { false, true }, new[] { 0x2d });
            keycode["y"] = new Code(new[] { false, true }, new[] { 0x15 });
            keycode["z"] = new Code(new[] { false, true }, new[] { 0x2c });
            keycode[" "] = new Code(new[] { false, true }, new[] { 0x39 });

            keycode[","] = new Code(new[] { false, true }, new[] { 0x33 });
            keycode["."] = new Code(new[] { false, true }, new[] { 0x34 });
            keycode["/"] = new Code(new[] { false, true }, new[] { 0x35 });
            keycode["["] = new Code(new[] { false, true }, new[] { 0x1a });
            keycode["]"] = new Code(new[] { false, true }, new[] { 0x1b });
            keycode["\\"] = new Code(new[] { false, true }, new[] { 0x2b });
            keycode[";"] = new Code(new[] { false, true }, new[] { 0x27 });
            keycode["'"] = new Code(new[] { false, true }, new[] { 0x28 });

            keycode["\""] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x28 });
            keycode[":"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x27 });
            keycode["|"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x2b });
            keycode["&"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x08 });
            keycode["%"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x06 });
            keycode["("] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x0a });
            keycode[")"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x0b });

            keycode["Win+R+down"] = new Code(new[] { false, false }, new[] { 0x15b, 0x13 });
            keycode["Win+R+up"] = new Code(new[] { true, true }, new[] { 0x15b, 0x13 });
            keycode["Win+D"] = new Code(new[] { false, false, true, true }, new[] { 0x15b, 0x20 });
            keycode["Alt+Shift"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x2a });
            keycode["Alt+Space"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x39 });
            keycode["Ctrl+Shift"] = new Code(new[] { false, false, true, true }, new[] { 0x1d, 0x2a });
            keycode["Alt+F4"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x3e });
            keycode["Ctrl+V"] = new Code(new[] { false, false, true, true }, new[] { 0x1d, 0x2f });
            keycode["Alt+F"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x21 });

            keycode["Ctrl+Shift+down"] = new Code(new[] { false, false }, new[] { 0x1d, 0x2a });
            keycode["Ctrl+Shift+up"] = new Code(new[] { true, true }, new[] { 0x1d, 0x2a });
        }
    }
}