Clan x86

Technical (Development, Security, etc.) => General Security Information => Topic started by: nslay on June 17, 2010, 04:43:15 pm

Title: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: nslay on June 17, 2010, 04:43:15 pm
I used to employ a firewall rule that would detect spurious connects on port 22 (ssh) and place both the offending IP on a badguys table and flush the state table for said IP (Meaning, anything connected with that source IP was no longer treated as connected by the firewall).  A cron job would then cleanup old entries from the badguys table.  For years, this worked remarkably!  My auth log would show 3 attempts and then activity from the source ceased.  Unfortunately, the bot nets got smarter.  I started seeing several hundreds of bots attempting a password every several minutes which isn't spurious.  As a consequence, my auth log would be flooded with annoying password failures!  So, I opted to block everything except address blocks of known locations (e.g. cafe, work, school, etc...) on top of the spurious connect rule.  This works well most of the time but did not fare so well with friends' or acquaintances' houses, airports, or new public WiFi locations in general (which I use my SSH server as a secure tunnel).  As I'm to travel soon, the thought of dynamic DNS came to mind.  Simply keep a list of dynamic domains and have a cron job resolve each one and add it to the goodguys table (and delete the previous resolutions if they differ).  I don't claim it's a new idea, but it's certainly ANOTHER solution.

Too Long Didn't Read

Here's an example of a Bourne shell script to do step 5 (for pf(4) on FreeBSD) (an updated version can be found here (http://forum.x86labs.org/index.php/topic,15313.msg187121.html#msg187121))
Code: [Select]
#!/bin/sh

GOODGUYS=/root/goodguys.txt
TABLE=goodguys

while read host
do
        hostfile="/tmp/goodguys.${host}"
        oldip=""

        if [ -s "${hostfile}" ]
        then
                read oldip < ${hostfile}
        fi

        str=`host -t A $host 2>/dev/null`
        if [ $? -eq 0 ]
        then
                ip=`echo "${str}" | awk '{ print $NF; exit }'`
                echo "${ip}" > ${hostfile}
        else
                ip=""
                rm -f ${hostfile}
        fi

        if [ -n "${oldip}" -a "${oldip}" != "${ip}" ]
        then
                /sbin/pfctl -t $TABLE -T del ${oldip} > /dev/null 2>&1
        fi

        if [ -n "${ip}" ]
        then
                /sbin/pfctl -t $TABLE -T add ${ip} > /dev/null 2>&1
        fi
done < $GOODGUYS

This reads a list of hostnames from /root/goodguys.txt and adds each resolved address to the table goodguys and stores the result in /tmp for later use. If the previous address is different than the current resolved address, the previous address is deleted from the goodguys table.

Place it in, say /root/bin/goodguys.sh

And here's what you'd add to /etc/crontab to do this every 5 minutes:
Code: [Select]
#minute hour    mday    month   wday    who     command
*/5     *       *       *       *       root    /root/bin/goodguys.sh

Voila! I find this to be the best solution of all the bruteforce solutions. Everyone is blocked except for you and friends ... granted you and your friends are using their own machines. No special software or firewall rules needed and most importantly NO ANNOYING AUTH LOG FAILURE MESSAGES!

Caveats
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: Blaze on June 17, 2010, 05:11:00 pm
Would disabling passwords in general and using private/public keys exclusively be a solution to this?
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: Sidoh on June 17, 2010, 05:33:26 pm
Cool!  I like this, nslay.  thanks for sharing.

Blaze, I'm not really sure why it's desirable, but I don't think you'd avoid having your auth logs flooded with that solution.  I certainly do that, though.  I like keys more anyway. :)
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: Newby on June 17, 2010, 05:40:11 pm
So basically a whitelist instead of a blacklist? Good idea, I suppose. I'd rather just do the IPs. What if your machine becomes compromised and resolves those domains to something wrong? Or the DynDNS account is compromised and bad IPs are added? (Granted, it would require that the attacker know about your setup, but it's something to consider. At the very least it would result in a DoS for legitimate users.)
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: Blaze on June 17, 2010, 05:40:23 pm
I'm not too worried about keeping pretty auth logs, I was just asking since I almost never look at my auth logs, and wanted to make sure that I'm probably fine doing what I'm doing.  :)

I also enjoyed the article, nslay.  Do post more if have spare time and have come up with cool solutions to stuff.  :)
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: Blaze on June 17, 2010, 05:42:56 pm
So basically a whitelist instead of a blacklist? Good idea, I suppose. I'd rather just do the IPs. What if your machine becomes compromised and resolves those domains to something wrong? Or the DynDNS account is compromised and bad IPs are added? (Granted, it would require that the attacker know about your setup, but it's something to consider. At the very least it would result in a DoS for legitimate users.)

The problem with just doing IPs is dynamicness.  The DynDNS is a solution that already exists for dynamic addresses, and is a smart solution to the problem.

It's unlikely that your DynDNS account is going to be targeted, unless you draw attention to it.

On your point of 'What happens if your machine becomes compromised', I would imagine it's already too late?  :)
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: rabbit on June 17, 2010, 06:40:26 pm
Couldn't you just whitelist certain MAC addresses?
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: Blaze on June 17, 2010, 07:02:09 pm
Couldn't you just whitelist certain MAC addresses?

No..
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: nslay on June 17, 2010, 07:52:41 pm
Would disabling passwords in general and using private/public keys exclusively be a solution to this?
I don't know if that would suppress annoying failure messages.  If it does, then that could work.  However, having the firewall protect sshd is desirable especially since sshd is a privileged process.  OpenSSL (which is used by OpenSSH) has had vulnerabilities (http://security.freebsd.org/advisories/FreeBSD-SA-09:08.openssl.asc) in the past pertaining to processing certificates (which is related to public/private keys in ssh).  I'm not sure to what extent an attacker could exploit that particular vulnerability, but it suggests that it may be possible to compromise a system by carefully crafting public/private keys (or any other aspect of the ssh protocol or cryptographic encoding/decoding rules).

In particular, I have three layers of defense from the firewall.
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: nslay on June 17, 2010, 08:05:01 pm
So basically a whitelist instead of a blacklist? Good idea, I suppose. I'd rather just do the IPs. What if your machine becomes compromised and resolves those domains to something wrong? Or the DynDNS account is compromised and bad IPs are added? (Granted, it would require that the attacker know about your setup, but it's something to consider. At the very least it would result in a DoS for legitimate users.)

Then the attacker hits another obstacle, like the firewall temporarily blocking source IPs that are spuriously connecting (max-src-conn-rate in pf(4) ... 3 connects per 30 within seconds is definitely spurious).
Bruteforce isn't a real security hazard in my opinion ... it would take years (considering network latency) to even fully bruteforce an 8 character password.  The problem is this floods your auth log with failure messages.  Many flavors of Unix keep /var as a separate (and small) file system.  Bruteforcers can easily cause the auth log to roll over several times a day eventually causing /var to be full (on top of you having hundreds upon hundreds of rolled over auth log files).  /var is where log files, mail, and some application settings (like named(8)) are stored and if it's full, it can cause problems. Most of these bruteforcers are just trying a dictionary of users and passwords ... it's just wasteful to log.

Of course, this all assumes the attacker knows which of the several dynamic DNS providers you use as well as your setup.
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: nslay on June 17, 2010, 08:15:33 pm
Other SSH/OpenSSL vulnerabilities:
http://security.freebsd.org/advisories/FreeBSD-SA-09:15.ssl.asc
http://security.freebsd.org/advisories/FreeBSD-SA-09:02.openssl.asc
http://security.freebsd.org/advisories/FreeBSD-SA-08:05.openssh.asc
http://security.freebsd.org/advisories/FreeBSD-SA-07:08.openssl.asc
http://security.freebsd.org/advisories/FreeBSD-SA-06:22.openssh.asc
http://security.freebsd.org/advisories/FreeBSD-SA-06:23.openssl.asc

And more listed here (http://www.freebsd.org/security/advisories.html).  Not all of the above are relevant to ssh (though some are).  The point is, you really should protect or isolate sshd.
Title: Hello from Ben Gurion International Airport, Israel!
Post by: nslay on June 19, 2010, 08:38:05 am
Hello hello hello *echos can be heard in the SSH tunnel*

This solution works swell!

Although, there are some unforeseen bugs in my cron script.  Namely, if multiple friends are using your ssh server from the same source IP and one leaves and logs in from elsewhere, then you may experience brief interruption since the cron script will delete the previous IP from the table possibly adding it later (or not at all if your friend was processed last!).

To fix it, you'll need to maintain a temporary list of IPs to delete and add.  These lists should be mutually exclusive with priority on additions (i.e. IPs to add should be deleted from the delete list).  After these lists are prepared, then you do the table deletions and additions.

I'll fix the script when I get a chance ... unless someone else wants to fix it.
Title: Re: Using Dynamic DNS to evade SSH bruteforce attacks
Post by: nslay on July 23, 2010, 01:48:03 am
Alright, I fixed the bug.  This script will only delete an IP address from the specified table if it does not occur in the add list.  This takes care of the situation when two or more friends initially have dynamic domains that resolve to the same IP address.  The old script would delete the IP from the table if one of the dynamic domains changed potentially causing everyone else with said IP to wait for the script to re-add them to the table.

I also attempted to make it easier for the script to work with other firewalls.  Just modify the functions addhosts() and delhosts() to invoke the firewall-specific commands.

Code: [Select]
#!/bin/sh

# List of dynamic hostnames
LIST="/var/db/goodguys.hosts"

# Firewall table to manipulate
TABLE="goodguys"

# Modify this to add a list of ips to $TABLE for your firewall
addhosts() {
        /sbin/pfctl -t $TABLE -T add $@
        return $?
}

# Modify this to delete a list of ips from $TABLE for your firewall
delhosts() {
        /sbin/pfctl -t $TABLE -T del $@
        return $?
}

addlist=""
dellist=""

while read hostname
do
        hostfile="/tmp/.goodguys.${hostname}"
        oldip=""
        ip=""

        if [ -f "${hostfile}" ]
        then
                read oldip < $hostfile
        fi

        str=`host -t A ${hostname} 2>/dev/null`

        if [ $? -eq 0 ]
        then
                ip=`echo "$str" | awk '{ print $NF; exit }'`
        fi

        if [ "${ip}" != "${oldip}" ]
        then
                dellist="${dellist} ${oldip}"

                echo "${ip}" > $hostfile

                [ -z "${ip}" ] && rm -f $hostfile
        fi

        addlist="${addlist} ${ip}"

done < $LIST

for oldip in $dellist
do
        del=1
        for ip in $addlist
        do
                if [ "${oldip}" = "${ip}" ]
                then
                        del=0
                        break
                fi
        done

        [ "${del}" -ne 0 ] && delhosts $oldip > /dev/null 2>&1
done

eval addhosts $addlist > /dev/null 2>&1

EDIT: Moved addlist assignment outside of the if block for redundant assignment.  If /tmp is not cleared at boot, the script would previously assume the IPs were already added.