Author Topic: Using Dynamic DNS to evade SSH bruteforce attacks  (Read 9341 times)

0 Members and 3 Guests are viewing this topic.

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Using Dynamic DNS to evade SSH bruteforce attacks
« 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
  • Block ALL incoming (at least) SSH connections with your firewall.
  • Add an exception rule for incoming SSH connections for any address on the goodguys table.
  • Make a Dynamic DNS hostname (e.g. no-ip.com) for each trusted mobile computer.
  • Install a Dynamic Update Client on each trusted mobile computer.
  • Add a cron job (every 5 minutes) that resolves a list of dynamic hostnames and adds their corresponding IPs to the goodguys table (preferably deleting old different resolutions).
  • Enjoy boiled peanuts (Very necessary, it won't work otherwise).

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)
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
  • It may take several minutes before you can ssh to your server.
  • If your dynamic hostname expires, said hostname may resolve to the dynamic DNS provider.
« Last Edit: July 23, 2010, 01:50:06 am by nslay »
An adorable giant isopod!

Offline Blaze

  • x86
  • Hero Member
  • *****
  • Posts: 7136
  • Canadian
    • View Profile
    • Maide
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #1 on: June 17, 2010, 05:11:00 pm »
Would disabling passwords in general and using private/public keys exclusively be a solution to this?
And like a fool I believed myself, and thought I was somebody else...

Offline Sidoh

  • x86
  • Hero Member
  • *****
  • Posts: 17634
  • MHNATY ~~~~~
    • View Profile
    • sidoh
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #2 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. :)

Offline Newby

  • x86
  • Hero Member
  • *****
  • Posts: 10877
  • Thrash!
    • View Profile
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #3 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.)
- Newby
http://www.x86labs.org

Quote
[17:32:45] * xar sets mode: -oooooooooo algorithm ban chris cipher newby stdio TehUser tnarongi|away vursed warz
[17:32:54] * xar sets mode: +o newby
[17:32:58] <xar> new rule
[17:33:02] <xar> me and newby rule all

I'd bet that you're currently bloated like a water ballon on a hot summer's day.

That analogy doesn't even make sense.  Why would a water balloon be especially bloated on a hot summer's day? For your sake, I hope there wasn't too much logic testing on your LSAT. 

Offline Blaze

  • x86
  • Hero Member
  • *****
  • Posts: 7136
  • Canadian
    • View Profile
    • Maide
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #4 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.  :)
And like a fool I believed myself, and thought I was somebody else...

Offline Blaze

  • x86
  • Hero Member
  • *****
  • Posts: 7136
  • Canadian
    • View Profile
    • Maide
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #5 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?  :)
And like a fool I believed myself, and thought I was somebody else...

Offline rabbit

  • x86
  • Hero Member
  • *****
  • Posts: 8092
  • I speak for the entire clan (except Joe)
    • View Profile
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #6 on: June 17, 2010, 06:40:26 pm »
Couldn't you just whitelist certain MAC addresses?

Offline Blaze

  • x86
  • Hero Member
  • *****
  • Posts: 7136
  • Canadian
    • View Profile
    • Maide
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #7 on: June 17, 2010, 07:02:09 pm »
Couldn't you just whitelist certain MAC addresses?

No..
And like a fool I believed myself, and thought I was somebody else...

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #8 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 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.
  • Block everyone (this topic).
  • Temporarily (hourly) block source IPs spuriously connecting to sshd (pf(4) keyword max-src-conn-rate).
  • synproxy a pf(4) keyword used in conjunction with pass in rules that has the firewall complete the TCP/IP handshake on behalf of the host process and network stack.
An adorable giant isopod!

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #9 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.
An adorable giant isopod!


Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Hello from Ben Gurion International Airport, Israel!
« Reply #11 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.
An adorable giant isopod!

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Re: Using Dynamic DNS to evade SSH bruteforce attacks
« Reply #12 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.
« Last Edit: July 25, 2010, 04:53:38 pm by nslay »
An adorable giant isopod!