OpenBSD Journal

User Stories: Page Knocking

Contributed by sean on from the notional security through obscurity dept.

bsdal found himself in a position he didn't like and came up with a solution:
In order to remove all those logs of people probing SSH, I keep PF configured to prevent access. A script looks for people accessing a specific page on the web service on the same machine. This script monitors the web logs, and when the specific page is accessed, it adds the source address to the table of addresses allowed to access port 22.

Conceptually similar to port knocking, but possibly more simple, I call this page knocking.
bsdal writes as follows:
After trying to access the SSH service from behind a rather restrictive firewall, I thought that page knocking would allow for multiplexing a port. Those address not in the privileged table get an SSL web server when accessing port 443, while those in the table get access to an SSH service when accessing port 443, via PF redirects. A quick page knock adds your address to the table, and another page knock removes the address from the table. Keeping states means that once the SSH session is established, the address may be removed from the table while maintaining the SSH session and having all others coming from the same address given the regular service on port 443.

For those interested, a more through explanation is available at http://www.otterhole.ca/knock/.
How would you approach this problem or improve on this solution?
What kinds of problems do you use OpenBSD to solve?

(Comments are closed)


Comments
  1. By Anonymous Coward (82.113.113.81) on

    nice work i searched for such a solution on openbsd.
    i used something different for a company intern router running freebsd.
    users are able to set filter rules via a php/html web interface to enable traffic to preset routes to different networks. the user www has the permission with sudo to set or delete the rules. but it needs an apache without chroot.

    Comments
    1. By Anonymous Coward (70.173.172.228) on

      > nice work i searched for such a solution on openbsd.
      > i used something different for a company intern router running freebsd.
      > users are able to set filter rules via a php/html web interface to enable traffic to preset routes to different networks. the user www has the permission with sudo to set or delete the rules. but it needs an apache without chroot.

      wouldn't '# mknod /var/www/dev/pf c 73 0' remove the need for un-chrooted apache?

  2. By Anthony (68.145.117.155) undeadly@arbitraryconstant.com on

    The whole point of port knocking is concealment, eg from an ISP that doesn't like you running servers, or whatever. I think this is of questionable merit anyway, since ISPs these days can passively figure out just about any traffic that isn't tunneled through SSH etc (and they can figure out some of that from traffic analysis). If you're already running a web server, the game is already up.

    If you don't like seeing failed login attempts from root, nobody, joe, and so on in the logs, just turn off password authentication and challenge response authentication. All that's left is publickey authentication, and the scanners don't even bother when they see that.

    Also, your box will be unreachable when something goes wrong with Apache.

    Comments
    1. By Anonymous Coward (116.240.236.47) on

      >...All that's left is publickey authentication, and the scanners don't even bother when they see that.

      Sadly this is not the case, at least with my server.

      >
      > Also, your box will be unreachable when something goes wrong with Apache.

      This is a very good point.

    2. By Martin Schröder (87.157.111.152) martin@oneiros.de on http://www.oneiros.de

      > The whole point of port knocking is concealment, eg from an ISP that

      Indeed. It's security by obscurity. Nuf said.

  3. By Matt (82.146.97.27) on

    It seems a rather long and tedious solution to a pretty straightforward problem. If you do not like your logfiles filling up (which are rotated anyway) just use pf directly to block out anyone that connects over, say 3 times within 30 seconds. I have this, which works for me:
    table <sshd_attackers> persist
    
    pass in proto tcp from any to any port ssh \
            keep state (max-src-conn-rate 3/30, \
            overload <sshd_attackers> flush global)
     block in log on $ext_if proto tcp from  to $ext_if port ssh
    

    On top of that, and VERY advisable for your solution too, I have a pool of 'friendly' ip addresses that can circumvent this rule so I never lock myself out:

    pass in on $ext_if proto tcp from $friendly_servers to $ext_if port ssh
    

    Another thing, apart from browser cache / history and the obvious 'apache down == locked out completely' problem Anthony already pointed out, is that many browsers are equipped with 'toolbars' that report their URL's to search engines (Alexa and Google being the most obvious ones). With that you possibly (depending on what the page might display) risk your system being spidered and becoming as vulnerable as before your solution.

    Comments
    1. By jkm (194.237.142.6) on

      I will try that. Right now i block SSH for Linux hosts which also blocks 98% of the SSH scans.

    2. By Anonymous Coward (212.20.215.129) on

      > table <sshd_attackers> persist
      >
      > pass in proto tcp from any to any port ssh \
      > keep state (max-src-conn-rate 3/30, \
      > overload <sshd_attackers> flush global)
      > block in log on $ext_if proto tcp from to $ext_if port ssh

      I assume you meant to have the <sshd_attackers> table between "from"
      and "to" there. Anyway, a simple `block in quick from <sshd_attackers>' (above the pass rule) is enough.

      > On top of that, and VERY advisable for your solution too, I have a
      > pool of 'friendly' ip addresses that can circumvent this rule so I
      > never lock myself out:
      >
      > pass in on $ext_if proto tcp from $friendly_servers to $ext_if port ssh

      I'd use 'quick' here.

      Comments
      1. By Matt (82.146.97.27) on

        > I assume you meant to have the <sshd_attackers> table between "from"
        > and "to" there. Anyway, a simple `block in quick from <sshd_attackers>' (above the pass rule) is enough.

        My bad!
        The undeadly html filter got the best of my <brackets>.
        I forgot to change them into html entities there.

        Which by the way proves this description:

        " Note that & must be escaped to &amp;, < to &lt; and > to &gt;, unless used within a <pre></pre> block."

        isn't quite true.

        > I'd use 'quick' here.

        Thanks, the whole rule/idea was based upon 3.7(?) rules provided in a pf mailinglist discussion and had to be changed to accomodate 4.1 on my latest server. So any improvements are more than welcome.


    3. By Justin (216.17.75.75) on

      > It seems a rather long and tedious solution to a pretty straightforward problem. If you do not like your logfiles filling up (which are rotated anyway) just use pf directly to block out anyone that connects over, say 3 times within 30 seconds. I have this, which works for me:
      >
      > table <sshd_attackers> persist
      >
      > pass in proto tcp from any to any port ssh \
      > keep state (max-src-conn-rate 3/30, \
      > overload <sshd_attackers> flush global)
      > block in log on $ext_if proto tcp from to $ext_if port ssh
      >

      I do this same thing and also add some cron entries to roots tab
      The first line gives me a list of addresses blocked so I can generate statistics about repeat offenders and optionally create rules in the future based on that analysis. The second rule removes the IP addresses from the block table.

      #clear out sshflood ips from being blocked
      0 1 * * * /sbin/pfctl -T show -t sshflood >> /root/sshflood.txt
      1 1 * * * /sbin/pfctl -T flush -t sshflood

      I have played around with the idea of setting up some server similar to DNS RBLs for these IP addresses but use it instead for more overt blocking and on a wider range of systems under my control.

      >
      > Another thing, apart from browser cache / history and the obvious 'apache down == locked out completely' problem Anthony already pointed out, is that many browsers are equipped with 'toolbars' that report their URL's to search engines (Alexa and Google being the most obvious ones). With that you possibly (depending on what the page might display) risk your system being spidered and becoming as vulnerable as before your solution.

      Protecting against search engine submissions could be to include http auth on the page knocking url. This still says nothing about the "apache down = no ssh for you" problem.

    4. By Henrik Gustafsson (gsson) on http://fnord.se/

      > It seems a rather long and tedious solution to a pretty straight-
      > forward problem. If you do not like your logfiles filling up 
      > (which are rotated anyway) just use pf directly to block out
      > anyone that connects over, say 3 times within 30 seconds. I have
      > this, which works for me:
      > 
      > table  persist
      > 
      > pass in proto tcp from any to any port ssh \
      >         keep state (max-src-conn-rate 3/30, \
      >         overload  flush global)
      >  block in log on $ext_if proto tcp from  to $ext_if port ssh
      > 
      > 
      > On top of that, and VERY advisable for your solution too, I have a
      > pool of 'friendly' ip addresses that can circumvent this rule so I
      > never lock myself out:
      > 
      
      Instead of doing this I'd advise you to just remove entries in the tables after some time of inactivity.

      Check the '-T expire' option in pfctl(8) for info how to do that.

      You might also be interested in Johan Fredins "Block ssh bruteforce attempts" and Peter N. M. Hansteens "Turning away the brutes". Last, and probably least these days, you might want to check out the "sysutils/expiretable" port and http://expiretable.fnord.se/.

      // gsson

  4. By Anonymous Coward (151.136.100.2) on

    i wander would not this improve page cache performance as well?

  5. By daco (83.211.25.130) on



    What about this solution: http://lowerca.se/2005-03-30/ ?

    Comments
    1. By jcs (75.48.205.46) on http://lowerca.se/

      > What about this solution:http://lowerca.se/2005-03-30/?

      it's not as effective anymore. libssh-0.2 is out, so the patch needs to be changed to libssh-*.

      i've still seen some brute force attacks come in even with an updated patch, though.

      i'm in favor of blocking all ssh except to a certain range of ips, or using pf's os fingerprinting and only allowing openbsd hosts through.

  6. By Charles Hill (167.20.232.130) on

    And what is wrong with running SSH on a different port?

    I had the same issue. My SSH logs were filling up with dictionary attacks, scans and a bunch of crap. So, I moved SSH to a high port and haven't had any not-supposed-to-be-there logs in over a year.

    The reality is, unless you're a specific target, most script kiddies and automated scans cover only the well-known ports. I can't remember the last time I registered a 65,535 port scan. Pick something 30000+ and odds are it'll never get scanned.


  7. By Anonymous Coward (206.248.190.11) on

    "How would you approach this problem or improve on this solution?"

    What problem? There's no problem here, just a "solution" desperately searching for a problem.

    Comments
    1. By newmember (66.11.81.65) on

      > "How would you approach this problem or improve on this solution?"
      >
      > What problem? There's no problem here, just a "solution" desperately searching for a problem.


      I have been thinking the same thing regarding my logs filling up. I was dreaming of something like spamd for port 22. It would gray list you if you have too many wrong log in attempts (lets say 4). The best part would be if the daemon would report the IP address of the offender and add them to a public "black list."
      This might have some effect over time.

      Now that I think about it, why stop on port 22, include all ports that generate failed login attempts, especially root attempts.

      Result, a few log file entries, for fun. You could still use 'knock' for a 'white list' and better put a timer on the 'white list enter' so it will expire in 5 min of the knock. Not sure if you remove the rule you would cut yourself off, or your port would close after the state on the port is dropped.

      Might be nice.


      Cheers













      Comments
      1. By William Palmer (wcpalmer) on http://wcpalmer.com

        > > "How would you approach this problem or improve on this solution?"
        > >
        > > What problem? There's no problem here, just a "solution" desperately searching for a problem.
        >
        >
        > I have been thinking the same thing regarding my logs filling up. I was dreaming of something like spamd for port 22. It would gray list you if you have too many wrong log in attempts (lets say 4). The best part would be if the daemon would report the IP address of the offender and add them to a public "black list."
        > This might have some effect over time.
        >
        > Now that I think about it, why stop on port 22, include all ports that generate failed login attempts, especially root attempts.
        >
        > Result, a few log file entries, for fun. You could still use 'knock' for a 'white list' and better put a timer on the 'white list enter' so it will expire in 5 min of the knock. Not sure if you remove the rule you would cut yourself off, or your port would close after the state on the port is dropped.
        >
        > Might be nice.
        >
        >
        > Cheers
        >
        >
        >

        I've been looking for something similar to Denyhosts (http://denyhosts.sourceforge.net/) for OpenBSD. It's basically a python script that runs via cron and parses your sshd log looking for repeated failed logins. It then adds them to /etc/hosts.deny or whatever you specify.

        I will probably write something similar to this for OpenBSD in Perl, because I'd prefer to leave sshd running on port 22.

        Comments
        1. By Anonymous Coward (70.173.172.228) on

          > > Result, a few log file entries, for fun. You could still use 'knock' for a 'white list' and better put a timer on the 'white list enter' so it will expire in 5 min of the knock. Not sure if you remove the rule you would cut yourself off, or your port would close after the state on the port is dropped.
          > >
          >
          > I will probably write something similar to this for OpenBSD in Perl, because I'd prefer to leave sshd running on port 22.
          >
          >

          the new syslog feature in 4.1 of piping log messages into another program's STDIN seems a perfect fit here.

          Comments
          1. By William Palmer (wcpalmer) on http://wcpalmer.com

            > > > Result, a few log file entries, for fun. You could still use 'knock' for a 'white list' and better put a timer on the 'white list enter' so it will expire in 5 min of the knock. Not sure if you remove the rule you would cut yourself off, or your port would close after the state on the port is dropped.
            > > >
            > >
            > > I will probably write something similar to this for OpenBSD in Perl, because I'd prefer to leave sshd running on port 22.
            > >
            > >
            >
            > the new syslog feature in 4.1 of piping log messages into another program's STDIN seems a perfect fit here.
            >

            That sounds great! Thanks for the heads up!

        2. By Lars Hansson (bysen) on

          > I've been looking for something similar to Denyhosts (http://denyhosts.sourceforge.net/) for OpenBSD.

          Say hi to max-src-conn-rate:
          http://johan.fredin.info/openbsd/block_ssh_bruteforce.html
          http://home.nuug.no/~peter/pf/en/bruteforce.html

  8. By Tyler Sable (69.42.243.110) on http://www.fenestrated.net/~macman/

    You might consider using the ssh_blocker that Juan J. Martínez wrote and I hacked up... it does just what's been suggested: listens to the logfiles and adds anybody that tries to log in with an invalid username to a PF table. I personally block drop quick that table.

    The homepage is http://www.usebox.net/jjm/ssh_blocker/ with my modified realtime version at http://www.fenestrated.net/~macman/stuff/ssh_blocker.sh

    I use expiretables to remove the entries after about 10 minutes; that way if I fat-finger something when I'm remote, I'm not totally locked out. I almost never see any scanners retrying after the 10 minutes have passed.

    Comments
    1. By Anonymous Coward (69.42.243.110) on

      Also, it's trivial to hack this up to watch the ftp logs and block ftp scans, too. Yet another way to reduce the size of your logfiles.

    2. By William Palmer (wcpalmer) on http://wcpalmer.com

      > You might consider using the ssh_blocker that Juan J. Martínez wrote and I hacked up... it does just what's been suggested: listens to the logfiles and adds anybody that tries to log in with an invalid username to a PF table. I personally block drop quick that table.
      >
      > The homepage is http://www.usebox.net/jjm/ssh_blocker/ with my modified realtime version at http://www.fenestrated.net/~macman/stuff/ssh_blocker.sh
      >
      > I use expiretables to remove the entries after about 10 minutes; that way if I fat-finger something when I'm remote, I'm not totally locked out. I almost never see any scanners retrying after the 10 minutes have passed.

      Cool, thanks for the links!

      I'll probably still write my own Perl version, since Perl is a bit more... "concise" than shell script. :P

      Plus, it'll be good practice. :)

    3. By Sean Cody (sean) on I don't work here.

      >http://www.fenestrated.net/~macman/stuff/ssh_blocker.sh
      >
      I believe this method breaks when the logs rotate.
      I've not found a nice clean solution for shell scripts which get input from rotated logs. If you have one I'd love to hear about it.

      Comments
      1. By sthen (85.158.44.148) on

        > >http://www.fenestrated.net/~macman/stuff/ssh_blocker.sh
        > >
        > I believe this method breaks when the logs rotate.

        tail -f handles rotation OK (at least on OpenBSD; this is not the case for some other OS). The regular expression needs tightening, though. http://www.ossec.net/en/attacking-loganalysis.html

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]