Postfix ban failed logins script

Fail2ban hasn’t been working for me, I still have people running brute force attacks on my Postfix server, so I though I’d rig up something myself.

This consists of a bash script that identifies multiple failures and bans them, run on cron every 10 minutes. It checks for both smtp and pop/imap login failures.

#!/bin/sh
# postfix ban failed login ips
# get all failed ip addresses into files
cat /var/log/maillog | grep "authentication failed" | grep -Eo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" > ~admin/mail_fail_smtp
cat /var/log/maillog | grep "auth failed" | grep -Eo "rip=([0-9]{1,3}[\.]){3}[0-9]{1,3}" > ~admin/mail_fail_imap
find ~admin/mail_fail_imap -type f -exec sed -i 's/rip=//g' {} \;
# only get over 5 fails (change the limit= part to change)
sort ~admin/mail_fail_imap | uniq -cd | awk -v limit=5 '$1 > limit{print $2}' > ~admin/mail_fail_imap_over5
sort ~admin/mail_fail_smtp | uniq -cd | awk -v limit=5 '$1 > limit{print $2}' > ~admin/mail_fail_smtp_over5
# read through files and add IP to hosts.deny if not there already
while read p; do
if grep $p /etc/hosts.deny; then
echo $p " already added"
else
echo ALL: $p >> /etc/hosts.deny
fi
done < ~admin/mail_fail_smtp_over5
while read p; do
if grep $p /etc/hosts.deny; then
echo $p " already added"
else
echo ALL: $p >> /etc/hosts.deny
fi
done < ~admin/mail_fail_imap_over5
# clean up
rm -f ~admin/mail_fail_smtp
rm -f ~admin/mail_fail_imap
rm -f ~admin/mail_fail_smtp_over5
rm -f ~admin/mail_fail_imap_over5

Then added to crontab:

*/10 * * * * /home/admin/postfix_ban_ips.sh > /dev/null

And just in case the localhost fails and is unintentionally blocked (this is quicker than filtering it out above):

echo "ALL: 127.0.0.1" >> /etc/hosts.allow

Linode Xen to KVM upgrade breaks quotas

On a Linode Virtualmin CentOS 6 the upgrade from Xen to KVM breaks quotas with the following error:

repquota: Cannot stat() mounted device /dev/root: No such file or directory

The issue is that the symbolic link /dev/root is linking to /dev/xvda which has been replaced by /dev/sda so the symlink just needs to be replaced:

# rm /dev/root
# ln -s /dev/sda /dev/root

Then pop into Virtualmin (Webmin, System, Disk Quotas) and turn the quotas back on.

Fix nss-softokn rpm/yum issue in CentOS 6

The recent update to nss-softokn breaks rpm/yum updates in CentOS 6.

To restore functionality run these commands:

For 64-bit:

# wget http://mirror.centos.org/centos/6/updates/x86_64/Packages/nss-softokn-freebl-3.14.3-19.el6_6.x86_64.rpm
# rpm2cpio nss-softokn-freebl-3.14.3-19.el6_6.x86_64.rpm | cpio -idmv
# cd lib64
# cp libfreeblpriv3.* /lib64
# yum update

For 32-bit:

# wget http://mirror.centos.org/centos/6/updates/i386/Packages/nss-softokn-freebl-3.14.3-19.el6_6.i686.rpm
# rpm2cpio nss-softokn-freebl-3.14.3-19.el6_6.i686.rpm | cpio -idmv
# cd lib
# cp libfreeblpriv3.* /lib
# yum update

Dovecot brute-force blocking with fail2ban

If you are getting any brute force attacks to your dovecot imap/pop3 server, install fail2ban to block the offenders. This works on CentOs 5.7. For other distributions, see the relevant websites.

Firstly, install fail2ban. You should have the rpmforge repo from my previous post. Enable it first to install fail2ban:

# cd /etc/yum.repos.d/
# vi rpmforge.repo

Change it to enabled = 1 and save

Then it’s simple:

# yum install fail2ban

After installation I recommend disabling the repo. Edit the file and change to enabled = 0

Then make sure the service starts up:

# chkconfig --add fail2ban
# chkconfig fail2ban on
# service fail2ban start

Create a new filter file for your dovecot:

# vi /etc/fail2ban/filter.d/dovecot-pop3imap.conf

Paste in the following definition:

[Definition]
failregex = pam.*dovecot.*(?:authentication failure).*rhost=(?:::f{4,6}:)?(?P<host>\S*)
ignoreregex =

Then add the new information to the main config file:

# vi /etc/fail2ban/jail.conf

At the end, add the following:

[dovecot-pop3imap]
enabled = true
filter = dovecot-pop3imap
action = iptables-multiport[name=dovecot-pop3imap, port="pop3,pop3s,imap,imaps", protocol=tcp]
# optional mail notification
# mail[name=dovecot-pop3imap, dest=root@domain]
# see /etc/fail2ban/action.d/ or Fail2Ban doc
logpath = /var/log/secure
maxretry = 20
findtime = 1200
bantime = 1200

That’s it!

CentOs: Install ffmpeg & ffmpeg-php 0.6

The ffmpeg installed by yum cannot be used with ffmpeg-php, so we need to download and compile it:

cd ~admin/software
wget http://www.ffmpeg.org/releases/ffmpeg-0.6.tar.gz
tar zxfv ffmpeg-0.6.tar.gz
cd ffmpeg-0.6
./configure --enable-shared
make
make install

Now we need to download and configure ffmpeg-php:

cd ~admin/software
wget http://downloads.sourceforge.net/project/ffmpeg-php/ffmpeg-php/0.6.0/ffmpeg-php-0.6.0.tbz2?use_mirror=puzzle&ts=1278667907
tar -xjf ffmpeg-php-0.6.0.tbz2
cd ffmpeg-php-0.6.0
phpize
./configure

There’s an error in this version (0.6) we need to correct or it won’t compile, so run:

vi ffmpeg_frame.c

We need to substitute PIX_FMT_RGBA32 for PIX_FMT_RGB32, so enter this command :%s/PIX_FMT_RGBA32/PIX_FMT_RGB32 and hit return. Now compile and install:

make
make install
echo "extension=ffmpeg.so" > /etc/php.d/ffmpeg.ini
service httpd restart

CentOS: Install PHP 5.2 with t1lib support

The first step is to vanilla install PHP 5.2 (to handle any dependency issues) and then recompile it with the t1lib option. So enable the testing repo of CentOS 5. Change to root user first, then create the repo:

su -
vi /etc/yum.repos.d/CentOS-Testing.repo

Enter insert mode (hit i) and paste the following into the new file:

# CentOS-Testing:
# !!!! CAUTION !!!!
# This repository is a proving grounds for packages on their way to CentOSPlus and CentOS Extras.
# They may or may not replace core CentOS packages, and are not guaranteed to function properly.
# These packages build and install, but are waiting for feedback from testers as to
# functionality and stability. Packages in this repository will come and go during the
# development period, so it should not be left enabled or used on production systems without due
# consideration.
[c5-testing]
name=CentOS-5 Testing
baseurl=http://dev.centos.org/centos/$releasever/testing/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://dev.centos.org/centos/RPM-GPG-KEY-CentOS-testing
includepkgs=php*

Then update PHP and restart Apache (yum will double-check you want to go ahead):

yum update php*
service httpd restart

PHP is now updated, but the t1lib is not installed or compiled into PHP. So let’s download and install it (you’ll need make and gcc installed):

cd ~admin/software
wget ftp://sunsite.unc.edu/pub/Linux/libs/graphics/t1lib-5.1.2.tar.gz
tar zxfv t1lib-5.1.2.tar.gz
cd t1lib-5.1.2
./configure
make && make install

If it exits with a latex error, install latex:

yum -y install tetex-latex

Installing t1lib can also be accomplished if you have the rpmforge repo installed (see previous post step 6) with: yum --enablerepo=rpmforge install t1lib
If you upgrade your software in the future and get an error about libt1.so.5()(64bit) then install t1lib again using this method and then service httpd restart

Then run the make commands again. T1lib is now installed. Next step is to recompile PHP. Firstly, set up a build environment (still as root) and install some software that we’ll need to compile:

mkdir -p /usr/src/redhat/{SRPMS,RPMS,SPECS,BUILD,SOURCES}
chmod 777 /usr/src/redhat/{SRPMS,RPMS,SPECS,BUILD,SOURCES}
yum -y install rpm-build re2c bison flex

Now, we need to lose our root privileges to compile the software, so we need to run exit or logout to drop back to the admin user (make sure this is the right version of PHP you have just installed, use rpm -q php to check).

exit
cd ~admin/software
wget http://dev.centos.org/centos/5/testing/SRPMS/php-5.2.10-1.el5.centos.src.rpm
rpm --install php-5.2.10-1.el5.centos.src.rpm
vi /usr/src/redhat/SPECS/php.spec

Technically, we should edit the release line to reflect the changes we are making, but that creates dependency issues, so we’ll ignore that and edit the configure lines. Scroll to where is says %configure with various includes after the line. Remove the line that says --disable-rpath \ which will stop the compile working (this is PHP bug #48172) and add at the end: --with-t1lib \

Exit insert mode, save and exit (hit Esc, then ZZ). Now rebuild the RPM files:

rpmbuild -bb /usr/src/redhat/SPECS/php.spec

It’s highly likely that you will now get a list of failed dependencies. All of them need to be installed. The following is my list – yours may be different. Su to the root user and install them, then logout back to the admin user after this command:

su -
yum -y --skip-broken install bzip2-devel curl-devel db4-devel expat-devel gmp-devel aspell-devel httpd-devel libjpeg-devel libpng-devel pam-devel libstdc++-devel sqlite-devel pcre-devel readline-devel libtool gcc-c++ libc-client-devel cyrus-sasl-devel openldap-devel postgresql-devel unixODBC-devel libxml2-devel net-snmp-devel libxslt-devel libxml2-devel ncurses-devel gd-devel freetype-devel
exit

Then run the rpmbuild command again. If you get a GD error after the T1_StrError line, try running this command as root:

su -
ldconfig /usr/local/lib
exit

Run the rpmbuild command again (as non-root). When it finishes (will take a while), install the resultant RPM files as root user:

su -
cd /usr/src/redhat/RPMS/x86_64/
rpm -Uhv --nodeps --force *.rpm
service httpd restart
exit

Your path to the RPMs may be different depending on your architecture.

Secure new CentOs install

Step 1: Secure SSH

Log in as root to your server and type the following commands to backup and then edit the SSH configuration:

cp /etc/ssh/ssh_config /etc/ssh/ssh_config.bak; cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
vi /etc/ssh/ssh_config

Hit the i key to enter insert mode. Then uncomment all the lines after (and including) Host * (i.e. remove the hashes) and change Protocol 2,1 to 2 only. Hit Esc to exit insert mode and type ZZ to quit saving the changes. Then type the following command:

vi /etc/ssh/sshd_config

As before, in insert mode, uncomment the Port, Protocol (and change to 2 only if not already) and ListenAddress 0.0.0.0 statements. Also uncomment and change PermitRootLogin to: no. Quit and save (Esc, ZZ). Then restart the SSH service:

service sshd restart

Since we have now prevented the root user from logging in remotely (as a security measure – the root user has full access to the entire system and can break things very easily), the final step is to create a user who can log in remotely. Type in:

useradd -g wheel admin
passwd admin

Next time when you log in you can switch to the root user using the following command (enter the root password at the prompt):

su -

Step 2: Install ChkRootKit (rootkit finder)

Create a directory to hold downloaded or compiled sofware, then install some tools we will need (these may well already be installed):

mkdir -p ~admin/software
cd ~admin/software
yum -y install gcc make wget vixie-cron perl

Download and install ChkRootKit:

wget ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz
tar zxfv chkrootkit.tar.gz
cd chkrootkit-*
make sense

Then add a cron entry to run the script automatically (this is still done as the root user):

crontab -e

Tell it to run every day at 3am and email you the errors – add the following line (use the same commands as when using vim above):

0 3 * * * /home/admin/software/chkrootkit-*/chkrootkit -q 2>&1 | mail -s "ChkRootKit Output from `hostname`" your@email.com

You could do that bit of editing entirely on the command line by creating a temporary file and then adding that to the crontab like this:

touch crontab_temp
crontab -l > crontab_temp
echo "0 3 * * * /home/admin/software/chkrootkit-*/chkrootkit -q 2>&1 | mail -s \"ChkRootKit Output from \`hostname\`\" your@email.com" >> crontab_temp
cat crontab_temp | crontab
rm -f crontab_temp

Step 3: Install Portsentry (check for people sniffing/scanning your ports and block them)

cd ~admin/software

32-bit version – use this if your OS is 32-bit – download and install the existing package:

wget ftp://ftp.pbone.net/mirror/ftp.falsehope.net/home/tengel/centos/4/te/i386/RPMS/portsentry-1.2-1.te.i386.rpm
rpm -Uhv portsentry-1.2-1.te.i386.rpm
/etc/rc.d/init.d/portsentry start
echo "/etc/rc.d/init.d/portsentry" >> /etc/rc.d/rc.local

64-bit version – use this if your OS is 64-bit – we need to compile the original program, but there is an error in one of the files we need to fix first:

wget http://downloads.sourceforge.net/project/sentrytools/portsentry%201.x/portsentry-1.2/portsentry-1.2.tar.gz
tar zxfv portsentry-1.2.tar.gz
cd portsentry_beta
vi portsentry.c

The error is on line 1584 and will prevent the program from compiling. To see line numbers, type in :set number
Find line 1584 and remove the line break in the middle of that sentence. Then install:

make linux
make install

Next we need to create a script to control the service:

vi /etc/init.d/portsentry

Start insert mode and paste this all this into the file (careful of linebreaks – then save and quit):

#!/bin/bash

case "$1" in
start)
echo "Starting Portsentry..."
ps ax | grep -iw '/usr/local/psionic/portsentry/portsentry -atcp' | grep -iv 'grep' > /dev/null
if [ $? != 0 ]; then
/usr/local/psionic/portsentry/portsentry -atcp
fi
ps ax | grep -iw '/usr/local/psionic/portsentry/portsentry -audp' | grep -iv 'grep' > /dev/null
if [ $? != 0 ]; then
/usr/local/psionic/portsentry/portsentry -audp
fi
echo "Portsentry is now up and running!"
;;
stop)
echo "Shutting down Portsentry..."
array=(`ps ax | grep -iw '/usr/local/psionic/portsentry/portsentry' | grep -iv 'grep' \
| awk '{print $1}' | cut -f1 -d/ | tr '\n' ' '`)
element_count=${#array[@]}
index=0
while [ "$index" -lt "$element_count" ]
do
kill -9 ${array[$index]}
let "index = $index + 1"
done
echo "Portsentry stopped!"
;;
restart)
$0 stop && sleep 3
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit 0

Then we need to make that script executable, add portsentry to the startup scripts and start it up:

chmod 755 /etc/init.d/portsentry
ln -s /etc/init.d/portsentry /etc/rc2.d/S20portsentry
ln -s /etc/init.d/portsentry /etc/rc3.d/S20portsentry
ln -s /etc/init.d/portsentry /etc/rc4.d/S20portsentry
ln -s /etc/init.d/portsentry /etc/rc5.d/S20portsentry
ln -s /etc/init.d/portsentry /etc/rc0.d/K20portsentry
ln -s /etc/init.d/portsentry /etc/rc1.d/K20portsentry
ln -s /etc/init.d/portsentry /etc/rc6.d/K20portsentry
/etc/init.d/portsentry start

Step 4: Install LibSafe (prevents buffer overflow exploits)

cd ~admin/software

Download for 32-bit:

wget http://pubs.research.avayalabs.com/src/libsafe-2.0-16.i386.rpm

Or for 64-bit:

wget ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/extras/3/x86_64/libsafe-2.0-16.fdr.1.rh80.x86_64.rpm

Then install:

rpm -Uhv libsafe-2.0-16*.rpm

Step 5: Install Hogwash (inline packet scrubber)

Download, install and configure Hogwash:

cd ~admin/software
wget http://hogwash.sourceforge.net/devel-0.5-latest.tgz
tar zxfv devel-0.5-latest.tgz
cd distro/devel-0.5/devel-0.5
./configure
make
cp hogwash /sbin
mkdir /var/log/hogwash
mkdir /etc/hogwash
cd rules
cp *.rules /etc/hogwash
cd ..
cp *.config /etc/hogwash
cp /etc/hogwash/stock.config /etc/hogwash/live.config

We need to create another control script, but we can do this on the command line:

touch Hog
echo '#!/bin/sh' >> Hog # needs single quotes
echo "#chkconfig: 2345 11 89" >> Hog
echo "#description: Automates Hogwash packet filter" >> Hog
echo "/sbin/hogwash -d -c /etc/hogwash/live.config -r /etc/hogwash/live.rules -l /var/log/hogwash" >> Hog
chmod 700 Hog

Make sure it starts at boot time:

cp Hog /etc/rc.d/init.d
chkconfig --add Hog

Step 6: Install DenyHosts (blocks brute force login attempts)

cd ~admin/software

Install the RPMForge repo – for 32-bit:

wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.1-1.el5.rf.i386.rpm

Or for 64-bit:

wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.1-1.el5.rf.x86_64.rpm

Install, configure and make sure your own address is not blocked (substitute your IP address in the code below)

rpm -i rpmforge-release-0.5.1-1.el5.rf.*.rpm
yum check-update
yum -y install denyhosts
echo "sshd: 11.22.33.44" >> /etc/hosts.allow
perl -pi -e "s/PURGE_DENY =/PURGE_DENY = 7d/g;" /etc/denyhosts/denyhosts.cfg
chkconfig denyhosts on
service denyhosts start

Step 7: Install RootKit Hunter (yes, another one)

Download and configure RkHunter, then set up the cronjob to execute automatically (as above) and email you if there are warnings:

yum -y install rkhunter
cd ~admin/software
perl -pi -e "s/MAIL-ON-WARNING=\"\"/MAIL-ON-WARNING=\"your\@email.com\"/g;" /etc/rkhunter.conf
touch crontab_temp
crontab -l > crontab_temp
echo "0 4 * * * /usr/bin/rkhunter --cronjob 2>&1" >> crontab_temp
echo "@monthly /usr/bin/rkhunter --update" >> crontab_temp
cat crontab_temp | crontab
rm -f crontab_temp