Is it possible to use libmodsecurity as a library and process requests on my own? I was messing with the examples in the repo ModSecurity examples, but I cant figure out how to make it take my request. I tried with simple_example_using_c.c but with no success. Is anyone have idea if this is possible?
#include <stdio.h>
#include <stdlib.h>
#include <modsecurity/modsecurity.h>
#include <modsecurity/rules_set.h>
char rulez[] ="basic_rules.conf";
const char *request = "" \
"GET /?test=test HTTP/\n" \
"Host: localhost:9999\n" \
"Content-Length: 27\n" \
"Content-Type: application/x-www-form-urlencoded\n";
int main(){
ModSecurity *modsec;
RulesSet *setRulez;
Transaction *transakcyja;
const char *error;
modsec = msc_init();
printf(msc_who_am_i(modsec));
msc_set_connector_info(modsec, "ModSecurity simple API");
setRulez = msc_create_rules_set();
int rulz = msc_rules_add_file(setRulez, rulez, &error);
if(rulz == -1){
fprintf(stderr, "huston rulez problem \n");
fprintf(stderr, "%s\n", error);
return -1;
}
msc_rules_dump(setRulez);
transakcyja = msc_new_transaction(modsec, setRulez, NULL);
if(transakcyja == NULL){
fprintf(stderr, "Init bad");
return -1;
}
msc_process_connection(transakcyja, "127.0.0.1", 9998, "127.0.0.1", 9999);
msc_process_uri(transakcyja, "http://127.0.0.1:9999/?k=test&test=test", "GET", "1.1");
msc_process_request_body(transakcyja);
msc_process_response_headers(transakcyja, 200, "HTTP 1.3");
msc_process_response_body(transakcyja);
msc_process_logging(transakcyja);
msc_rules_cleanup(setRulez);
msc_cleanup(modsec);
return 0;
}
Edit: I know something more now but, anyone know how to pass request to transaction? I know there is addRequestHeader() but it takes one header at the time, I can't really figure it out.
I think you have to understand how ModSecurity works.
There are five phases of all transaction:
(And plus the phase 0: process the connection itself.)
In the examples you can see couple of functions for each phases.
This is a common HTTP request:
POST /set.php HTTP/1.1
Host: foobar.com
User-Agent: something
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
a=1&b=2
Now if you already create a transaction object, you have to add the data of phases to that.
First see the status line, and add the necessary parts - consider your application already has the information, like client IP (std::string cip
), port (int cport
), and server IP (std::string dip
), port (int dport
). You also have the URI (std::string uri
), method (std::string method
) and the version of protocoll (std::string vers
). You also need an object with type modsecurity::ModSecurityIntervention *it
.
// phase 0
trans->processConnection(cip.c_str(), cport, dip.c_str(), dport);
trans->processURI(uri.c_str(), method.c_str(), vers.c_str());
trans->intervention(it);
Now you have to check the it
variable, eg. it.status
. For more information, check the source.
Now consider you have a variable (a list) which contains the parsed headers. Now you have to add these headers one by one to the transaction:
for(your_iterator it=headerType.begin(); it != headerType.end(); ++it) {
const std::string key = it->first.as<std::string>(); // key
const std::string val = it->second.as<std::string>(); // val
trans->addRequestHeader(key, val);
}
Now you can process the headers and check the results. Note, that if you process a phase, the engine evaluates all rules, where the phase
values is relevant: 1, 2, 3, 4 or 5.
// phase 1
trans->processRequestHeaders();
trans->intervention(it);
In next steps, you have to add the request body and process it, then get the response headers and body (from the upstream), and repeat the steps above...
Hope now you can see how does it works.
I've made a utility, which runs the CRS test cases on libmodecurity3 while it uses CRS rules. The tool available here: ftwrunner.
Hope this helped.