diff --git a/.cifuzz-build/logs/build-my_fuzz_test.log b/.cifuzz-build/logs/build-my_fuzz_test.log new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/Vulnerability.yml b/.github/workflows/Vulnerability.yml new file mode 100644 index 0000000..de310cc --- /dev/null +++ b/.github/workflows/Vulnerability.yml @@ -0,0 +1,107 @@ +name: Vulnerability Assessment + + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + branches: [ main ] + +env: + # The fuzzing server gRPC UR + FUZZING_SERVER_ADDRESS: grpc.code-intelligence.com:443 + # The fuzzing server HTTP URL... + WEB_APP_ADDRESS: https://app.code-intelligence.com + + # Directoriess in which the repository will be cloned. + CHECKOUT_DIR: checkout-dir/ + CIFUZZ_DOWNLOAD_URL: "https://github.com/CodeIntelligenceTesting/cifuzz/releases/latest/download/cifuzz_installer_linux_amd64" + CIFUZZ_INSTALL_DIR: ./cifuzz + FUZZING_ARTIFACT: fuzzing-artifact.tar.gz + BUILD_TYPE: Release + +jobs: + fuzz-test: + runs-on: ubuntu-latest + + steps: + - id: Checkout-Repo + name: Checkout Repository + uses: actions/checkout@v2 + with: + repository: gladzeka/TcpServer + ref: TestChironda/TcpServer + path: ${{ env.CHECKOUT_DIR }} + + - id: SetupCmake + name: Setup Cmake + run: | + sudo apt-get install -y cmake + cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} + + - id: DownloadCmake + name: Download CMakeLists.txt + run: | + curl -sSL -o CMakeLists.txt https://github.com/gladzeka/TcpServer/raw/main/CMakeLists.txt + + - id: Destination + name: Create Destination Directory + run: mkdir -p /home/runner/work/TcpServer/build/ + + - id: install-cifuzz + name: Install cifuzz + run: | + curl --fail --silent --show-error --location -o cifuzz_installer "$CIFUZZ_DOWNLOAD_URL" + chmod u+x cifuzz_installer + ./cifuzz_installer --install-dir $CIFUZZ_INSTALL_DIR + + - id: Envs + name: Setup Environment + run: | + # Set up the necessary dependencies and environment for the fuzz test + # Install any required packages or tools + # Example commands: + sudo apt-get update + + - id: Build + name: Build Server + run: | + cmake --build ${{ github.workspace }}/build --config ${{ env.BUILD_TYPE }} + + - name: Build Client + run: | + # Build the client application + # Replace the command with the actual build command for your client application + # Example command: + # g++ client.cpp -o client + + - name: Start Server + run: | + # Start the server before running the fuzz test + # Replace the command with the actual command to start the server + # Example command: + ./server + + - name: Run Fuzz Test + run: | + # Run the fuzz test on the client application + # Replace the command with the actual fuzz test command for your client application + # Example command d + ./client + + - name: Save Fuzz Test Results + if: always() + run: | + # Save the fuzz test results to an artifact or a file for further analysis + # Replace the command with the necessary steps to save the results + # Example command: + cp fuzz_results.txt $GITHUB_WORKSPACE/fuzz_results.txt + + - name: Upload Fuzz Test Results + if: always() + uses: actions/upload-artifact@v2 + with: + name: Fuzz Test Results + path: ${{ env.CHECKOUT_DIR }}/results # Replace with the actual path to the fuzz test results diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..fd8ba10 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "cmake.configureOnOpen": true, + "files.associations": { + "*.yml": "cpp", + "chrono": "cpp", + "system_error": "cpp", + "xlocale": "cpp" + }, + "C_Cpp.errorSquiggles": "disabled" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..05054c5 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++ build active file", + "command": "/usr/bin/g++", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/CMakeLists - backup.txt b/CMakeLists - backup.txt new file mode 100644 index 0000000..6795e26 --- /dev/null +++ b/CMakeLists - backup.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.8.1) +project(tcp_client_server) + +find_package (Threads) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++11") + +add_library(${PROJECT_NAME} + src/tcp_client.cpp + src/tcp_server.cpp + src/client.cpp + src/pipe_ret_t.cpp + src/common.cpp) + +option(SERVER_EXAMPLE "Build SERVER" ON) + +if(SERVER_EXAMPLE) + + add_definitions( + -DSERVER_EXAMPLE + ) + + add_executable(tcp_server examples/server_example.cpp) + + target_link_libraries (tcp_server ${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) + +endif() + +option(CLIENT_EXAMPLE "Build CLIENT" ON) + +if(CLIENT_EXAMPLE) + + add_definitions( + -DCLIENT_EXAMPLE + ) + + add_executable(tcp_client examples/client_example.cpp) + + target_link_libraries (tcp_client ${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) + +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 6795e26..6a5bc31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.8.1) project(tcp_client_server) -find_package (Threads) +find_package(cifuzz) +enable_fuzz_testing() set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++11") @@ -38,5 +39,7 @@ if(CLIENT_EXAMPLE) add_executable(tcp_client examples/client_example.cpp) target_link_libraries (tcp_client ${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) + add_fuzz_test(my_fuzz_test test/my_fuzz_test.cpp) + target_link_libraries(my_fuzz_test PRIVATE server_example) endif() diff --git a/CMakeUserPresets.json b/CMakeUserPresets.json new file mode 100644 index 0000000..e507671 --- /dev/null +++ b/CMakeUserPresets.json @@ -0,0 +1,100 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + "configurePresets": [ + { + "name": "cifuzz (Coverage)", + "displayName": "cifuzz (Coverage)", + "binaryDir": "${sourceDir}/.cifuzz-build/replayer/gcov", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CIFUZZ_ENGINE": "replayer", + "CIFUZZ_SANITIZERS": "gcov", + "CIFUZZ_TESTING": { + "type": "BOOL", + "value": "ON" + }, + "CMAKE_BUILD_RPATH_USE_ORIGIN": { + "type": "BOOL", + "value": "ON" + } + } + }, + { + "name": "cifuzz (Fuzzing)", + "displayName": "cifuzz (Fuzzing)", + "binaryDir": "${sourceDir}/.cifuzz-build/libfuzzer/address+undefined", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CIFUZZ_ENGINE": "libfuzzer", + "CIFUZZ_SANITIZERS": "address;undefined", + "CIFUZZ_TESTING": { + "type": "BOOL", + "value": "ON" + }, + "CMAKE_BUILD_RPATH_USE_ORIGIN": { + "type": "BOOL", + "value": "ON" + } + }, + "environment": { + "CC": "clang", + "CXX": "clang++" + } + }, + { + "name": "cifuzz (Regression Test)", + "displayName": "cifuzz (Regression Test)", + "binaryDir": "${sourceDir}/.cifuzz-build/replayer/address+undefined", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CIFUZZ_ENGINE": "replayer", + "CIFUZZ_SANITIZERS": "address;undefined", + "CIFUZZ_TESTING": { + "type": "BOOL", + "value": "ON" + }, + "CMAKE_BUILD_RPATH_USE_ORIGIN": { + "type": "BOOL", + "value": "ON" + } + } + } + ], + "buildPresets": [ + { + "name": "cifuzz (Coverage)", + "displayName": "cifuzz (Coverage)", + "configurePreset": "cifuzz (Coverage)", + "configuration": "RelWithDebInfo" + }, + { + "name": "cifuzz (Fuzzing)", + "displayName": "cifuzz (Fuzzing)", + "configurePreset": "cifuzz (Fuzzing)", + "configuration": "RelWithDebInfo" + }, + { + "name": "cifuzz (Regression Test)", + "displayName": "cifuzz (Regression Test)", + "configurePreset": "cifuzz (Regression Test)", + "configuration": "RelWithDebInfo" + } + ], + "testPresets": [ + { + "name": "cifuzz (Regression Test)", + "displayName": "cifuzz (Regression Test)", + "configurePreset": "cifuzz (Regression Test)", + "filter": { + "include": { + "label": "^cifuzz_regression_test$" + } + } + } + ] +} diff --git a/build.sh b/build.sh old mode 100755 new mode 100644 diff --git a/cifuzz.yaml b/cifuzz.yaml new file mode 100644 index 0000000..4464473 --- /dev/null +++ b/cifuzz.yaml @@ -0,0 +1,46 @@ +## Configuration for a CI Fuzz project +## Generated on 2023-05-31 + +## The build system used to build this project. If not set, cifuzz tries +## to detect the build system automatically. +## Valid values: "bazel", "cmake", "maven", "gradle", "other". +#build-system: cmake + +## If the build system type is "other", this command is used by +## `cifuzz run` to build the fuzz test. +#build-command: "make my_fuzz_test" + +## Directories containing sample inputs for the code under test. +## See https://llvm.org/docs/LibFuzzer.html#corpus +#seed-corpus-dirs: +# - path/to/seed-corpus + +## A file containing input language keywords or other interesting byte +## sequences. +## See https://llvm.org/docs/LibFuzzer.html#dictionaries +#dict: path/to/dictionary.dct + +## Command-line arguments to pass to libFuzzer. +## See https://llvm.org/docs/LibFuzzer.html#options +#engine-args: +# - -rss_limit_mb=4096 + +## Maximum time to run fuzz tests. The default is to run indefinitely. +#timeout: 30m + +## By default, fuzz tests are executed in a sandbox to prevent accidental +## damage to the system. Set to false to run fuzz tests unsandboxed. +## Only supported on Linux. +#use-sandbox: false + +## Set to true to print output of the `cifuzz run` command as JSON. +#print-json: true + +## Set to true to disable desktop notifications +#no-notifications: true + +## Set URL of the CI App +#server: https://app.code-intelligence.com + +## Set the project name on the CI App +#project: my-project-1a2b3c4d diff --git a/examples/client_example.cpp b/examples/client_example.cpp index 64f4ea6..d6d48cb 100644 --- a/examples/client_example.cpp +++ b/examples/client_example.cpp @@ -2,7 +2,9 @@ /////////////////////CLIENT EXAMPLE//////////////////////// /////////////////////////////////////////////////////////// -#ifdef CLIENT_EXAMPLE +std::string message; +std::cin >> message; + #include #include diff --git a/examples/myfuzztest.cpp b/examples/myfuzztest.cpp new file mode 100644 index 0000000..13fc581 --- /dev/null +++ b/examples/myfuzztest.cpp @@ -0,0 +1,155 @@ +#ifdef SERVER_EXAMPLE + +#include +#include +#include +#include + +#include "../include/tcp_server.h" + +// declare the server +TcpServer server; + +// declare a server observer which will receive incomingPacketHandler messages. +// the server supports multiple observers +server_observer_t observer; + +bool shouldSaveMsg = false; +char msgBuffer[10] = {0}; + +std::mutex mtx; +std::condition_variable server_ready; +bool canAcceptNextClient = true; + +// observer callback. will be called for every new message received by clients +// with the requested IP address +void onIncomingMsg(const std::string &clientIP, const char *msg, size_t size) { + std::string msgStr = msg; + if (msgStr == "S") { + shouldSaveMsg = true; + } else if (shouldSaveMsg) { + if (strncmp(msgStr.c_str(), "M", 1) == 0) { + memcpy(msgBuffer, msg, size); + } + shouldSaveMsg = false; + } + // print client message + std::cout << "Observer1 got client msg: " << msgStr << "\n"; +} + +// observer callback. will be called when client disconnects +void onClientDisconnected(const std::string &ip, const std::string &msg) { + std::cout << "Client: " << ip << " disconnected. Reason: " << msg << "\n"; + { + std::lock_guard lock(mtx); + canAcceptNextClient = true; + server_ready.notify_one(); + } +} + +int main() { + // start server on port 65123 + pipe_ret_t startRet = server.start(65123); + if (startRet.isSuccessful()) { + std::cout << "Server setup succeeded\n"; + } else { + std::cout << "Server setup failed: " << startRet.message() << "\n"; + return EXIT_FAILURE; + } + + // configure and register observer + observer.incomingPacketHandler = onIncomingMsg; + observer.disconnectionHandler = onClientDisconnected; + observer.wantedIP = "127.0.0.1"; + server.subscribe(observer); + + while (true) { + acceptClient(); + { + std::lock_guard lock(mtx); + canAcceptNextClient = false; + } + std::unique_lock lock(mtx); + server_ready.wait(lock, [] { return canAcceptNextClient; }); + } + + return 0; +} + +#endif +/////////////////////////////////////////////////////////// +/////////////////////CLIENT EXAMPLE//////////////////////// +/////////////////////////////////////////////////////////// + +#ifdef CLIENT_EXAMPLE + +#include +#include +#include "../include/tcp_client.h" + +TcpClient client; + +// on sig_exit, close client +void sig_exit(int s) { + std::cout << "Closing client...\n"; + pipe_ret_t finishRet = client.close(); + if (finishRet.isSuccessful()) { + std::cout << "Client closed.\n"; + } else { + std::cout << "Failed to close client.\n"; + } + exit(0); +} + +// observer callback. will be called for every new message received by the server +void onIncomingMsg(const char *msg, size_t size) { + std::cout << "Got msg from server: " << msg << "\n"; +} + +// observer callback. will be called when server disconnects +void onDisconnection(const pipe_ret_t &ret) { + std::cout << "Server disconnected: " << ret.message() << "\n"; +} + +int main() { + // register to SIGINT to close client when user press ctrl+c + signal(SIGINT, sig_exit); + + // configure and register observer + client_observer_t observer; + observer.wantedIP = "127.0.0.1"; + observer.incomingPacketHandler = onIncomingMsg; + observer.disconnectionHandler = onDisconnection; + client.subscribe(observer); + + // connect client to an open server + bool connected = false; + while (!connected) { + pipe_ret_t connectRet = client.connectTo("127.0.0.1", 65123); + connected = connectRet.isSuccessful(); + if (connected) { + std::cout << "Client connected successfully\n"; + } else { + std::cout << "Client failed to connect: " << connectRet.message() << "\n" + << "Make sure the server is open and listening\n\n"; + sleep(2); + std::cout << "Retrying to connect...\n"; + } + } + + // send messages to server + while (true) { + // Fuzzed input for sending a message to the server + std::string message = /* fuzzed message */; + pipe_ret_t sendRet = client.sendMsg(message.c_str(), message.size()); + if (!sendRet.isSuccessful()) { + std::cout << "Failed to send message: " << sendRet.message() << "\n"; + } else { + std::cout << "Message was sent successfully\n"; + } + } + + return 0; +} + +#endif diff --git a/examples/server_example.cpp b/examples/server_example.cpp index 3d9f21d..b4781b7 100644 --- a/examples/server_example.cpp +++ b/examples/server_example.cpp @@ -42,9 +42,8 @@ void acceptClient() { } -// observer callback. will be called for every new message received by clients -// with the requested IP address -void onIncomingMsg(const std::string &clientIP, const char * msg, size_t size) { + + void onIncomingMsg(const std::string &clientIP, const char * msg, size_t size) { std::string msgStr = msg; if (msgStr == "S") { shouldSaveMsg = true; @@ -54,8 +53,17 @@ void onIncomingMsg(const std::string &clientIP, const char * msg, size_t size) { } shouldSaveMsg = false; } - // print client message + // Print client message std::cout << "Observer1 got client msg: " << msgStr << "\n"; + + // Check for the X-Injected-Header value + std::string injectedHeaderValue = "MaliciousContentChironda"; + if (msgStr == injectedHeaderValue) { + std::cout << "Zacarias has injected a file heree: " << msgStr << "\n"; + // Example: server.handleInjectedHeader(injectedHeaderValue); + } + + } // observer callback. will be called when client disconnects diff --git a/test/my_fuzz_test.cpp b/test/my_fuzz_test.cpp new file mode 100644 index 0000000..13fc581 --- /dev/null +++ b/test/my_fuzz_test.cpp @@ -0,0 +1,155 @@ +#ifdef SERVER_EXAMPLE + +#include +#include +#include +#include + +#include "../include/tcp_server.h" + +// declare the server +TcpServer server; + +// declare a server observer which will receive incomingPacketHandler messages. +// the server supports multiple observers +server_observer_t observer; + +bool shouldSaveMsg = false; +char msgBuffer[10] = {0}; + +std::mutex mtx; +std::condition_variable server_ready; +bool canAcceptNextClient = true; + +// observer callback. will be called for every new message received by clients +// with the requested IP address +void onIncomingMsg(const std::string &clientIP, const char *msg, size_t size) { + std::string msgStr = msg; + if (msgStr == "S") { + shouldSaveMsg = true; + } else if (shouldSaveMsg) { + if (strncmp(msgStr.c_str(), "M", 1) == 0) { + memcpy(msgBuffer, msg, size); + } + shouldSaveMsg = false; + } + // print client message + std::cout << "Observer1 got client msg: " << msgStr << "\n"; +} + +// observer callback. will be called when client disconnects +void onClientDisconnected(const std::string &ip, const std::string &msg) { + std::cout << "Client: " << ip << " disconnected. Reason: " << msg << "\n"; + { + std::lock_guard lock(mtx); + canAcceptNextClient = true; + server_ready.notify_one(); + } +} + +int main() { + // start server on port 65123 + pipe_ret_t startRet = server.start(65123); + if (startRet.isSuccessful()) { + std::cout << "Server setup succeeded\n"; + } else { + std::cout << "Server setup failed: " << startRet.message() << "\n"; + return EXIT_FAILURE; + } + + // configure and register observer + observer.incomingPacketHandler = onIncomingMsg; + observer.disconnectionHandler = onClientDisconnected; + observer.wantedIP = "127.0.0.1"; + server.subscribe(observer); + + while (true) { + acceptClient(); + { + std::lock_guard lock(mtx); + canAcceptNextClient = false; + } + std::unique_lock lock(mtx); + server_ready.wait(lock, [] { return canAcceptNextClient; }); + } + + return 0; +} + +#endif +/////////////////////////////////////////////////////////// +/////////////////////CLIENT EXAMPLE//////////////////////// +/////////////////////////////////////////////////////////// + +#ifdef CLIENT_EXAMPLE + +#include +#include +#include "../include/tcp_client.h" + +TcpClient client; + +// on sig_exit, close client +void sig_exit(int s) { + std::cout << "Closing client...\n"; + pipe_ret_t finishRet = client.close(); + if (finishRet.isSuccessful()) { + std::cout << "Client closed.\n"; + } else { + std::cout << "Failed to close client.\n"; + } + exit(0); +} + +// observer callback. will be called for every new message received by the server +void onIncomingMsg(const char *msg, size_t size) { + std::cout << "Got msg from server: " << msg << "\n"; +} + +// observer callback. will be called when server disconnects +void onDisconnection(const pipe_ret_t &ret) { + std::cout << "Server disconnected: " << ret.message() << "\n"; +} + +int main() { + // register to SIGINT to close client when user press ctrl+c + signal(SIGINT, sig_exit); + + // configure and register observer + client_observer_t observer; + observer.wantedIP = "127.0.0.1"; + observer.incomingPacketHandler = onIncomingMsg; + observer.disconnectionHandler = onDisconnection; + client.subscribe(observer); + + // connect client to an open server + bool connected = false; + while (!connected) { + pipe_ret_t connectRet = client.connectTo("127.0.0.1", 65123); + connected = connectRet.isSuccessful(); + if (connected) { + std::cout << "Client connected successfully\n"; + } else { + std::cout << "Client failed to connect: " << connectRet.message() << "\n" + << "Make sure the server is open and listening\n\n"; + sleep(2); + std::cout << "Retrying to connect...\n"; + } + } + + // send messages to server + while (true) { + // Fuzzed input for sending a message to the server + std::string message = /* fuzzed message */; + pipe_ret_t sendRet = client.sendMsg(message.c_str(), message.size()); + if (!sendRet.isSuccessful()) { + std::cout << "Failed to send message: " << sendRet.message() << "\n"; + } else { + std::cout << "Message was sent successfully\n"; + } + } + + return 0; +} + +#endif