diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 89170761..f616b48b 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -2,11 +2,7 @@ name: CI/CD for IIS Module on: push: - branches: - - v2/test-ci-windows pull_request: - branches: - - v2/test-ci-windows jobs: build: @@ -39,48 +35,42 @@ jobs: shell: pwsh run: | echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - # Original Make file contain comment build script for ssdeep, - # which is rely on MSYS2, so we need to install MSYS2. - # If it's enabled, it need msys2 library for ssdeep. - # - name: Setup MSYS2 - # uses: msys2/setup-msys2@v2 - # with: - # msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} - # update: true - # install: > - # git - # make - # autoconf - # automake - # libtool - # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} - # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} + update: true + install: > + git + make + autoconf + automake + libtool + ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} + ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} - # - name: Clone and build ssdeep - # shell: msys2 {0} - # run: | - # MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') - # echo "Converted workspace path: $MSYS2_WORKSPACE" + - name: Clone and build ssdeep + shell: msys2 {0} + run: | + MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') - # git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 - # cd ssdeep - # autoreconf -i + git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 + cd ssdeep + autoreconf -i - # if [ "${{ matrix.arch }}" = "x86" ]; then - # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 - # else - # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" - # fi + if [ "${{ matrix.arch }}" = "x86" ]; then + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 + else + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" + fi - # make dll + make dll - # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin" - # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include" - # cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin/" - # cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include/" - # cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/" + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/" + cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/" + cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/" + cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/" - name: Restore vcpkg cache id: vcpkg-cache @@ -105,14 +95,13 @@ jobs: -DAPACHE_ROOT="$env:APACHE_ROOT" ` -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` + -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` + -DWITH_SSDEEP=ON ` -A $cmakeArch ` -DWITH_LUA=ON ` -DWITH_YAJL=ON ` -S IIS -B "iis\build" - # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` - # -DWITH_SSDEEP=ON ` - - name: Build IIS Module shell: pwsh run: | @@ -316,6 +305,9 @@ jobs: run: | go install github.com/coreruleset/go-ftw@latest + # Certain rules are disabled due to specific IIS behavior patterns. + # Using go-ftw in cloud mode as the IIS connector does not generate logs in file format. + # Technically, Event logs can be streamed to files, but this requires implementing rate limits to avoid log overflow. - name: Test ModSecurity Rules shell: pwsh run: | diff --git a/iis/.gitignore b/iis/.gitignore new file mode 100644 index 00000000..d1638636 --- /dev/null +++ b/iis/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index c65dd14d..fe5e1d0f 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -7,10 +7,8 @@ find_package(PCRE2 CONFIG REQUIRED) find_package(CURL CONFIG REQUIRED) find_package(APR CONFIG REQUIRED) -# iis/CMakeLists.txt -set(IIS_MODULE_NAME "modsecurityiis") # Name should match the original output +set(IIS_MODULE_NAME "modsecurityiis") -# Source files for IIS module (reusing Apache sources) set(IIS_APACHE_SOURCES ../apache2/mod_security2.c ../apache2/apache2_config.c @@ -46,7 +44,6 @@ set(IIS_APACHE_SOURCES ../apache2/libinjection/libinjection_xss.c ) -# Source files for standalone components (if they exist in the project) set(IIS_STANDALONE_SOURCES ../standalone/api.c ../standalone/buckets.c @@ -57,18 +54,12 @@ set(IIS_STANDALONE_SOURCES ../standalone/server.c ) -# Determine architecture if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(ARCHITECTURE "x64") else() set(ARCHITECTURE "x86") endif() -# Check if standalone directory exists, if not, exclude those sources -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../standalone) - set(IIS_STANDALONE_SOURCES "") -endif() - set(IIS_RESOURCE_MC "${CMAKE_CURRENT_SOURCE_DIR}/ModSecurityIISMessage.mc") set(MC_GENERATED_RC "${CMAKE_CURRENT_BINARY_DIR}/ModSecurityIISMessage.rc") @@ -110,27 +101,19 @@ set_target_properties(${IIS_MODULE_NAME} PROPERTIES SUFFIX ".dll" ) -# Include directories target_include_directories(${IIS_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../apache2 ${CMAKE_CURRENT_SOURCE_DIR}/../apache2/libinjection ${LIBXML2_INCLUDE_DIR}/libxml + ${CMAKE_CURRENT_SOURCE_DIR}/../standalone ${PCRE2_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${APR_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ) -# Include standalone directory if it exists -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../standalone) - target_include_directories(${IIS_MODULE_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../standalone - ) -endif() - -# Apache-specific includes if(APACHE_ROOT) if(NOT EXISTS "${APACHE_ROOT}") message(FATAL_ERROR "APACHE_ROOT is defined but the directory '${APACHE_ROOT}' does not exist. Please set APACHE_ROOT to a valid Apache installation directory.") @@ -172,7 +155,6 @@ if(APACHE_ROOT) ) endif() -# Compile definitions to match the original Makefile.win set(MODSECURITY_VERSION_FLAG "VERSION_IIS") # Define the version flag string target_compile_definitions(${IIS_MODULE_NAME} PRIVATE inline=APR_INLINE @@ -181,11 +163,10 @@ target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_REMOTE_RULES MSC_LARGE_STREAM_INPUT WITH_YAJL - ${MODSECURITY_VERSION_FLAG} # Use the defined version flag + ${MODSECURITY_VERSION_FLAG} ) option(WITH_LUA "Enable Lua support" OFF) -# Optional compile definitions if(WITH_LUA) find_package(Lua CONFIG REQUIRED) target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_LUA) @@ -211,30 +192,26 @@ if(WITH_YAJL) target_include_directories(${IIS_MODULE_NAME} PRIVATE ${YAJL_INCLUDE_DIRS}) else() message(WARNING "YAJL not found. YAJL_INCLUDE_DIR: '${YAJL_INCLUDE_DIR}', YAJL_LIBRARY: '${YAJL_LIBRARY}'. Please ensure yajl is installed via vcpkg in the vcpkg_installed directory. Disabling YAJL support.") - option(WITH_YAJL "Enable YAJL support" OFF) # Disable if not found + option(WITH_YAJL "Enable YAJL support" OFF) endif() endif() option(WITH_SSDEEP "Enable SSDEEP support" OFF) if(WITH_SSDEEP) - set(SSDEEP_ROOT "" CACHE PATH "Path to manually built ssdeep") - if(NOT SSDEEP_ROOT OR NOT EXISTS "${SSDEEP_ROOT}") + if(NOT EXISTS "${SSDEEP_ROOT}") message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Current SSDEEP_ROOT: '${SSDEEP_ROOT}'. Please set SSDEEP_ROOT to the ssdeep installation directory. Disabling SSDEEP support.") set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) else() file(TO_CMAKE_PATH "${SSDEEP_ROOT}" SSDEEP_ROOT) - message(STATUS "SSDEEP_ROOT: ${SSDEEP_ROOT}") - find_path(SSDEEP_INCLUDE_DIR fuzzy.h - PATHS "${SSDEEP_ROOT}/include" + PATHS "${SSDEEP_ROOT}" NO_DEFAULT_PATH ) if(SSDEEP_INCLUDE_DIR) - message(STATUS "Found manually built ssdeep include: ${SSDEEP_INCLUDE_DIR}") target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_SSDEEP) target_include_directories(${IIS_MODULE_NAME} PRIVATE ${SSDEEP_INCLUDE_DIR}) @@ -244,7 +221,7 @@ if(WITH_SSDEEP) set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) else() set(SSDEEP_GENERATED_LIB "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.lib") - set(SSDEEP_GENERATED_dll "${CMAKE_CURRENT_BINARY_DIR}/bin/fuzzy.dll") + set(SSDEEP_GENERATED_dll "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.dll") add_custom_command( OUTPUT ${SSDEEP_GENERATED_LIB} @@ -271,43 +248,30 @@ if(WITH_SSDEEP) ) endif() + else() + message(WARNING "fuzzy.h not found at ${SSDEEP_INCLUDE_DIR}. Disabling SSDEEP support.") + set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) endif() endif() endif() -# Compiler-specific options for MSVC to match the original Makefile.win if(MSVC) target_compile_options(${IIS_MODULE_NAME} PRIVATE /nologo /W3 /wd4244 /wd4018 - ) endif() -# Link libraries to match the original Makefile.win target_link_libraries(${IIS_MODULE_NAME} PRIVATE LibXml2::LibXml2 PCRE2::8BIT CURL::libcurl - kernel32 - user32 - gdi32 - winspool - comdlg32 - advapi32 - shell32 - ole32 - oleaut32 - uuid - odbc32 - odbccp32 ws2_32 iphlpapi ) -# Apache-specific libraries if(APACHE_ROOT) target_link_libraries(${IIS_MODULE_NAME} PRIVATE Apache::httpd @@ -319,7 +283,6 @@ else() message(WARNING "APACHE_ROOT is not defined or path does not exist. Current APACHE_ROOT: '${APACHE_ROOT}'. Please set APACHE_ROOT to the Apache installation directory.") endif() -# Optional link libraries if(WITH_LUA) target_link_libraries(${IIS_MODULE_NAME} PRIVATE ${LUA_LIBRARIES}) endif() @@ -349,10 +312,10 @@ else() message(WARNING "APACHE_ROOT is not defined or path does not exist. Current APACHE_ROOT: '${APACHE_ROOT}'. Please set APACHE_ROOT to the Apache installation directory.") endif() -if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/bin/fuzzy.dll") +if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/fuzzy.dll") add_custom_command(TARGET ${IIS_MODULE_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${SSDEEP_ROOT}/bin/fuzzy.dll" + "${SSDEEP_ROOT}/fuzzy.dll" $ COMMENT "Copying SSDEEP DLL to output directory" ) @@ -374,9 +337,9 @@ if(APACHE_ROOT AND EXISTS "${APACHE_ROOT}/bin") ) endif() -if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/bin/fuzzy.dll") +if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/fuzzy.dll") install(FILES - "${SSDEEP_ROOT}/bin/fuzzy.dll" + "${SSDEEP_ROOT}/fuzzy.dll" DESTINATION . ) endif() diff --git a/iis/installer.wxs b/iis/installer.wxs index 240db63e..3f174433 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> - + diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index e9d5ce37..dfaee4b2 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -17,6 +17,8 @@ #undef inline #define inline inline +#include "winsock2.h" + // IIS7 Server API header file #include #include @@ -30,8 +32,6 @@ #include "api.h" #include "moduleconfig.h" -#include "winsock2.h" - class REQUEST_STORED_CONTEXT : public IHttpStoredContext { @@ -90,63 +90,66 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - const char *format = "%15[0-9.]:%5[0-9]"; - char ip[16] = { 0 }; // ip4 addresses have max len 15 - char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max - - DWORD len = 50; - char *buf = (char *)apr_palloc(pool, len); - - if(buf == NULL) - return ""; - - buf[0] = 0; - - WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len); - - // test for IPV4 with port on the end - if (sscanf(buf, format, ip, port) == 2) { - // IPV4 but with port - remove the port - char* input = ":"; - char* ipv4 = strtok(buf, input); - return ipv4; - } - - return buf; + if (pAddr == nullptr) { + return apr_pstrdup(pool, ""); + } + + DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); + auto buf = (char*)apr_palloc(pool, NI_MAXHOST); + if (buf == nullptr) { + return apr_pstrdup(pool, ""); + } + buf[0] = '\0'; + + if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST) != 0) { + return apr_pstrdup(pool, ""); + } + + return buf; } apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - int adrlen = 16, iplen = 4; + apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - if(pAddr->sa_family == AF_INET6) - { - adrlen = 46; - iplen = 16; + addr->pool = pool; + addr->hostname = "unknown"; + addr->servname = addr->hostname; + addr->family = AF_UNSPEC; + addr->addr_str_len = 0; + addr->ipaddr_len = 0; + addr->ipaddr_ptr = nullptr; + addr->salen = 0; + addr->port = 0; + + if (pAddr == nullptr) { + return addr; } - addr->addr_str_len = adrlen; addr->family = pAddr->sa_family; - addr->hostname = "unknown"; -#ifdef WIN32 - addr->ipaddr_len = sizeof(IN_ADDR); -#else - addr->ipaddr_len = sizeof(struct in_addr); -#endif - addr->ipaddr_ptr = &addr->sa.sin.sin_addr; - addr->pool = pool; - addr->port = 80; -#ifdef WIN32 - memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen); -#else - memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen); -#endif - addr->sa.sin.sin_family = pAddr->sa_family; - addr->sa.sin.sin_port = 80; - addr->salen = sizeof(addr->sa); - addr->servname = addr->hostname; + if (pAddr->sa_family == AF_INET) { + auto sin = (SOCKADDR_IN *)pAddr; + addr->addr_str_len = INET_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in_addr); + addr->ipaddr_ptr = &addr->sa.sin.sin_addr; + addr->sa.sin.sin_family = AF_INET; + addr->sa.sin.sin_port = sin->sin_port; /* keep network byte order */ + /* copy address */ + memcpy(&addr->sa.sin.sin_addr, &sin->sin_addr, sizeof(struct in_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin->sin_port); + } else if (pAddr->sa_family == AF_INET6) { + auto sin6 = (SOCKADDR_IN6 *)pAddr; + addr->addr_str_len = INET6_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in6_addr); + addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr; + addr->sa.sin6.sin6_family = AF_INET6; + addr->sa.sin6.sin6_port = sin6->sin6_port; + memcpy(&addr->sa.sin6.sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin6->sin6_port); + } return addr; }