Ich bin immer wieder erstaunt, dass man im Internet doch relativ wenig zu ModSecurity findet. Dabei ist es ein wichtiges Werkzeug um Internetseiten wirksam vor Angriffen zu schützen. Die Idee hinter ModSecurity ist genial einfach. Alle Anfragen werden, unabhängig von der dahinter liegenden Internetseite, auf mögliche Angrifssvektoren überprüft und dann entweder durchgelassen oder blockiert. Der Vorteil an dieser Herangehensweise ist, dass man nicht darauf vertrauen muss, ob denn der Entwickler der Seite (dies kann eine interne Seite sein, oder die eines bekannten Herstellers) auf Sicherheit geachtet hat, sondern es werden einfach bestimmte Angriffe von vornherein abgeblockt. Ich teste dass immer gern mit dem einfachen Parameter:
https://website.de/?user=<script>alert(DANGER)</script>
Eigentlich sollte bei diesem Aufruf nichts passieren, ModSecurity erkennt aber den Script-Teil und blockiert den Aufruf mit einer 403-Fehlermeldung.
Was ich bis heute bei ModSecurity nicht verstehe, ist die komplizierte und nicht sehr auswertungsunfreundliche Formatierung der Log-Datei.
--6b253045-A--
[18/Aug/2020:08:25:15 +0100] SopXW38EAAE9YbLQ 192.168.3.1 2387 192.168.3.111 8080
--6b253045-B--
POST /index.html?a=test HTTP/1.1
Host: 192.168.3.111:8080
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://192.168.3.111:8080/index.html?a=test
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
--6b253045-F--
HTTP/1.1 200 OK
Last-Modified: Tue, 18 Aug 2020 07:17:44 GMT
ETag: "6eccf-99-4716550995f20"
Accept-Ranges: bytes
Content-Length: 159
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
Aber zum Glück gibt es bei den moderneren ModSecurity Versionen die Möglichkeit, die Daten als JSON ab zu legen. Dafür muss man in der apache.conf unterhalb des VirtualHost die folgenden Zeilen einfügen:
SecAuditLogFormat JSON
SecAuditLogParts ABEFHIJZ
SecAuditLogStorageDir /var/log/modsecurity/{{ site }}
Mein erster Ansatz war nun, diese Daten direkt per rsyslog an den Elastic Server zu schicken. Dies erwies sich aber als grandioser Fehlschlag. Nicht dass es nicht funktioniert hätte, die Daten wurden als JSON formatiert und auch an den Elastic Server geschickt. Idiotischerweise wurde aber der wichtige Teil, der Teil in dem die gesamte ModSecurity Meldung enthalten ist, als ein String formatiert. Sinnvollerweise hätte ich erwartet, dass so eine Meldung wie folgt aussieht:
"modsecurity": { "msg": "XSS Attack Detected via libinjection", "severity": "CRITICAL", "accuracy": "9", "data": "Matched Data: accept-language found within ARGS_NAMES:<script>alert(hi)</script>: <script>alert(hi)</script>", "file": "/etc/httpd/modsecurity.d/activated_rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf", "id": "941100", "rev": "2", "maturity": "1" },
Leider sah es aber wie folgt aus:
\"modsecurity\": {
\"msg\": \"XSS Attack Detected via libinjection\",
\"severity\": \"CRITICAL\",
\"accuracy\": \"9\",
\"data\": \"Matched Data: accept-language found within ARGS_NAMES:: \",
\"file\": \"/etc/httpd/modsecurity.d/activated_rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf\",
\"id\": \"941100\",
\"rev\": \"2\",
\"maturity\": \"1\"
},
Sprich, es wurde alles escaped. Deshalb war ich leider gezwungen ein Python Script zu schreiben, welches den ModSecurity Ordner überwacht, den Inhalt des neuen Eintrags parst und diesen dann an den Elastic Server schickt.