DEV Community

Carrie
Carrie

Posted on

Automated Security Operations with Safeline WAF (Part 1)

This article is originally written by a SafeLine user: 爱吃麦当劳.

Disclaimer

This tutorial is prepared for legitimate educational purposes only. It is strictly prohibited to use it for any illegal activities or commercial purposes. Before using this tutorial, ensure that your actions comply with local laws and regulations.

Introduction

I use the free edition of Safeline WAF(https://waf.chaitin.com/), but many features are restricted. Therefore, I began to automate the security operations.

Mapping Database Ports

#!/bin/bash

# Run the install/update script
bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)"

# Enter the /data/safeline directory
cd /data/safeline || { echo "/data/safeline not found!"; exit 1; }

# Check if compose.yaml exists and back it up
if [ -f compose.yaml ]; then
    echo "Backing up the current compose.yaml"
    cp compose.yaml compose.yaml.bak
else
    echo "compose.yaml not found in /data/safeline!"
    exit 1
fi

# Check if port mapping already exists
if grep -q "5433:5432" compose.yaml; then
    echo "PostgreSQL port mapping already exists."
else
    # Use sed to insert ports field into the postgres service
    sed -i '/container_name: safeline-pg/a\    ports:\n      - 5433:5432' compose.yaml
    echo "PostgreSQL port mapping added to 5433:5432."
fi

# Restart the containers to apply changes
docker compose down --remove-orphans && docker compose up -d

echo "Containers restarted with the updated compose.yaml"
Enter fullscreen mode Exit fullscreen mode

This script is useful for remapping the database ports each time an update is done.

Extracting Alert Logs

Use cat /data/safeline/.env | grep POSTGRES_PASSWORD | tail -n 1 | awk -F '=' '{print $2}' to find the database password.

Then, write the following code into /var/scripts/.pgpass, and set its permissions to 600:

localhost:5433:safeline-ce:safeline-ce:abcd # Replace 'abcd' with the password obtained in the previous step
Enter fullscreen mode Exit fullscreen mode
#!/bin/bash

# Set the PGPASSFILE environment variable
export PGPASSFILE=/var/scripts/.pgpass

# PostgreSQL connection information
PG_HOST="localhost"
PORT="5433"
DATABASE="safeline-ce"
USERNAME="safeline-ce"
HOSTNAME=$(hostname)
PROGRAM_NAME="safeline-ce"

# Get the ID of the last WAF attack event log
LAST_ID=$(psql -h $PG_HOST -p $PORT -U $USERNAME -d $DATABASE -t -P footer=off -c "SELECT id FROM PUBLIC.MGT_DETECT_LOG_BASIC ORDER BY id desc limit 1")
while true; do
    # Get the latest WAF attack event log from the PostgreSQL database
    raw_log=$(psql -h $PG_HOST -p $PORT -U $USERNAME -d $DATABASE -t -P footer=off -c "SELECT TO_CHAR(to_timestamp(timestamp) AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD HH24:MI:SS'), CONCAT(PROVINCE, CITY) AS SRC_CITY, SRC_IP, CONCAT(HOST, ':', DST_PORT) AS HOST,url_path,rule_id,id FROM PUBLIC.MGT_DETECT_LOG_BASIC where id > '$LAST_ID' ORDER BY id asc limit 1")
    # Check SQL query results, if new logs are generated, rewrite the SQL query results as syslog logs, and record them in /var/log/waf_alert/waf_alert.log
    if [ -n "$raw_log" ]; then
        ALERT_TIME=$(echo "$raw_log" | awk -F ' \\| ' '{print $1}')
        SRC_CITY=$(echo "$raw_log" | awk -F ' \\| ' '{print $2}')
        SRC_IP=$(echo "$raw_log" | awk -F ' \\| ' '{print $3}')
        DST_HOST=$(echo "$raw_log" | awk -F ' \\| ' '{print $4}')
        URL=$(echo "$raw_log" | awk -F ' \\| ' '{print $5}')
        RULE_ID=$(echo "$raw_log" | awk -F ' \\| ' '{print $6}')
        EVENT_ID=$(echo "$raw_log" | awk -F ' \\| ' '{print $7}')
        syslog="src_city:$SRC_CITY, src_ip:$SRC_IP, dst_host:$DST_HOST, url:$URL, rule_id:$RULE_ID, log_id:$EVENT_ID"
        echo $ALERT_TIME $HOSTNAME $PROGRAM_NAME: $syslog >> /var/log/waf_alert/waf_alert.log
        # Update the last processed event ID
        LAST_ID=$(($LAST_ID+1))
    fi
    sleep 3
done
Enter fullscreen mode Exit fullscreen mode

This script extracts alert logs to /var/log/waf_alert/waf_alert.log. Before executing the log extraction script, install postgresql-client using apt install postgresql-client.

Run it in the background or write it into the systemctl startup script: nohup /var/scripts/waf_log.sh > /dev/null 2>&1 &

Monitoring Log File Changes

To monitor log file changes and trigger alert scripts, install inotify-tools on Linux. The inotifywait command can monitor file modification events and trigger a command when a change is detected.

Install inotify-tools

apt update
apt install inotify-tools
Enter fullscreen mode Exit fullscreen mode

Use inotify-tools

Create a monitor.sh script with the following content:

#!/bin/bash

# Path to the log file to monitor
LOG_FILE="/var/log/waf_alert/waf_alert.log"

# Command to execute when log file changes
COMMAND_TO_EXECUTE="/var/scripts/Log_Push_linux_amd64"  # Here, execute DingTalk notification

# Use inotifywait to continuously monitor the log file for modifications
inotifywait -m -e modify "$LOG_FILE" | while read path action file; do
    echo "Detected $action on $file. Executing command..."
    # Execute the specified command
    $COMMAND_TO_EXECUTE
done
Enter fullscreen mode Exit fullscreen mode

Run this script in the background, or set it as a startup item.

Implementing DingTalk Push Notifications

Here I use Golang to achieve this, which can push notifications to DingTalk.

Here is the source code: https://github.com/Fiary-Tale/Log_Push

Result

Image description

Autostart on Boot

Create a waf_monitor.service file:

[Unit]
Description=WAF Log Monitor Service
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash /var/scripts/waf_log.sh
ExecStartPost=/bin/bash /var/scripts/monitor.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Then execute the following commands:

systemctl daemon-reload          # Reload systemd configuration
systemctl enable waf_monitor.service  # Enable autostart on boot
systemctl start waf_monitor.service    # Start the service
Enter fullscreen mode Exit fullscreen mode

Top comments (0)