Note: This process is intended to run on a fully up-to-date Debian Stretch, that follows installation best practices
You can download naxsi from the releases page here Get the latest release source code and the corresponding signature file :
usr@008885ac189c:~$ export NAXSI_VER=1.3
usr@008885ac189c:~$ wget https://github.com/wargio/naxsi/releases/download/$NAXSI_VER/naxsi-$NAXSI_VER-src-with-deps.tar.gz -O naxsi-$NAXSI_VER-src-with-deps.tar.gz
Next, you need to get the source code for the nginx version you are running (in this example, we are using the nginx from the debian stretch repository) :
usr@008885ac189c:~$ export NGINX_VER=X.YY.Z
usr@008885ac189c:~$ wget https://nginx.org/download/nginx-$NGINX_VER.tar.gz
usr@008885ac189c:~$ wget https://nginx.org/download/nginx-$NGINX_VER.tar.gz.asc
usr@008885ac189c:~$ gpg --recv-key 520A9993A1C052F8
usr@008885ac189c:~$ gpg --verify nginx-$NGINX_VER.tar.gz.asc
usr@008885ac189c:~$ rm nginx-$NGINX_VER.tar.gz.asc
If the signature fails, check that both files have been correctly downloaded and are not corrupted.
First, extract the source code :
usr@008885ac189c:~$ mkdir -p naxsi-$NAXSI_VER
usr@008885ac189c:~$ tar -C naxsi-$NAXSI_VER -xzf naxsi-$NAXSI_VER-src-with-deps.tar.gz
usr@008885ac189c:~$ tar vxf nginx-$NGINX_VER.tar.gz
usr@008885ac189c:~$ cd nginx-$NGINX_VER
usr@008885ac189c:~/nginx-X.YY.Z$ ./configure --add-dynamic-module=../naxsi-$NAXSI_VER/naxsi_src/
usr@008885ac189c:~/nginx-X.YY.Z$ make modules
The resulting ngx_http_naxsi_module.so
will be located in the objs
directory.
Copy it to your nginx server, in /etc/nginx/modules/
.
Also copy naxsi_core.rules
to /etc/nginx/
.
You need to build the module with the same flags as your NGINX server package was compiled for example via apt-get source nginx
Execute this to list them:
usr@008885ac189c:~$ nginx -V
Then pass them to ./configure
.
usr@008885ac189c:~/nginx-X.YY.Z$ ./configure <FLAGS FROM ABOVE COMMAND> --add-dynamic-module=../naxsi-$NAXSI_VER/naxsi_src/
usr@008885ac189c:~/nginx-X.YY.Z$ make modules
This will ensure module will be compatible with your nginx and will load properly.
You need to tell nginx to load the naxsi module and naxsi core rules (if you don’t load them, naxsi will block every requests) :
usr@008885ac189c:~$ cat /etc/nginx/nginx.conf
...
load_module /etc/nginx/modules/ngx_http_naxsi_module.so; # load naxsi
http {
include /etc/nginx/naxsi_core.rules; # load naxsi core rules
...
}
...
Naxsi works on a per-location basis, meaning you can only enable it inside a location :
server {
...
location / { # naxsi is enabled, and in learning mode
SecRulesEnabled; #enable naxsi
LearningMode; #enable learning mode
LibInjectionSql; #enable libinjection support for SQLI
LibInjectionXss; #enable libinjection support for XSS
DeniedUrl "/RequestDenied"; #the location where naxsi will redirect the request when it is blocked
CheckRule "$SQL >= 8" BLOCK; #the action to take when the $SQL score is superior or equal to 8
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 5" BLOCK;
CheckRule "$UPLOAD >= 5" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
proxy_pass http://127.0.0.1;
....
}
location /admin { # naxsi is disabled
SecRulesDisabled; #optional, naxsi is disabled by default
allow 1.2.3.4;
deny all;
proxy_pass http://127.0.0.1;
....
}
location /vuln_page.php { # naxsi is enabled, and is *not* in learning mode
SecRulesEnabled;
proxy_pass http://127.0.0.1;
}
location /RequestDenied {
internal;
return 403;
}
...
}
As naxsi uses a whitelist approach, a lot of false positives may be generated, potentially dropping legitimate requests.
To prevent this, whitelists must be written (either manually or with nx-tool).
For example, if you have an e-commerce website that sells furniture, people will be likely to search for something like table
. Unfortunately, table
is also a SQL keyword, which will trigger naxsi.
To prevent this, you can write a whitelist telling naxsi to allow the table
keyword in the search form (assuming the search form in on /search
) :
server {
location / {
SecRulesEnabled; #enable naxsi
LearningMode; #enable learning mode
LibInjectionSql; #enable libinjection support for SQLI
LibInjectionXss; #enable libinjection support for XSS
DeniedUrl "/RequestDenied"; #the location where naxsi will redirect the request when it is blocked
CheckRule "$SQL >= 8" BLOCK; #the action to take when the $SQL score is superior or equal to 8
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 5" BLOCK;
CheckRule "$UPLOAD >= 5" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
BasicRule wl:1000 "mz:$URL:/search|$ARGS_VAR:q";
proxy_pass http://127.0.0.1;
....
}
}
See here and here for more informations about whitelists.
You can also create blacklist with naxsi, allowing you to drop requests even when in learning mode.
Let’s imagine a PHP script (/vuln_page.php
) vulnerable to an unquoted SQLI in the id
parameter, a typical exploitation would look like this :
GET /vuln_page.php?id=1'+or+1=1/*
You can use naxsi to virtually patch this vulnerabilty by adding a blacklist denying every requests on /vuln_page.php
where the id
parameter contains anything other than a number (in this example, the blacklist will only apply to the /
location, you can use MainRule
and put it outside in the http
block to make it global):
server {
location / {
SecRulesEnabled; #enable naxsi
LearningMode; #enable learning mode
LibInjectionSql; #enable libinjection support for SQLI
LibInjectionXss; #enable libinjection support for XSS
DeniedUrl "/RequestDenied"; #the location where naxsi will redirect the request when it is blocked
CheckRule "$SQL >= 8" BLOCK; #the action to take when the $SQL score is superior or equal to 8
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 5" BLOCK;
CheckRule "$UPLOAD >= 5" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
BasicRule id:4242 "mz:$URL:/vuln_page.php|$ARGS_VAR:id" "rx:[^\d]+" "s:DROP" "msg:blacklist for SQLI in /vuln_page.php";
proxy_pass http://127.0.0.1;
....
}
}