Dev.to Security 🔐 Cybersecurity 👁 0 📖 2 min read

Zero Day Protection - NGINX web server example

The recent PHP vulnerability got me thinking about how to prevent any kind of HTTP exploit be it known or not. In order for an attacker to exploit a weakness they must discover it. In order to discover an exploitable se

The recent PHP vulnerability got me thinking about how to prevent any kind of HTTP exploit be it known or not. In order for an attacker to exploit a weakness they must discover it. In order to discover an exploitable service the attacker much send a lot of probes. we see these probes on any web server that's open to the internet 24/7.

The web server at my home is constantly, shamelessly groped.

This inspired me to write a script that tails the web server log and takes action based on configurable attributes.

  • If we see three requests resulting in HTML status codes that have been designated 'not normal' for this web server, we signal Netfilter to block any traffic from the source IP of the request.
  • If we see any request from a HTTP user agent we've deemed unworthy we signal Netfilter to block any traffic from the source IP of the request. Seriously, would any human be using a user agent such as?:

"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36; compatible; OAI-SearchBot/1.4; robots.txt; +https://openai.com/searchbot"

Dropping the traffic at layer 3 appeals to me as we prevent any other buffoonery from this IP address. If we send and ICMP unreachable back, this consumes our resources. By dropping it the attacker knows not if it's just a slow connection or a non-existent server and will wait till it times out, consuming their resources.

The script goes like this:

  • Tail the log
  • Use a 'while' loop to process each new log message
  • The NGINX log was converted to a JSON format in order to have a predictable data structure. This is very helpful for scripts that ingest it. We realize the benefit of the data structure by loading log message with the python3 json module
  • Next we evaluate the log data:
    • if the request was from a trusted network stop processing it, we are OK with any request from a trusted network.
    • update a hash of clients that keeps track of each public IP address, status codes, and number of times the status code was returned.
    • If the user agent contains a predefined term that's deemed unsavory signal Netfilter to block the public IP address of the request
    • if the returned status codes is in a predefined list and exceeds a predefined number of occurrences block the public IP address of the request.

This routine looks like this:

while True:
    logLine = logTail.stdout.readline()
    logLine = logLine.decode(errors='ignore').strip()
    logHash = json.loads(logLine)
    clientIp = logHash['remote_addr']
    status = logHash['status']
    trust = checkAddress(clientIp)
    if trust == 'untrust':
        print('untrusted')
        if clientIp not in clientHash:
            clientHash[clientIp] = {}
        if status not in clientHash[clientIp]:
            clientHash[clientIp][status] = 0
        clientHash[clientIp][status] += 1
        if logHash['http_user_agent'] == '' or logHash['http_user_agent'] == '-':
            print('stupid user agent')
            doBlock(clientIp)
        for ua in unwantedAgents:
            if ua in logHash['http_user_agent']:
                print('blocking unwanted user agent')
                doBlock(clientIp)
        if status in blockableStatusCodes:
            if clientHash[clientIp][status] >= blockThreshold and clientIp not in blockedSet:
                print('strike ' + str(clientHash[clientIp][status]) + '!')
                doBlock(clientIp)
            else:
                print('strike ' + str(clientHash[clientIp][status]) + '!')

The complete script may be found here:
https://gist.github.com/netdsg/cc338230a46f8a01c1b25983d5935143

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.