diff --git a/Tubio/CMakeLists.txt b/Tubio/CMakeLists.txt index 5503758..080830f 100755 --- a/Tubio/CMakeLists.txt +++ b/Tubio/CMakeLists.txt @@ -4,7 +4,7 @@ project(Tubio) # Set C++ standard set(CMAKE_CXX_STANDARD 17) -# Add StringTools src dir to include dir list +# Add external-directories dir to include dir list include_directories(./external_dependencies/) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") @@ -43,7 +43,9 @@ add_executable(Tubio XGControl.h external_dependencies/casenta/mongoose/mongoose.c external_dependencies/casenta/mongoose/mongoose.h - external_dependencies/leonetienne/JasonPP/JasonPP.hpp external_dependencies/leonetienne/JasonPP/JasonPP.cpp + external_dependencies/leonetienne/JasonPP/JasonPP.hpp + external_dependencies/leonetienne/stringtools/StringTools.cpp + external_dependencies/leonetienne/stringtools/StringTools.h ) diff --git a/Tubio/HttpServer.cpp b/Tubio/HttpServer.cpp index a72c575..eee915e 100644 --- a/Tubio/HttpServer.cpp +++ b/Tubio/HttpServer.cpp @@ -1,4 +1,5 @@ #include "HttpServer.h" +#include "external_dependencies/leonetienne/stringtools/StringTools.h" using namespace Logging; using namespace Rest; @@ -137,6 +138,15 @@ void HttpServer::EventHandler(mg_connection* pNc, int ev, void* p) return; } +std::string HttpServer::SanitizeString(std::string in) { + in = StringTools::Replace(in, '`', "\\\\`"); + in = StringTools::Replace(in, '|', "\\\\|"); + in = StringTools::Replace(in, '$', "\\\\$"); + in = StringTools::Replace(in, "&&", "\\\\&\\\\&"); + + return in; +} + void HttpServer::ProcessAPIRequest(mg_connection* pNc, int ev, void* p, std::string peerAddress) { // Get struct with http message informations @@ -144,6 +154,9 @@ void HttpServer::ProcessAPIRequest(mg_connection* pNc, int ev, void* p, std::str // Get the transmitted message body std::string requestBodyRaw = FixUnterminatedString(hpm->body.p, hpm->body.len); + + // Sanitize it + requestBodyRaw = SanitizeString(requestBodyRaw); // Check for the body being valid json if (IsJsonValid(requestBodyRaw)) diff --git a/Tubio/HttpServer.h b/Tubio/HttpServer.h index 5a8c1d6..0f95a43 100644 --- a/Tubio/HttpServer.h +++ b/Tubio/HttpServer.h @@ -31,6 +31,8 @@ namespace Rest static bool IsConnectionAllowed(std::string peer_address, std::string& denialReason); + //! Will remove all `, | and && from a string to prevent remote code execution + static std::string SanitizeString(std::string in); struct mg_mgr* pMgr; struct mg_connection* pNc; diff --git a/Tubio/Version.h b/Tubio/Version.h index 71a977b..147f94f 100644 --- a/Tubio/Version.h +++ b/Tubio/Version.h @@ -1,2 +1,2 @@ #pragma once -#define TUBIO_SERVER_VERSION (0.6) +#define TUBIO_SERVER_VERSION (0.65) diff --git a/Tubio/external_dependencies/leonetienne/stringtools/StringTools.cpp b/Tubio/external_dependencies/leonetienne/stringtools/StringTools.cpp new file mode 100644 index 0000000..fe16c93 --- /dev/null +++ b/Tubio/external_dependencies/leonetienne/stringtools/StringTools.cpp @@ -0,0 +1,155 @@ +#include "StringTools.h" +#include + +std::string StringTools::Replace(const std::string& str, const char find, const std::string& subst) { + std::stringstream ss; + + for (std::size_t i = 0; i < str.length(); i++) + { + if (str[i] != find) + ss << str[i]; + else + ss << subst; + } + + return ss.str(); +} + +std::string StringTools::Replace(const std::string& str, const std::string& find, const std::string& subst) { + if (find.length() == 0) + return str; + + std::stringstream ss; + + std::size_t posFound = 0; + std::size_t lastFound = 0; + + while (posFound != std::string::npos) + { + lastFound = posFound; + posFound = str.find(find, posFound); + + if (posFound != std::string::npos) + { + ss << str.substr(lastFound, posFound - lastFound) << subst; + posFound += find.length(); + } + else + { + ss << str.substr(lastFound, (str.length()) - lastFound); + } + } + + return ss.str(); +} + +std::string StringTools::Replace(const std::string& str, const char find, const char subst) { + std::stringstream ss; + ss << subst; + + return Replace(str, find, ss.str()); +} + +std::string StringTools::Replace(const std::string& str, const std::string& find, const char subst) { + std::stringstream ss; + ss << subst; + + return Replace(str, find, ss.str()); +} + +std::string StringTools::Lower(const std::string& str) { + std::stringstream ss; + + for (std::size_t i = 0; i < str.size(); i++) + { + const char c = str[i]; + + // Quick-accept: regular letters + if ((c >= 'A') && (c <= 'Z')) + ss << (char)(c | 32); + + // Else: keep the character as is + else ss << c; + } + + return ss.str(); +} + +std::string StringTools::Upper(const std::string& str) { + std::stringstream ss; + + for (std::size_t i = 0; i < str.size(); i++) + { + const char c = str[i]; + + // Quick-accept: regular letters + if ((c >= 'a') && (c <= 'z')) + ss << (char)(c & ~32); + + // Else: keep the character as is + else ss << c; + } + + return ss.str(); +} + +std::vector StringTools::Split(const std::string& str, const std::string& seperator) { + std::vector toRet; + // Quick-accept: str length is 0 + if (str.length() == 0) + toRet.push_back(""); + + // Quick-accept: seperator length is 0 + else if (seperator.length() == 0) { + for (const char c : str) + toRet.push_back(std::string(&c, (&c) + 1)); + } + + else { + std::size_t idx = 0; + while (idx != std::string::npos) { + std::size_t lastIdx = idx; + idx = str.find(seperator, idx); + + // Grab our substring until the next finding of sep + if (idx != std::string::npos) { + toRet.push_back(str.substr( + lastIdx, + idx - lastIdx + )); + + idx += seperator.length(); + } + // No more seperator found. Grab the rest until the end of the string + else { + toRet.push_back(str.substr( + lastIdx + )); + } + } + } + + return toRet; +} + +std::string StringTools::PadLeft(const std::string& str, const char pad, const std::size_t len) { + std::stringstream ss; + + for (std::size_t i = str.length(); i < len; i++) + ss << pad; + + ss << str; + + return ss.str(); +} + +std::string StringTools::PadRight(const std::string& str, const char pad, const std::size_t len) { + std::stringstream ss; + + ss << str; + + for (std::size_t i = str.length(); i < len; i++) + ss << pad; + + return ss.str(); +} diff --git a/Tubio/external_dependencies/leonetienne/stringtools/StringTools.h b/Tubio/external_dependencies/leonetienne/stringtools/StringTools.h new file mode 100644 index 0000000..e8de59d --- /dev/null +++ b/Tubio/external_dependencies/leonetienne/stringtools/StringTools.h @@ -0,0 +1,43 @@ +#ifndef STRINGTOOLS_STRINGTOOLS_H +#define STRINGTOOLS_STRINGTOOLS_H + +#include +#include + +/* Handy utensils to manipulate strings */ +class StringTools +{ +public: + //! Will replace every occurence of `find` in `str` by `subst`. + static std::string Replace(const std::string& str, const char find, const std::string& subst); + + //! Will replace every occurence of `find` in `str` by `subst`. + static std::string Replace(const std::string& str, const std::string& find, const std::string& subst); + + //! Will replace every occurence of `find` in `str` by `subst`. + static std::string Replace(const std::string& str, const char find, const char subst); + + //! Will replace every occurence of `find` in `str` by `subst`. + static std::string Replace(const std::string& str, const std::string& find, const char subst); + + //! Will make a string all-lowercase. + static std::string Lower(const std::string& str); + + //! Will make a string all-uppercase. + static std::string Upper(const std::string& str); + + //! Will split a string by a string seperator + static std::vector Split(const std::string& str, const std::string& seperator); + + //! Will pad a string to the left to length l + static std::string PadLeft(const std::string& str, const char pad, const std::size_t len); + + //! Will pad a string to the right to length l + static std::string PadRight(const std::string& str, const char pad, const std::size_t len); + +private: + // No instanciation! >:( + StringTools(); +}; + +#endif //STRINGTOOLS_STRINGTOOLS_H diff --git a/Tubio/main.cpp b/Tubio/main.cpp index c203008..cd1d7b7 100644 --- a/Tubio/main.cpp +++ b/Tubio/main.cpp @@ -1,7 +1,45 @@ #include "Framework.h" +#ifndef _WIN +#include +#include +#include +#include +#include + +void Deamonize() { + // Fork me, kernel-san :o + pid_t fork_res = fork(); + + // Error handling... + if (fork_res < 0) { + std::cerr << "Aww shit! Deamonizing failed! Couldn't get forked..." << std::endl; + exit(-1); + } + + // Close launcher process... + if (fork_res > 0) { + std::cout << "Successfully spawned tubio daemon... Exiting launcher gracefully..." << std::endl; + exit(0); + } + + // And set the daemon process free + if (setsid() < 0) { + std::cerr << "Aww shit! Deamonizing failed! Couldn't create new session..." << std::endl; + exit(-1); + } + +} + +#endif + + int main() { + #ifndef _WIN +// Deamonize(); + #endif + Framework framework; framework.Run();