nbs-system / naxsi

NAXSI is an open-source, high performance, low rules maintenance WAF for NGINX
GNU General Public License v3.0
4.79k stars 606 forks source link

Naxsi rule to block XXE #542

Closed cyndy08 closed 3 years ago

cyndy08 commented 3 years ago

Hello everybody,

i am currently writing my bachelor thesis on web application Firewalls. For this i have to test a few open source WAFs and then compare them. I chose Modsecurity and Naxsi for my work. I am currently trying to write a rule to block XXE (XML External Entities). For example if i upload the following code it should be blocked by the waf and not executed:

` <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]>

&xxe; ` i also add a checkrule: CheckRule "$XXE >= 4" BLOCK; I tried with this rule but it not working: MainRule "rx:Entity|System" "msg:XML Entity detected" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XXE:4" id:1700. It seems like the uploaded file is not beeing expected by naxsi. I write a rule to block the upload of xml.files and it works. But if i upload the xml file using curl -d , it doesnt work anymore and the XXE attack successes. Any suggestion will be really appreciated.# Thank you
wargio commented 3 years ago

remove the |$HEADERS_VAR:Cookie i would also split the rule in 2 sets

MainRule "str:Entity" "msg:XML Entity detected" "mz:ARGS|URL|BODY" "s:$XXE:4" id:1700;
MainRule "str:System" "msg:XML System detected" "mz:ARGS|URL|BODY" "s:$XXE:4" id:1701;
cyndy08 commented 3 years ago

Thank you for your suggestion. It still doesnt work with these rules. It seems like Naxsi is not able to read the content of the file that is uploaded.

wargio commented 3 years ago

oh, i know why. you need to use RAW_BODY.

MainRule "str:Entity" "msg:XML Entity detected" "mz:RAW_BODY" "s:$XXE:4" id:1700;
MainRule "str:System" "msg:XML System detected" "mz:RAW_BODY" "s:$XXE:4" id:1701;
cyndy08 commented 3 years ago

It still doesn't work. The XXE attack succeed. Is it anyway to see debug informations?

wargio commented 3 years ago

can you show me what the content of the request looks like (a raw request can be useful)? so i know what you are doing. and also logs from nginx

cyndy08 commented 3 years ago

I have a php file on a webserver with following content:

<?php 
    libxml_disable_entity_loader (false);
    $xmlfile = file_get_contents('php://input');
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    $creds = simplexml_import_dom($dom);
    $userid = $creds->userid;
    echo "You have logged in as user $userid";
?> 

Then i upload this xml file as argument to run the php code:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<creds>
    <userid>&xxe;</userid>
</creds>

To send the request i use: curl -d @attack.xml http://ip/DVWA/hackable/uploads/xxe.php I expected the waf to block this POST-request, like ModSecurity did. Since the request is not blocked there is no Logs from nginx in the error-log file. In the acces.log file i have: ip - - [04/Jan/2021:10:48:17 -0800] "POST /DVWA/hackable/uploads/xxe.php HTTP/1.1" 200 2746 "-" "curl/7.72.0"

I hope you can understand what i did.

Thank you

wargio commented 3 years ago

whats your configuration?

cyndy08 commented 3 years ago

Which configuration? You mean my nginx.conf file? This is my nginx.conf file:


user  www-data;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    include       /etc/nginx/naxsi_core.rules;
    include       /etc/nginx/conf.d/*.conf;
    include       /etc/nginx/sites-enabled/*;
    access_log    /var/log/nginx/acces.log;
    error_log     /var/log/nginx/error.log;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  127.0.0.1;
        root        /var/www/html/nginx;
        index  index.html index.htm index.nginx-debian.html index.php;

        location / {

           include     /etc/nginx/naxsi.rules;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        location ~ \.php$ {

            fastcgi_pass   unix:/run/php/php7.4-fpm.sock;
            fastcgi_index  index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

    }

}

This is my naxsi_cores.rules file:

##################################
## INTERNAL RULES IDS:1-999     ##
##################################
#@MainRule "msg:weird request, unable to parse" id:1;
#@MainRule "msg:request too big, stored on disk and not parsed" id:2;
#@MainRule "msg:invalid hex encoding, null bytes" id:10;
#@MainRule "msg:unknown content-type" id:11;
#@MainRule "msg:invalid formatted url" id:12;
#@MainRule "msg:invalid POST format" id:13;
#@MainRule "msg:invalid POST boundary" id:14;
#@MainRule "msg:invalid JSON" id:15;
#@MainRule "msg:empty POST" id:16;
#@MainRule "msg:libinjection_sql" id:17;
#@MainRule "msg:libinjection_xss" id:18;

##################################
## SQL Injections IDs:1000-1099 ##
##################################
MainRule "rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop" "msg:sql keywords" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1000;
MainRule "str:\"" "msg:double quote" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8,$XSS:8" id:1001;
MainRule "str:0x" "msg:0x, possible hex encoding" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:2" id:1002;
## Hardcore rules
MainRule "str:/*" "msg:mysql comment (/*)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1003;
MainRule "str:*/" "msg:mysql comment (*/)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1004;
MainRule "str:|" "msg:mysql keyword (|)"  "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1005;
MainRule "str:&&" "msg:mysql keyword (&&)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1006;
## end of hardcore rules
MainRule "str:--" "msg:mysql comment (--)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1007;
MainRule "str:;" "msg:semicolon" "mz:BODY|URL|ARGS" "s:$SQL:4,$XSS:8" id:1008;
MainRule "str:=" "msg:equal sign in var, probable sql/xss" "mz:ARGS|BODY" "s:$SQL:2" id:1009;
MainRule "str:(" "msg:open parenthesis, probable sql/xss" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1010;
MainRule "str:)" "msg:close parenthesis, probable sql/xss" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1011;
MainRule "str:'" "msg:simple quote" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1013;
MainRule "str:," "msg:comma" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1015;
MainRule "str:#" "msg:mysql comment (#)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1016;
MainRule "str:@@" "msg:double arobase (@@)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1017;

###############################
## OBVIOUS RFI IDs:1100-1199 ##
###############################
MainRule "str:http://" "msg:http:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1100;
MainRule "str:https://" "msg:https:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1101;
MainRule "str:ftp://" "msg:ftp:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1102;
MainRule "str:php://" "msg:php:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1103;
MainRule "str:sftp://" "msg:sftp:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1104;
MainRule "str:zlib://" "msg:zlib:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1105;
MainRule "str:data://" "msg:data:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1106;
MainRule "str:glob://" "msg:glob:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1107;
MainRule "str:phar://" "msg:phar:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1108;
MainRule "str:file://" "msg:file:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1109;
MainRule "str:gopher://" "msg:gopher:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1110;

#######################################
## Directory traversal IDs:1200-1299 ##
#######################################                                          
MainRule "str:.." "msg:double dot" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1200;
MainRule "str:/etc/passwd" "msg:obvious probe" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1202;
MainRule "str:c:\\" "msg:obvious windows path" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1203;
MainRule "str:cmd.exe" "msg:obvious probe" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1204;
MainRule "str:\\" "msg:backslash" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1205;
MainRule "str:/" "msg:slash in args" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:2" id:1206;

########################################
## Cross Site Scripting IDs:1300-1399 ##
########################################
MainRule "str:<" "msg:html open tag" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1302;
MainRule "str:>" "msg:html close tag" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1303;
MainRule "str:[" "msg:open square backet ([), possible js" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1310;
MainRule "str:]" "msg:close square bracket (]), possible js" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1311;
MainRule "str:~" "msg:tilde (~) character" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1312;
MainRule "str:`"  "msg:grave accent (`)" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1314;
MainRule "rx:%[23]."  "msg:double encoding" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1315;

####################################
## Evading tricks IDs: 1400-1500 ##
####################################
MainRule "str:&#" "msg:utf7/8 encoding" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$EVADE:4" id:1400;
MainRule "str:%U" "msg:M$ encoding" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$EVADE:4" id:1401;
MainRule "str:%" "msg:M$ encoding" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$EVADE:4" id:1402;
#############################
## File uploads: 1500-1600 ##
#############################
MainRule "rx:\.ph|\.asp|\.ht" "msg:asp/php file upload" "mz:FILE_EXT" "s:$UPLOAD:8" id:1500;

## Automated Scanner tools: 1600-1700 ##
MainRule "rx:fuzz" "msg:scanner tool ffuf detected" "mz:ARGS|URL|BODY|$HEADERS_VAR:USER-AGENT" "s:$SCANNER:4" id:1600;
MainRule  "str:sqlmap" "msg:Scanner sqlmap detected" "mz:$HEADERS_VAR:User-Agent" "s:$SCANNER:4" id:1601;

##XXE Detection: 1700-1800 ##
#MainRule "rx:<!ENTITY\s+[^\s]+\s+SYSTEM\s+['\"](?i:file|http|https|ftp|php|zlib|data|glob|phar|ssh2|rar|ogg|expect|zip)://" "msg:XML Injection detected" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie|FILE_EXT" "s:$XML:4" id:1700;
MainRule "rx:\.xml" "msg:xml file upload" "mz:FILE_EXT|BODY" "s:$UPLOAD:8" id:1701;
#MainRule "str:<!entity" "msg:XML Entity detected" "mz:ARGS|URL|RAW_BODY|BODY|$HEADERS_VAR:Cookie|FILE_EXT" "s:$XXE:4" id:1702;
MainRule "str:Entity" "msg:XML Entity detected" "mz:RAW_BODY" "s:$XXE:4" id:1702;
MainRule "str:System" "msg:XML System detected" "mz:RAW_BODY" "s:$XXE:4" id:1703;
cyndy08 commented 3 years ago

hello @wargio , could you find something useful from the configuration files?

wargio commented 3 years ago

looks like you haven't enabled naxsi in the *.php$ location and also in the / location. please check the wiki: https://github.com/nbs-system/naxsi/wiki/naxsi-setup#example-configuration You are missing SecRulesEnabled, DeniedUrl and CheckRule, which are required per location

cyndy08 commented 3 years ago

I have already included /etc/nginx/naxsi.rules in / location and this file defines SecRulesEnabled, DeniedUrl and CheckRule. So it is basicall the same. This my naxsi.rules file:

SecRulesEnabled;
DeniedUrl "/error.html";
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
CheckRule "$UPLOAD >= 8" BLOCK;
CheckRule "$SCANNER >= 4" BLOCK;
CheckRule "$XML >= 4" BLOCK;
CheckRule "$XXE >= 4" BLOCK;

But it works when i add include /etc/nginx/naxsi.rules; to \.php$ location. Now the request is blocked by Naxsi Thank you very much Is it a way to get more informations from the log message of Naxsi? And is it possible that naxsi also analyse and block the responses of the webserver before they reach the client if the have sensitive data?

wargio commented 3 years ago

if you use naxsi on an reverse proxy (RP), the web server behind the RP will never see the request. i would suggest to enable json logs (because it's easier to read them) and use also NXAPI for visualizing the data produced by naxsi.

Everything is explained on the wiki.