summaryrefslogtreecommitdiff
path: root/no_buster.sh
blob: 25ac7599bbf1a00519c17e556908b6514fad530b (plain) (blame)
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
#!/usr/bin/env bash

# no_buster - a tool to check if someone uses a 'default' wordlist to gain access to web directorys that are not visible by default
# author: Mike Wollmann aka. jak1
# requires: root access
#           iptables
# 
# TODO/WIP:
#   add: checks if apache has this path, so we don't catch real paths in our routin and accidentaly ban someone for using the webservices the right way X_X!


# --> configuration section
max_rows=2; # when get 5 (default) hits in a row the ip gets blocked 
dir_files="./wordlists/dirb/common.txt ./wordlists/dirbuster/apache-user-enum-1.0.txt"; # dont add more then 10 files! every file has 10 words to check for! 10*10 = 100 words per log entry! every 60 secounds per default.
check_first_x_lines=10;
wl_file_opt="head -n${check_first_x_lines}";

check_every_sec=60; # time between checks
check_log_lines=10; # 10 by default, can be increased, but will cause some cpu usage the higher it is.
log_file_opt="tail -n${check_log_lines}"; # using tail
access_log="/var/log/apache2/access.log";
access_log="./access.log"; # remove this line later!

no_buster_log_dir="/var/log/no_buster/";
no_buster_log_file="no_buster";

ip_tables="/sbin/iptables";
ip_tables_chain="no_buster";
# <-- configuration section


if [[ `whoami` != "root" ]]; then
    echo "you need to be root for:";
    echo " - reading ${access_log}";
    echo " - reading and writing to iptables";
    echo " - writing no_buster.log to ${no_buster_log_dir}";
    exit 1
fi

n=`which iptables`
if [[ $? != 0 ]]; then
    echo "iptables is required!";
fi
unset $n

function cac_chain(){
    # check and create chain
    check=`${ip_tables} -L ${ip_tables_chain} -v -n`;
    if [[ $? != 0 ]]; then
        `${ip_tables} -N ${ip_tables_chain}`;
        `${ip_tables} -A OUTPUT -j ${ip_tables_chain}`;
        `${ip_tables} -A ${ip_tables_chain} -p tcp --dport 80  -j ACCEPT`;
        `${ip_tables} -A ${ip_tables_chain} -p tcp --dport 443  -j ACCEPT`;
        echo "chain '${ip_tables_chain}' created";
    fi
}

function logging(){
    if [[ ! -d "${no_buster_log_dir}" ]]; then
        mkdir -p "${no_buster_log_dir}";
    fi
    timestamp=$(date +'%d.%m.%Y - %r');
    filedate=$(date +'%m-%Y');
    echo -e "${timestamp}: ${1}" >> "${no_buster_log_dir}${no_buster_log_file}-${filedate}.log";
}

function block_ip(){
    # dont block loopback!
    if [[ "${1}" != "127.0.0.1" ]]; then
        check=`${ip_tables} -L ${ip_tables_chain} -v -n | grep "${1}"`;
        if [[ ${?} != 0 ]]; then
            # http:// (should not even get used anymore)
            e1=`${ip_tables} -A ${ip_tables_chain} -p tcp --dport 80 -s "${1}" -j DROP`;
            # https://
            e2=`${ip_tables} -A ${ip_tables_chain} -p tcp --dport 443 -s "${1}" -j DROP`;
            logging "${1} got blocked for ports: 80 & 443\n                        ${2}";
            return 1
        else
            # because of log spam ^^' cause of tail -n{N} it well get removed in the next {N} hits via p80/p443
            #logging "WARN: $1 got allready blocked"
            #logging "${check}"
            return 0
        fi
    fi
    return 0

}

function wl_check(){
    n_ip="";
    last_lines=`${log_file_opt} ${access_log}`;
    IFS=$'\n' read -rd '' -a y <<<"$last_lines";
    o_hit_paths="";
    for ((i = 1; i < ${#y[@]}; i++)); do
        o_ip=`echo ${y[$i]} | awk '{print $1}'`;
        o_hit_path=`echo ${y[$i]} | awk '{print $7}'`;
        if [[ "${n_ip}" == "${o_ip}" || ${n_ip} == "" ]]; then
            for dir_file in ${dir_files}; do
                if [[ -f "${dir_file}" ]]; then
                    wl_file=`${wl_file_opt} ${dir_file}`;
                    for x in ${wl_file}; do
                            if [[ "${o_hit_path}" == *"${x}"* ]]; then
                                hits_per_row=$((hits_per_row+1));
                                o_hit_paths="${o_hit_paths}\n\t\t\t\t${o_hit_path}";
                                if [[ ${hits_per_row} -ge ${max_rows} ]]; then
                                    block_ip ${o_ip} "reason:\n\t\t\t\tfound '${hits_per_row}' hits in a row. \n\t\t\tpaths:${o_hit_paths}";
                                fi
                                break;
                            else        
                                o_hit_paths="";
                                hits_per_row=0;
                            fi
                    done
                fi
            done
        fi
        n_ip=${o_ip};
    done
}


running=1;
cac_chain;
while [[ ${running} != 0 ]]; do
    wl_check;
    sleep ${check_every_sec};
done