Transform your passive defense into active defense with ModSecurity and MISP

Transform your passive defense into active defense with ModSecurity and MISP

“Threat Intelligence is the key that unlocks all the doors.”

 

      1. Prerequisites
      2. (Very) High Level design
      3. MISP integration
      4. ModSecurity configuration
      5. Jenkins automation
      6. RBL integration
      7. Complete workflow
      8. Conclusion

1. Prerequisites

ModSecurity is a toolkit for real-time Web Application monitoring, logging, and access control.

The MISP threat sharing platform is a free and open source software that helps to share information about threat intelligence including Cybersecurity indicators.

 

The leading open source automation server, Jenkins, provides hundreds of plugins to support building, deploying and automating projects.

 

A “named” DNS server

 

2. (Very) High Level design

 

3. MISP integration

On your WAF, create the following file in: /usr/local/bin/waf2misp.py

#!/usr/bin/env python

### Library
import urllib3, re, json, requests, time, sys, datetime, smtplib
from pymisp import PyMISP
from datetime import datetime
import os

# Disable TLS warning
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Default Variables
ioc_category = "Network activity"


### Functions
# Date to Epoch
def convertToEpoch(date):
     pattern = '%Y-%m-%d'
     return int(time.mktime(time.strptime(date, pattern)))

# Push to Misp
def pushtoMISP(ioc_value):
     # Variable: MISP URL, Cert, Key
     misp_url = 'https://misp.security-center.io/'
     misp_verifycert = False
     misp_key = "**************************************"


     # MISP connection
     misp = PyMISP(misp_url, misp_key, True, 'json')

     #date = "2018-02-28"
     i = datetime.now()
     date = i.strftime('%Y-%m-%d')

     # Set the event name
     Event_name = "ModSecurity - "+date+" - Honeypot"

     # Prepare MISP attribute
     misp_attributes = []
     ioc_datetime = str(convertToEpoch(date))
     comments = " "
     misp_attribute = {'category': ioc_category, 'type': 'ip-dst', 'value': ioc_value, 'distribution': '0', 'to_ids': True, 'comment': comments , 'timestamp': ioc_datetime}
     misp_attributes.append(misp_attribute)

     # Prepare MISP event
     misp_event = {'Event':{'info': Event_name, 'date': date, 'distribution': '0', 'threat_level_id': '1', 'analysis': '2', 'Tag': [{'name': 'ModSecurity'}, {'name': 'AUTO'}],'Attribute': misp_attributes}}

     # Insert Event + Attribute to MISP
     misp_event_added = misp.add_event(misp_event)
     # Publish (/!\ Bring in production)
     misp.publish(misp_event_added)


### Main
def main():
     global ip_to_add
     ip_to_add=str(os.environ["ATTACKER"])
     pushtoMISP(ip_to_add)

if __name__ == "__main__":
     main()

 

4. ModSecurity configuration

In our ModSecurity configuration, we will configure some rules for “Attack limitation”. For example:

Limit directory bruteforce

### 21 - Bruteforce Directory block
SecRule IP:BFDIR_ATTEMPT "@gt 12" "log,drop,phase:1,id:21,msg:'Too many 404 detected',logdata:'Too many 404',setenv:ATTACKER=%{REMOTE_ADDR},exec:/usr/local/bin/waf2misp.py"

### 22 - 404 Brute force
SecRule RESPONSE_STATUS "404" "phase:3,t:none,id:'22',nolog,setvar:ip.bfdir_attempt=+1,deprecatevar:ip.bfdir_attempt=5/15,expirevar:ip.bfdir_attempt=60"

 

Limit too many attacks

###1600, 1601 - Block request
SecRule IP:BADGUY_ATTEMPT "@gt 15" "log,drop,phase:1,id:1600,msg:'Too many 403 detected. Blocking for 3600s',logdata:'Too many 403. Blocking for 3600s',setenv:ATTACKER=%{REMOTE_ADDR},exec:/usr/local/bin/waf2misp.py"
SecRule TX:ANOMALY_SCORE "@ge %{tx.inbound_anomaly_score_level}" "chain,phase:5,t:none,id:1601,nolog,setvar:ip.badguy_attempt=+1,deprecatevar:ip.badguy_attempt=5/120,expirevar:ip.badguy_attempt=3600"
       SecRule TX:ANOMALY_SCORE_BLOCKING "@streq on"

 

4(bis). ModSecurity configuration

Transform your site in active HoneyPot

### HoneyPot
## 110 - Add form
SecRule STREAM_OUTPUT_BODY "@rsub s/<\/form>/<input type=\"hidden\" name=\"debug\" value=\"false\"><\/form>/" "id:'110',phase:4,t:none,nolog,pass"

## 111 - Exploit form changes
SecRule ARGS:debug "!@streq false" "id:'111', phase:2, t:none, log, pass, msg:'HoneyTrap alert', setenv:ATTACKER=%{REMOTE_ADDR},exec:/usr/local/bin/waf2misp.py"

 

The rule 110 adds a hidden input in any form. A “normal” user is not supposed to manipulate this.

If the value for the argument name “debug” is different than false, then we perform some actions…

 

5. Jenkins automation

We will use this custom script from Jenkins to export our MISP IPs and generate a rbl DNS zone (tools/generate_dnsbl.py)

#!/usr/bin/env python
import requests
import datetime
import sys
import re
import time
import socket

headers = {'Accept': 'application/xml', 'content-type': 'application/xml', 'Authorization': '*****************************'}
zone_name = 'dnsbl.security-center.io'
url_ip_dst = 'https://misp.security-center.io/attributes/text/download/ip-dst/false/false/false/2016-01-01/'
url_ip_src = 'https://misp.security-center.io/attributes/text/download/ip-src/false/false/false/2016-01-01/'


r_ip_dst = requests.get(url_ip_dst,headers=headers)
r_ip_src = requests.get(url_ip_src,headers=headers)

clean_ip_dst = r_ip_dst.content.replace("*." , "")
clean_ip_src = r_ip_src.content.replace("*." , "")


list_ip_dst = clean_ip_dst.split("\n")
list_ip_src = clean_ip_src.split("\n")

#
# Print header of zone file
#
print """;dnsbl.security-center.io
;auto-generated on %s by %s
$TTL 300
@ in soa ns.security-center.io. postmaster.security-center.io. (
         %d ;serial
         10800 ;refresh
         3600 ;retry
         604800 ;expiration
         86400 ) ;minimum

     IN NS ns1.security-center.io.
     IN NS ns2.security-center.io.

""" % (time.ctime(), socket.gethostname(), int(time.time()))

#
# Print ip from MISP
#
for ioc in list_ip_dst[4:] :
     if ":" not in ioc:
          reverse_ip = '.'.join(ioc.split('.')[::-1]) + "." + zone_name + "."
          print "%s IN A 127.0.0.3" % (reverse_ip)

for ioc in list_ip_src[4:] :
     if ":" not in ioc:
          reverse_ip = '.'.join(ioc.split('.')[::-1]) + "." + zone_name + "."
          print "%s IN A 127.0.0.3" % (reverse_ip)

 

-> Source Management

-> Trigger

 

-> Define environment

-> Build

 

Our rbl zone is now up to date thanks to Jenkins and MISP. We can also add a post build to send an email, or a message in a Slack room when the build is over.

 

6. RBL integration

SecRule REMOTE_ADDR "@rbl dnsbl.security-center.io" "id:'120',phase:1,drop,noauditlog,msg:'Attacker detected using RBL from dnsbl.security-center.io'"

 

7. Complete workflow

 

8. Conclusion

When you are managing several heterogeneous environments, it is important to centralize information on threats because it is the key in order to block future threats. knowledge is the key. The problem is that most of the existing solutions have their own Threat Intelligence. Therefore, other products cannot interact with them, and in fact, sometimes it is just a black box solution. This is why MISP arrived, and saved the world!!!

Thanks to MISP, we are now able to centralize things, interact with other security groups, and manage data in every format we want through the API. In this article, MISP has helped to centralize your attacks in a single place, and share the information with other WAF. It will reduce the scope of attacks in your environment and protect your clients on current threats.

 


Keywords: ModSecurity, HoneyPot, MISP, RBL, Jenkins, Automation, Web Application Firewall, Threat Intelligence, CIRCL, blog.security-center.io