Current location

narf Source control manager Git

summaryrefslogtreecommitdiff
blob: 714fefb53f4bc078e8a4d5d4b0e859f1fa05da7f (plain)
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
#!/bin/sh
# $Id$
# Script to trawl logs for nastiness and log bad IP addresses
# From http://netnix.blogspot.com/2005/06/openbsd-ssh-protection.html
# Warning and whitelist features by Olivier Mehani <shtrom-openbsd@ssji.net>
#
# Minimal pf.conf file:
#  table <whitelist> persist file "/etc/whitelist"
#  table <kiddies> persist file "/var/tmp/blockers.list"
#  pass in quick on egress proto tcp from <whitelist> to (egress) port ssh
#  block in quick on $ext_if from <kiddies>
# Crontab entry:
#  */5     *       *       *       *       /usr/local/sbin/denyhost.sh
#
# Remember to manually populate your <whitelist> table:
#  # pfctl -vt whitelist -T add ADDRESS
# or by creating file /etc/whitelist (adding it to /etc/changelist may
# also be a good idea)
#
PATH=/usr/local/bin:$PATH
AUTHLOG=/var/log/authlog
NUM_TRIES=3
TMP_DIR=/var/tmp
NEW_BLOCKERS_FILE=`mktemp ${TMP_DIR}/blockers.list.XXXXXX`
DEST_ADDR=root@`hostname`

MAIL=mail

# Exit if another instance is already running.
# Selecting on 'R+' is a bit of a kludge to avoid getting yet to be named
# processes forks for the pipe of this very check...
ps ax | grep $0 | grep -v "R+" | grep -v $$ | grep -qv grep && exit 1

function process_ip
{
	HOST_FILE=`mktemp ${TMP_DIR}/host.XXXXXX`
	host $IP > $HOST_FILE
	HOSTS=`gsed -n "s/.*\(:\|domain name pointer\) \(.\+\)/\2/p" $HOST_FILE | \
		gsed ':a N;s/\n/, /g; ta'`

	WHOIS_FILE=`mktemp ${TMP_DIR}/whois.XXXXXX`
	whois $IP > $WHOIS_FILE
	ABUSE=`extract_email $WHOIS_FILE`
	
	LOGIN_FILE=`mktemp ${TMP_DIR}/logins.list.XXXXXX`
	grep $IP $AUTHLOG | grep -v "Received disconnect" > $LOGIN_FILE
	LOGINS=`gsed -n "s/.*sshd\[[0-9]\+\]: \(Invalid user\|Failed password for\( invalid user\)\?\) \([^[:space:]]\+\) from.*/\3/p" $LOGIN_FILE | \
		sort | uniq | gsed ':a N;s/\n/, /g; ta'`
	if [ -z "$ABUSE" ]; then
		NETS=`gsed -n "s/.*\(NET-[-0-9]\+\).*/\1/p" $WHOIS_FILE`
		for NET in $NETS; do
			whois $NET >> $WHOIS_FILE
		done
		ABUSE=`extract_email $WHOIS_FILE`
	fi
	if [ ! -z "$ABUSE" ]; then
		(
cat << EOF
Greetings,

[ This is an automated email, please report any problem to
<shtrom-admin@ssji.net> ]

Unauthorised login attempts have recently been observed from an IP address
in one of your administrative ranges ($IP), as identified by WHOIS
information.

Please find below reports from the blocking system, including logs of
connection attempts at the bottom.

Could you please take this machine down for cleanup, or forward this
message to its administrator in charge.

Offending IP: $IP
Hostnames: $HOSTS
Abuse addresses: $ABUSE
Usernames tried: $LOGINS
	
Host and WHOIS information:
EOF
		cat $HOST_FILE
		cat $WHOIS_FILE
		echo "Incriminating logs:"
		cat $LOGIN_FILE
		) | $MAIL -c $DEST_ADDR -s "Host $IP is compromised" $ABUSE
	else
		(
		echo "Offending IP: $IP"
		echo "Hostnames: $HOSTS"
		echo "Abuse addresses: $ABUSE"
		echo "Usernames tried: $LOGINS"
		echo
		echo "Host and WHOIS information:"
		cat $HOST_FILE
		cat $WHOIS_FILE
		echo "Incriminating logs:"
		cat $LOGIN_FILE
		) | $MAIL -s "Host $IP (admin unknown) is compromised" $DEST_ADDR
	fi
	rm -f $HOST_FILE $WHOIS_FILE $LOGIN_FILE
}

function extract_email
{
	grep -v changed $1 | gsed -n "s/.*[^-+\._A-Za-z0-9]\([-+\._A-Za-z0-9]\+@\([-A-Za-z0-9]\+\.\)\+[A-Za-z]\+\).*/\1/p" | \
		gsed "/whois-contact@lacnic.net/d; \
		/mail-abuse@cert.br/d; \
		/cert@cert.br/d; \
		/search-apnic-not-arin@apnic.net/d; \
		/hostmaster@nic.ad.jp/d; \
		/hostmaster@ripe.net/d; \
		/ncc@ripe.net/d; \
		/search-ripe-ncc-not-arin@ripe.net/d" | \
		sort | uniq | gsed ':a N;s/\n/, /g; ta'
}

SSH_INVALID_USERS=`sed -n "s/.*Invalid user .* from //p" $AUTHLOG | sort -u`
for iu in $SSH_INVALID_USERS; do
   num=`grep $iu $AUTHLOG | grep 'Invalid user' | wc -l`
   if [ $num -gt $NUM_TRIES ]; then
     echo "$iu"
   fi
done > ${TMP_DIR}/invalid_users.list

SSH_FAILED_PASSWORD=`grep 'Failed password for' $AUTHLOG | grep -v 'invalid user' | awk '{ print $11 }' | sort -u`
for fp in $SSH_FAILED_PASSWORD; do
   num=`grep $fp $AUTHLOG | grep 'Failed password for' | grep -v 'invalid user' | wc -l`
   if [ $num -gt $NUM_TRIES ]; then
     echo "$fp" 
   fi
done > ${TMP_DIR}/failed_passwords.list

sort -u ${TMP_DIR}/invalid_users.list ${TMP_DIR}/failed_passwords.list -o $NEW_BLOCKERS_FILE

pfctl -t kiddies -Tshow | sed "s/ //g" | sort -n > ${TMP_DIR}/blockers.list
for IP in `grep -v -f ${TMP_DIR}/blockers.list $NEW_BLOCKERS_FILE`; do
	process_ip $IP
done 

# Flush entries older than a week
pfctl -t kiddies -T expire 25200 1>/dev/null 2>&1 

# Add new entries
mv $NEW_BLOCKERS_FILE ${TMP_DIR}/blockers.list
pfctl -t kiddies -Tadd -f ${TMP_DIR}/blockers.list 1>/dev/null 2>&1