mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 13:56:01 +03:00
In ModSecurityIIS the configuration is loaded upon the first request is received. In other words, SecStatusEngine value can be only loaded once the first request hit the server, and so, the status function was moved to proceed just after the configuration got loaded. This update is IIS only.
434 lines
12 KiB
C
434 lines
12 KiB
C
/*
|
||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||
*
|
||
* You may not use this file except in compliance with
|
||
* the License. You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* If any of the files related to licensing are missing or if you have any
|
||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||
* directly using the email address security@modsecurity.org.
|
||
*/
|
||
|
||
#include "msc_status_engine.h"
|
||
#include "apr_sha1.h"
|
||
|
||
#ifdef WIN32
|
||
#include <winsock2.h>
|
||
#include <iphlpapi.h>
|
||
#endif
|
||
|
||
#ifdef DARWIN
|
||
#include <arpa/inet.h>
|
||
#include <ifaddrs.h>
|
||
#include <net/if.h>
|
||
#include <net/if_dl.h>
|
||
#include <netinet/in.h>
|
||
#include <sys/utsname.h>
|
||
#include <sys/types.h>
|
||
#include <sys/socket.h>
|
||
#if ! defined(IFT_ETHER)
|
||
#define IFT_ETHER 0x6/* Ethernet CSMACD */
|
||
#endif
|
||
#endif
|
||
|
||
#ifdef __gnu_linux__
|
||
#include <sys/utsname.h>
|
||
#include <linux/if.h>
|
||
#include <linux/sockios.h>
|
||
#endif
|
||
|
||
// Bese32 encode, based on:
|
||
// https://code.google.com/p/google-authenticator/source/browse/libpam/base32.c
|
||
void DSOLOCAL msc_status_engine_base32_encode(char *encoded,
|
||
const char *data, int len) {
|
||
int buffer;
|
||
int count = 0;
|
||
char *result = encoded;
|
||
int length = strlen(data);
|
||
|
||
buffer = data[0];
|
||
|
||
if (length > 0) {
|
||
int next = 1;
|
||
int bitsLeft = 8;
|
||
while (count < len && (bitsLeft > 0 || next < length)) {
|
||
int index;
|
||
if (bitsLeft < 5) {
|
||
if (next < length) {
|
||
buffer <<= 8;
|
||
buffer |= data[next++] & 0xff;
|
||
bitsLeft += 8;
|
||
} else {
|
||
int pad = 5 - bitsLeft;
|
||
buffer <<= pad;
|
||
bitsLeft += pad;
|
||
}
|
||
}
|
||
index = 0x1f & (buffer >> (bitsLeft - 5));
|
||
bitsLeft -= 5;
|
||
result[count++] = msc_status_engine_basis_32[index];
|
||
}
|
||
}
|
||
if (count < len) {
|
||
result[count] = '\000';
|
||
}
|
||
}
|
||
|
||
void DSOLOCAL msc_status_engine_fill_with_dots(char *encoded_with_dots,
|
||
const char *data, int len, int space)
|
||
{
|
||
int i;
|
||
int count = 0;
|
||
|
||
for (i = 0; i < strlen(data) && i < len; i++) {
|
||
if (i % space == 0 && i != 0) {
|
||
encoded_with_dots[count++] = '.';
|
||
}
|
||
encoded_with_dots[count++] = data[i];
|
||
}
|
||
encoded_with_dots[count] = '\0';
|
||
}
|
||
|
||
|
||
// Based on:
|
||
// http://stackoverflow.com/questions/16858782/how-to-obtain-almost-unique-system-identifier-in-a-cross-platform-way
|
||
int DSOLOCAL msc_status_engine_machine_name(char *machine_name, size_t len) {
|
||
#ifdef WIN32
|
||
DWORD lenComputerName = len;
|
||
#endif
|
||
|
||
memset(machine_name, '\0', sizeof(char) * len);
|
||
|
||
#ifdef WIN32
|
||
GetComputerName(machine_name, &lenComputerName);
|
||
#else
|
||
static struct utsname u;
|
||
|
||
if ( uname( &u ) < 0 ) {
|
||
goto failed;
|
||
}
|
||
|
||
apr_snprintf(machine_name, len-1, "%s", u.nodename);
|
||
#endif
|
||
|
||
return 0;
|
||
|
||
failed:
|
||
return -1;
|
||
}
|
||
|
||
int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac)
|
||
{
|
||
#ifdef DARWIN
|
||
struct ifaddrs* ifaphead;
|
||
struct ifaddrs* ifap;
|
||
int i = 0;
|
||
|
||
if ( getifaddrs( &ifaphead ) != 0 ) {
|
||
goto failed;
|
||
}
|
||
|
||
// iterate over the net interfaces
|
||
for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next ) {
|
||
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;
|
||
if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER )
|
||
&& mac[0] && mac[1] && mac[2] && i < 6) {
|
||
for (i = 0; i<6; i++) {
|
||
sprintf(mac, "%s%s%02x", mac, (i == 0)?"":":",
|
||
(unsigned char)LLADDR(sdl)[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
freeifaddrs( ifaphead );
|
||
#endif
|
||
|
||
#if __gnu_linux__
|
||
struct ifconf conf;
|
||
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP );
|
||
struct ifreq* ifr;
|
||
if ( sock < 0 ) {
|
||
goto failed;
|
||
}
|
||
|
||
char ifconfbuf[ 128 * sizeof(struct ifreq) ];
|
||
memset( ifconfbuf, 0, sizeof( ifconfbuf ));
|
||
conf.ifc_buf = ifconfbuf;
|
||
conf.ifc_len = sizeof( ifconfbuf );
|
||
if ( ioctl( sock, SIOCGIFCONF, &conf )) {
|
||
close(sock);
|
||
goto failed;
|
||
}
|
||
|
||
for ( ifr = conf.ifc_req; ifr < conf.ifc_req + conf.ifc_len; ifr++ ) {
|
||
if ( ioctl( sock, SIOCGIFFLAGS, ifr )) {
|
||
continue; // failed to get flags, skip it
|
||
}
|
||
|
||
if ( ioctl( sock, SIOCGIFHWADDR, ifr ) == 0 ) {
|
||
int i = 0;
|
||
if (!ifr->ifr_addr.sa_data[0] && !ifr->ifr_addr.sa_data[1]
|
||
&& !ifr->ifr_addr.sa_data[2]) {
|
||
continue;
|
||
}
|
||
|
||
for (i = 0; i<6; i++) {
|
||
sprintf(mac, "%s%s%02x", mac, (i == 0)?"":":",
|
||
(unsigned char)ifr->ifr_addr.sa_data[i]);
|
||
}
|
||
}
|
||
}
|
||
close( sock );
|
||
#endif
|
||
|
||
#if WIN32
|
||
PIP_ADAPTER_INFO pAdapterInfo;
|
||
PIP_ADAPTER_INFO pAdapter = NULL;
|
||
DWORD dwRetVal = 0;
|
||
UINT i;
|
||
|
||
ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
|
||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof (IP_ADAPTER_INFO));
|
||
if (!pAdapterInfo) {
|
||
goto failed;
|
||
}
|
||
|
||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||
free(pAdapterInfo);
|
||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
|
||
if (!pAdapterInfo) {
|
||
goto failed;
|
||
}
|
||
}
|
||
|
||
dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||
if (dwRetVal != NO_ERROR) {
|
||
free(pAdapterInfo);
|
||
goto failed;
|
||
}
|
||
|
||
pAdapter = pAdapterInfo;
|
||
while (pAdapter && !mac[0] && !mac[1] && !mac[2])
|
||
{
|
||
if (pAdapter->AddressLength > 4)
|
||
{
|
||
for (i = 0; i < pAdapter->AddressLength && i < 6; i++)
|
||
{
|
||
sprintf(mac, "%s%s%02x", mac, (i == 0) ? "" : ":",
|
||
(unsigned char)pAdapter->Address[i]);
|
||
}
|
||
}
|
||
pAdapter = pAdapter->Next;
|
||
}
|
||
|
||
free(pAdapterInfo);
|
||
#endif
|
||
|
||
done:
|
||
return 0;
|
||
|
||
failed:
|
||
return -1;
|
||
}
|
||
|
||
int DSOLOCAL msc_status_engine_unique_id (unsigned char *digest)
|
||
{
|
||
unsigned char local_digest[APR_SHA1_DIGESTSIZE];
|
||
apr_sha1_ctx_t context;
|
||
char *input;
|
||
int i = 0;
|
||
unsigned char *mac_address = NULL;
|
||
char *machine_name = NULL;
|
||
int ret = 0;
|
||
|
||
mac_address = malloc(sizeof(char)*(6+5+1));
|
||
if (!mac_address) {
|
||
ret = -1;
|
||
goto failed_mac_address;
|
||
}
|
||
memset(mac_address, 0, sizeof(char)*(6+5+1));
|
||
|
||
if (msc_status_engine_mac_address(mac_address)) {
|
||
ret = -1;
|
||
goto failed_set_mac_address;
|
||
}
|
||
|
||
machine_name = malloc(sizeof(char)*201);
|
||
if (!machine_name) {
|
||
ret = -1;
|
||
goto failed_machine_name;
|
||
}
|
||
|
||
if (msc_status_engine_machine_name(machine_name, 200)) {
|
||
ret = -1;
|
||
goto failed_set_machine_name;
|
||
}
|
||
|
||
input = malloc(sizeof(char)*(strlen(machine_name) +
|
||
strlen(mac_address)+1));
|
||
if (!input) {
|
||
goto failed_input;
|
||
}
|
||
|
||
apr_snprintf(input, strlen(machine_name)+strlen(mac_address)+1,
|
||
"%s%s", machine_name, mac_address);
|
||
|
||
apr_sha1_init(&context);
|
||
apr_sha1_update(&context, input, strlen(input));
|
||
apr_sha1_final(local_digest, &context);
|
||
|
||
for (i = 0; i < APR_SHA1_DIGESTSIZE; i++) {
|
||
sprintf(digest, "%s%02x", digest, local_digest[i]);
|
||
}
|
||
|
||
free(input);
|
||
failed_input:
|
||
failed_set_machine_name:
|
||
free(machine_name);
|
||
failed_machine_name:
|
||
failed_set_mac_address:
|
||
free(mac_address);
|
||
failed_mac_address:
|
||
|
||
return ret;
|
||
}
|
||
|
||
int msc_status_engine_call (void) {
|
||
char *apr = NULL;
|
||
const char *apr_loaded = NULL;
|
||
char pcre[7];
|
||
const char *pcre_loaded = NULL;
|
||
char *lua = NULL;
|
||
char *lua_loaded = NULL;
|
||
char *libxml = NULL;
|
||
char *libxml_loaded = NULL;
|
||
char *modsec = NULL;
|
||
const char *apache = NULL;
|
||
char *id = NULL;
|
||
char *beacon_string = NULL;
|
||
int beacon_string_len = 0;
|
||
char *beacon_string_encoded = NULL;
|
||
char *beacon_string_ready = NULL;
|
||
char *beacon_string_encoded_splitted = NULL;
|
||
int ret = 0;
|
||
|
||
apr = APR_VERSION_STRING;
|
||
apr_loaded = apr_version_string();
|
||
|
||
pcre_loaded = pcre_version();
|
||
apr_snprintf(pcre, 7, "%2d.%2d ", PCRE_MAJOR, PCRE_MINOR);
|
||
#ifdef WITH_LUA
|
||
lua = LUA_VERSION;
|
||
#endif
|
||
lua_loaded = 0;
|
||
|
||
libxml = LIBXML_DOTTED_VERSION;
|
||
libxml_loaded = 0;
|
||
|
||
modsec = MODSEC_VERSION;
|
||
apache = apache_get_server_version();
|
||
|
||
id = malloc(sizeof(char)*((2*APR_SHA1_DIGESTSIZE)+1));
|
||
if (!id) {
|
||
ret = -1;
|
||
goto failed_id;
|
||
}
|
||
|
||
memset(id, '\0', sizeof(char)*((2*APR_SHA1_DIGESTSIZE)+1));
|
||
if (msc_status_engine_unique_id(id)) {
|
||
sprintf(id, "unique id failed");
|
||
}
|
||
|
||
beacon_string_len = (modsec ? strlen(modsec) : 6) + (apache ? strlen(apache) : 6) +
|
||
(apr ? strlen(apr) : 6) + (apr_loaded ? strlen(apr_loaded) : 6) +
|
||
(pcre ? strlen(pcre) : 6) + (pcre_loaded ? strlen(pcre_loaded) : 6) +
|
||
(lua ? strlen(lua) : 6) + (lua_loaded ? strlen(lua_loaded) : 6) +
|
||
(libxml ? strlen(libxml) : 6) + (libxml_loaded ? strlen(libxml_loaded) : 6) +
|
||
(id ? strlen(id) : 6);
|
||
|
||
#ifdef WIN32
|
||
beacon_string = malloc(sizeof(char)*(beacon_string_len+1+10+4));
|
||
if (!beacon_string) {
|
||
goto failed_beacon_string;
|
||
}
|
||
|
||
apr_snprintf(beacon_string, beacon_string_len+1+10+4,
|
||
"%s,IIS,%s/%s,%s/%s,%s/%s,%s/%s,%s",
|
||
modsec, apr, apr_loaded, pcre, pcre_loaded, lua, lua_loaded,
|
||
libxml, libxml_loaded, id);
|
||
#else
|
||
beacon_string = malloc(sizeof(char)*(beacon_string_len+1+10));
|
||
if (!beacon_string) {
|
||
goto failed_beacon_string;
|
||
}
|
||
|
||
apr_snprintf(beacon_string, beacon_string_len+1+10,
|
||
"%s,%s,%s/%s,%s/%s,%s/%s,%s/%s,%s",
|
||
modsec, apache, apr, apr_loaded, pcre, pcre_loaded, lua, lua_loaded,
|
||
libxml, libxml_loaded, id);
|
||
#endif
|
||
|
||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||
"ModSecurity: StatusEngine call: \"%s\"", beacon_string);
|
||
|
||
beacon_string_encoded = malloc(sizeof(char)*(strlen(beacon_string)*3));
|
||
if (!beacon_string_encoded) {
|
||
goto failed_beacon_string_encoded;
|
||
}
|
||
msc_status_engine_base32_encode(beacon_string_encoded, beacon_string,
|
||
strlen(beacon_string)*3);
|
||
|
||
beacon_string_encoded_splitted = malloc (sizeof(char) *
|
||
((strlen(beacon_string_encoded)/STATUS_ENGINE_DNS_IN_BETWEEN_DOTS) +
|
||
strlen(beacon_string_encoded) + 1 + 1));
|
||
if (!beacon_string_encoded_splitted) {
|
||
goto failed_beacon_string_encoded_splitted;
|
||
}
|
||
|
||
msc_status_engine_fill_with_dots(beacon_string_encoded_splitted,
|
||
beacon_string_encoded,
|
||
(strlen(beacon_string_encoded)/STATUS_ENGINE_DNS_IN_BETWEEN_DOTS) +
|
||
strlen(beacon_string_encoded) + 1 + 1,
|
||
STATUS_ENGINE_DNS_IN_BETWEEN_DOTS);
|
||
|
||
beacon_string_ready = malloc (sizeof(char) *
|
||
strlen(beacon_string_encoded_splitted) +
|
||
strlen(STATUS_ENGINE_DNS_SUFFIX) + 10 + 1);
|
||
|
||
if (!beacon_string_ready) {
|
||
goto failed_beacon_string_ready;
|
||
}
|
||
|
||
apr_snprintf(beacon_string_ready, strlen(beacon_string_encoded_splitted) +
|
||
strlen(STATUS_ENGINE_DNS_SUFFIX) + 12 + 1, "%s.%lu.%s",
|
||
beacon_string_encoded_splitted, time(NULL),
|
||
STATUS_ENGINE_DNS_SUFFIX);
|
||
|
||
if (gethostbyname(beacon_string_ready)) {
|
||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||
"ModSecurity: StatusEngine call successfully sent. For more " \
|
||
"information visit: http://%s/", STATUS_ENGINE_DNS_SUFFIX);
|
||
} else {
|
||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||
"ModSecurity: StatusEngine call failed. Query: %s",
|
||
beacon_string_ready);
|
||
}
|
||
|
||
free(beacon_string_ready);
|
||
failed_beacon_string_ready:
|
||
free(beacon_string_encoded_splitted);
|
||
failed_beacon_string_encoded_splitted:
|
||
free(beacon_string_encoded);
|
||
failed_beacon_string_encoded:
|
||
free(beacon_string);
|
||
failed_beacon_string:
|
||
free(id);
|
||
failed_id:
|
||
|
||
return ret;
|
||
}
|
||
|