Category Archives: Shell Scripting

A hacked together bash script to scan for heartbleed vulnerable services

Here’s a script to scan networks to look for services vulnerable to the heartbleed OpenSSL bug. It uses NMAP to scan for pingable hosts and obtain a list of network ports open and then uses the hb_test.py script to check if they’re vulnerable.

Grab the hb_test.py script here.

Edit the network variable in the script to change the list of networks to scan.

#!/bin/bash

# This is the string we're looking for in the python script output
pattern="server is vulnerable"

#Networks to scan
network="192.168.0.0/24 192.168.1.0/24"

echo -ne "Scanning network(s) $network                                                 \r"

#Use NMAP to find the IPs that ping in the networks listed
network_ips=(`nmap -n -sn -PE $network | grep "Nmap scan" | awk {'print $5'} | awk 1 ORS=' '`)

for ip in "${network_ips[@]}"
do
        echo -ne "NMAP port scan on $ip                                              \r"
		# Get a list of open ports on the IP address
        ports=(`nmap  -sT $ip | grep open | awk '{print $1}' | awk -F '/' '{print $1}' | awk 1 ORS=' '`)
        rc=$?
        if [[ $rc -eq 0 ]] ; then
                for p in "${ports[@]}"
                do
                        echo -ne "Scanning $ip on port $p                            \r"
						# If the port is 25 then let's try STARTTLS
                        if [[ $p -eq 25 ]] ; then
                                echo -ne "Scanning $ip on port $p (smtp)             \r"
                                output=`timeout 1 python ./hb_test.py $ip -s -p $p 2>&1`
                        else
								# Otherwise just do normal SSL
                                output=`timeout 1 python ./hb_test.py $ip -p $p 2>&1`
                        fi
						# Check if the text output matched
                        if [ "x" != "x`echo $output | grep "$pattern"`" ]; then
                                echo "$ip - port $p - VULNERABLE"
                        fi
                done
        fi
done

 

Tagged ,

Mimicking a multi-stage update server for RHEL servers on Classic

One of Redhat Satellite’s functions is update release management. Unfortunately it also quite expensive. If you have classic you can mimic the update features (albeit not the security updates) through some scripting.

This solution uses a server which is registered with Redhat with a Classic subscription so it’s not quite free. The server is able to reposync all the updates for its architecture and major release version (e.g. RHEL 5 x86_64).

1. Register the server you want to use as the reposync server on Redhat Classic and assign the correct channel.

2. Using the following command to create a new repo:

reposync -p /mypath/mirror/ --repoid=rhel-x86_64-server-5 -l -n

This syncs the whole of Redhat’s rhel-x86_64-server-5 repository to the /mypath/mymirror folder. You can change these paths and repoid to however you please. The -n switch means that only the newest files are synced each run so you can schedule this in your crontab to run regularly.

3. Now you want to create a point in time snapshot of all the updates contained in the mirror at that point in time. To do that you can use lndir. Here is my rhn_create_snapshot.sh script:

#!/bin/sh

baseRepoPath=/mypath

function usage()
{
 echo "This script creates a new snapshot folder for yum updates"
 echo
 echo "rhn-create-snapshot.sh MYGROUP"
 echo "-h --help Show this help"
 echo "--environment=MYGROUP Set the environment to create the repo for"
 echo
}
while [ "$1" != "" ]; do
 PARAM=`echo $1 | awk -F= '{print $1}'`
 VALUE=`echo $1 | awk -F= '{print $2}'`
 case $PARAM in
 -h | --help)
 usage
 exit
 ;;
 --environment)
 currEnvironment=$VALUE
 ;;
 *)
 echo "ERROR: unknown parameter \"$PARAM\""
 usage
 exit 1
 ;;
 esac
 shift
done
if [ "$currEnvironment" == "" ]; then
 echo "Environment not set properly. Exiting."
 usage
 exit 1
fi
currDate=$(date +%Y%m%d-%k%m)

echo "Creating yum snapshot for environment $currEnvironment in $baseRepoPath/snapshots/rhel-x86_64-server-5/$currDate/packages"

echo "Creating new folder for the snapshot to go in"
mkdir -p $baseRepoPath/snapshots/rhel-x86_64-server-5/$currDate/packages

echo "Creating new folder for the repodata to go in"
mkdir -p $baseRepoPath/snapshots/rhel-x86_64-server-5/$currDate/repodata

echo "Creating a directory of links in the snapshot folder"
lndir $baseRepoPath/mirror/rhel-x86_64-server-5/getPackage/ $baseRepoPath/snapshots/rhel-x86_64-server-5/$currDate/packages

echo "Creating a repo for the client to read"
createrepo $baseRepoPath/snapshots/rhel-x86_64-server-5/$currDate

echo "Creating a link for the client to the snapshot directory"
if [ -e $baseRepoPath/updates/$currEnvironment ]; then
 rm -f $baseRepoPath/updates/$currEnvironment
fi

ln -s $baseRepoPath/snapshots/rhel-x86_64-server-5/$currDate $baseRepoPath/updates/$currEnvironment

echo "All done"
echo "Please use the following yum config in your yum.conf:"
echo
echo "[update]"
echo "gpgcheck=0"
echo "name=Red Hat Linux Updates"
echo "baseurl=http://<servername>/updates/$currEnvironment"
echo

If you run

sh ./rhn_create_snapshot.sh MYGROUP

it creates a folder structure like this:

mypath
       mirror
             rhel-x86_64-server-5
                    getPackage
                            <list of reposync'd packages>
       updates
            MYGROUP -> /mypath/snapshots/rhel-x86_64-server-5/2013-12-11-1104
       snapshots
            rhel-x86_64-server-5
                    2013-12-11-1104
                            packages
                                   <directory of symbolic links to /mypath/mirror/rhel-x86_64-server-5/getPackage/<filename>
                            repodata

Each time the rhn_create_snapshot.sh script is run is creates a new dated snapshot directory under /mypath/snapshots/rhel-x86_64-server-5 containing a packages folder with a directory full of symbolic links of the files that were in /mypath/mirror/rhel-x86_64-server-5/getPackage at the time it was run. A repo is then created on this list of files. The only space the snapshot takes up is for the repodata files, which is about 200MB in size.

So now you can roll patches through groups of servers by setting the baseurl in their yum.conf to point to different updates/MYGROUP. For example:

TEST -> /mypath/snapshots/rhel-x86_64-server-5/2013-12-11-1104
UAT -> /mypath/snapshots/rhel-x86_64-server-5/2013-09-11-1001
PROD -> /mypath/snapshots/rhel-x86_64-server-5/2013-17-05-1630

The PROD group could be getting a different set of packages when yum update is run than UAT or LIVE. All you need to do to release TEST packages to UAT is to change the symbolic link. Using the above example:

rm -f /mypath/updates/UAT
ln -s /mypath/snapshots/rhel-x86_64-server-5/2013-12-11-1104 /mypath/updates/UAT

which now gives:

TEST -> /mypath/snapshots/rhel-x86_64-server-5/2013-12-11-1104
UAT -> /mypath/snapshots/rhel-x86_64-server-5/2013-12-11-1104
PROD -> /mypath/snapshots/rhel-x86_64-server-5/2013-17-05-1630

Now going to UAT machine and running yum update should list new updates. You could no doubt script that if you wanted.

Tagged , , , , , ,

Simple btrfs snapshot script

I bought a Raspberry Pi sometime ago and have been using it as my backup device via a USB disk. My other machines use rsync to backup their data to the pi’s /mnt/backupdisk. Instead of running backups to the same disk I decided to use BTRFS and snapshotting. I looked around for a script to do this for me in the same way as time machine, back in time or rsnapshot would do but couldn’t find any. So I’ve written a simple script.

What it does:

  • Creates a primary snapshot every hour which is overwritten every day
  • Creates a primary snapshot every day which is overwritten a week later
  • Creates a primary snapshot on the 1st of the month which is overwritten a year later
  • Create a primary snapshot on the 1st January every year which is kept forever

I guess you’ll be thinking that this could end up chewing up disk space as I’ll be keeping very old snapshots. Whether you want to do that is up to you. I have plenty of disk space and my data doesn’t change all that often.

The script:

#!/bin/bash
if [ $# -eq 0 ]
 then
 echo "Syntax: btrfs_snap.sh Hourly|Daily|Weekly|Monthly|Yearly|list"
fi
# Hourly Snaps (24)
if [ "$1" == "Hourly" ]
 then
 /sbin/btrfs subvolume delete /mnt/backupdisk/.snapshot/Hourly-$(date +%H)
 /sbin/btrfs subvolume snapshot /mnt/backupdisk/ /mnt/backupdisk/.snapshot/Hourly-$(date +%H)
fi
#Daily Snaps (7)
if [ "$1" == "Daily" ]
 then
 /sbin/btrfs subvolume delete /mnt/backupdisk/.snapshot/Daily-$(date +%a)
 /sbin/btrfs subvolume snapshot /mnt/backupdisk/ /mnt/backupdisk/.snapshot/Daily-$(date +%a)
fi
#Weekly Snaps (52)
if [ "$1" == "Weekly" ]
 then
 /sbin/btrfs subvolume delete /mnt/backupdisk/.snapshot/Weekly-$(date +%V)
 /sbin/btrfs subvolume snapshot /mnt/backupdisk/ /mnt/backupdisk/.snapshot/Weekly-$(date +%V)
fi
#Yearly Snaps (1 per year)
if [ "$1" == "Yearly" ]
 then
 /sbin/btrfs subvolume delete /mnt/backupdisk/.snapshot/Yearly-$(date +%Y)
 /sbin/btrfs subvolume snapshot /mnt/backupdisk/ /mnt/backupdisk/.snapshot/Yearly-$(date +%Y)
fi
#List Snaps
if [ "$1" == "list" ]
 then
 /sbin/btrfs subvolume list /mnt/backupdisk/
fi

Also you’ll want to schedule it in root’s crontab:

sudo crontab -e
#BTRFS snaps of /mnt/backupdisk--------------------------------------------------
0 * * * * /bin/bash /scripts/btrfs_snap.sh Hourly 2>&1 >> /var/log/btrfs_snap.log
5 0 * * * /bin/bash /scripts/btrfs_snap.sh Daily 2>&1 >> /var/log/btrfs_snap.log
10 0 * * 0 /bin/bash /scripts/btrfs_snap.sh Weekly 2>&1 >> /var/log/btrfs_snap.log
15 0 1 * * /bin/bash /scripts/btrfs_snap.sh Monthly 2>&1 >> /var/log/btrfs_snap.log
20 0 1 1 * /bin/bash /scripts/btrfs_snap.sh Yearly 2>&1 >> /var/log/btrfs_snap.log
#-------------------------------------------------------------------------------

It logs to /var/log/btrfs_snap.log.

The snapshots are fully writable and can be found under /mnt/backupdisk/.snapshot/

You can check your snapshots using

# sudo /scripts/btrfs_snap.sh list
ID 415 top level 5 path .snapshot/Hourly-20
ID 416 top level 5 path .snapshot/Hourly-21
ID 417 top level 5 path .snapshot/Hourly-22
ID 418 top level 5 path .snapshot/Hourly-23
ID 419 top level 5 path .snapshot/Hourly-00
ID 420 top level 5 path .snapshot/Daily-Mon
ID 421 top level 5 path .snapshot/Hourly-01
ID 422 top level 5 path .snapshot/Hourly-02
ID 423 top level 5 path .snapshot/Hourly-03
ID 424 top level 5 path .snapshot/Hourly-04
ID 425 top level 5 path .snapshot/Hourly-05
ID 426 top level 5 path .snapshot/Hourly-06
ID 427 top level 5 path .snapshot/Hourly-07
ID 428 top level 5 path .snapshot/Hourly-08
ID 429 top level 5 path .snapshot/Hourly-09
Tagged ,