File: send-payload-pls.sh

package info (click to toggle)
modsecurity-crs 3.3.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,672 kB
  • sloc: ansic: 727; perl: 443; python: 421; sh: 90; ruby: 69; javascript: 53; makefile: 14
file content (170 lines) | stat: -rwxr-xr-x 7,101 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/bin/bash
#
# Script to post a payload against a local webserver at each paranoia level.
#
# Note: Webserver has to be prepared to take desired PL as Request Header "PL".
#
# WARNING: Setting the paranoia level using a header without proper
# authentication and authorization is extremely dangerous, and is not
# recommended for production.
#
# Check how to use the Christian Folini's Apache access log format at:
# https://www.netnea.com/cms/apache-tutorial-5_extending-access-log/
#
# LogFormat "%h %{GEOIP_COUNTRY_CODE}e %u [%{%Y-%m-%d %H:%M:%S}t.%{usec_frac}t] \"%r\" %>s %b \
# \"%{Referer}i\" \"%{User-Agent}i\" \"%{Content-Type}i\" %{remote}p %v %A %p %R \
# %{BALANCER_WORKER_ROUTE}e %X \"%{cookie}n\" %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x \
# %I %O %{ratio}n%% %D %{ModSecTimeIn}e %{ApplicationTime}e %{ModSecTimeOut}e \
# %{ModSecAnomalyScoreInPLs}e %{ModSecAnomalyScoreOutPLs}e \
# %{ModSecAnomalyScoreIn}e %{ModSecAnomalyScoreOut}e" extended
#
# This script assumes %{ModSecAnomalyScoreIn}e is the column before to last in
# the access log, if this does not match your LogFormat the script won't work
# For better results set the SecDefaultAction to 'pass'.
#
# The anomaly score envvar can be set as follows:
# SecAction "id:90101,phase:5,pass,nolog,\
#     setenv:ModSecAnomalyScoreIn=%{TX.anomaly_score}"
#
# Sample rule to setup the PL dynamically from localhost"
# SecRule REMOTE_ADDR "@ipMatch 127.0.0.1,192.168.0.128" \
#     "id:90102,phase:1,pass,capture,log,auditlog,\
#     msg:'Setting engine to PL%{matched_var}',chain"
#     SecRule REQUEST_HEADERS:PL "@rx ([1-4])" \
#         "setvar:'tx.executing_paranoia_level=%{matched_var}'"

# Path to CRS rule set and local files
CRS="/usr/share/modsecurity-crs/rules"
accesslog="/apache/logs/access.log"
errorlog="/apache/logs/error.log"
URL="localhost:40080"
protocol="http"
while [[ $# > 0 ]]
do
    case "$1" in
        -c|--crs)
            CRS="$2"
            shift
            ;;
        -a|--access)
            accesslog="$2"
            shift
            ;;
        -e|--error)
            errorlog="$2"
            shift
            ;;
        -u|--url)
            URL="$2"
            shift
            ;;
        -r|--resolve)
            resolve="$2"
            resolve="--resolve $resolve"
            shift
            ;;
        --protocol)
            protocol="$2"
            shift
            ;;
        -P|--payload)
            PAYLOAD="$2"
            shift
            ;;
        -h|--help)
            echo "Usage:"
            echo " --access \"/apache/logs/access.log\""
            echo " --error \"/apache/logs/error.log\""
            echo " --url \"localhost:40080\""
            echo " --resolve \"someservername:40080:localhost\""
            echo " --protocol \"https\""
            echo " --payload \"/tmp/payload\""
            echo " --help"
            exit 1
            ;;
    esac
    shift
done

echo "Using CRS: $CRS"
echo "Using accesslog: $accesslog"
echo "Using errorlog: $errorlog"
echo "Using URL: $URL"
echo "Using protocol: $protocol"

if [ -z "${PAYLOAD+x}" ]; then
    echo "Please submit valid payload file as parameter. This is fatal. Aborting."
    $0 -h
    echo "Examples:"
    echo "  ./send-payload-pls.sh -a /logs/test/access.log \
        -e /logs/test/error.log -u test.test.test.com:6443 --protocol https \
        --payload /tmp/payload --resolve test.test.test.com:6443:192.168.0.128"
    echo "  ./send-payload-pls.sh -a /logs/test/access.log \
        -e /logs/test/error.log -u test.test.test.com:6443 --protocol https \
        --payload 'or 1=1;--' --resolve test.test.test.com:6443:192.168.0.128"
    exit 1
fi

# URL of web server

# Rules per Paranoia level
# Paranoia level 1 rules, rule 012 is the delimiter of the start of PL1
# Paranoia level 1 rules, rule 013 is the delimiter of the end of PL1
PL1=$(awk "/012,phase:2/,/013,phase:1/" $CRS/*.conf |egrep -v "(012|013),phase" |egrep -o "id:[0-9]+" |sed -r 's,id:([0-9]+),\1\\,' |tr -t '\n' '\|' |sed -r 's,\\\|$,,')

# Paranoia level 2 rules, rule 014 is the delimiter of the start of PL2
# Paranoia level 2 rules, rule 015 is the delimiter of the end of PL2
PL2=$(awk "/014,phase:2/,/015,phase:1/" $CRS/*.conf |egrep -v "(014|015),phase" |egrep -o "id:[0-9]+" |sed -r 's,id:([0-9]+),\1\\,' |tr -t '\n' '\|' |sed -r 's,\\\|$,,')

# Paranoia level 3 rules, rule 016 is the delimiter of the start of PL3
# Paranoia level 3 rules, rule 017 is the delimiter of the end of PL3
PL3=$(awk "/016,phase:2/,/017,phase:1/" $CRS/*.conf |egrep -v "(016|017),phase" |egrep -o "id:[0-9]+" |sed -r 's,id:([0-9]+),\1\\,' |tr -t '\n' '\|' |sed -r 's,\\\|$,,')

# Paranoia level 4 rules, rule 018 is the delimiter of the start of PL4
# Paranoia level 4 rules, "Paranoia Levels Finished" delimiter of the end of PL4
PL4=$(awk "/018,phase:2/,/Paranoia Levels Finished/" $CRS/*.conf |egrep -v "018,phase" |egrep -o "id:[0-9]+" |sed -r 's,id:([0-9]+),\1\\,' |tr -t '\n' '\|' |sed -r 's,\\\|$,,')

echo "Sending the following payload at multiple paranoia levels: $PAYLOAD"
echo

for PL in 1 2 3 4; do
    echo "--- Paranoia Level $PL ---"
    echo
    if [ -f "$PAYLOAD" ]; then
        curl $protocol://$URL $resolve -k --data-binary "@$PAYLOAD" -H "PL: $PL" -o /dev/null -s
    else
        curl $protocol://$URL $resolve -k -d "$PAYLOAD" -H "PL: $PL" -o /dev/null -s
    fi

    # Here are three ways to get the transaction unique id,
    # the first one is Christian's format, second is Spartan's format,
    # and the third one tries to guess which is the unique id using a
    # regular expression, the first two require specific format.
    # The automatic format detection may cause the script to malfunction.
    # Uncomment only the required format.
    # To use Christian's accesslog format uncomment the following line
    uniq_id=$(tail -1 $accesslog | cut -d\" -f11 | cut -b2-26)

    # To use Spartan's accesslog format (21 col) uncomment the following line
    #uniq_id=$(tail -1 $accesslog | awk '{print $21}')

    # To use the automatic unique_id detection uncomment the following line
    #uniq_id=$(tail -1 $accesslog | egrep -o '[a-zA-Z0-9]{26,28}')

    echo "Tracking unique id: $uniq_id"

    grep $uniq_id $errorlog | sed -e "s/.*\[id \"//" -e "s/\(......\).*\[msg \"/\1 /" -e "s/\"\].*//" -e "s/(Total .*/(Total ...) .../" -e "s/Incoming and Outgoing Score: [0-9]* [0-9]*/Incoming and Outgoing Score: .../" | sed -e "s/$PL1/& PL1/" -e "s/$PL2/& PL2/" -e "s/$PL3/& PL3/ " -e "s/$PL4/& PL4/" | sort -k2 | sed -r "s/^([0-9]+)$/\1 FOREIGN RULE NOT IN CRS/"

    echo
    echo -n "Total Incoming Score: "

    # Here are two ways to get the transaction anomaly score,
    # the first one is Christian's format, second is Spartan's format
    # To use Christian's accesslog format uncomment the following line
    tail -1 $accesslog | cut -d\" -f11 | cut -d\  -f14 | tr "-" "0"

    # To use Spartan's accesslog format (21 col) uncomment the following line
    # To use a different column change the $NF value, e.g. $(NF-1)
    #tail -1 $accesslog | awk '{print $NF}' | tr "-" "0"
    echo
done