bring OS X to its knees, thanks to sshd via launchd

In my previous post, I had discussed an interesting issue I came across where we were hitting MaxStartups in our modified, standalone sshd configuration, but not via the Mac OS X (and Mac OS X Server) default configuration (since an sshd parent is forked off via the launchd service for each individual SSH connection).

Now, that got me thinking. If sshd NEVER hits MaxStartups via the OS X default launchd setup, then it should be relatively easy to DoS an OS X box, right? By default, OS X only allows 256 maximum user processes and 512 file descriptors, so with each new fork of an sshd parent, you can easily eat into that space and essentially block anyone from doing anything once you hit the limit. Even better (or worse), I’m guessing most OS X (and OS X Server) users don’t change any of these defaults: they keep sshd via launchd, and never run into any type of issue where they’d have to increase maxprocs or max file descriptors.

With this idea in my head, I chose to use my wife’s Macbook Pro as our test server; it could use a little exercise. So, I did what any OS X user would do: I went to System Preferences > Sharing, and then enabled Remote Login. Of course, if  I do a ‘ps’ to see if it’s running, I won’t see anything, because launchd is just hanging out waiting for someone to hit port 22.

Next thing, my Macbook Pro will have the same system defaults, so I have to increase those to be able to exceed them limit on the receiving end. That’s easy enough- let’s increase our maxprocs and max fds:

chets-laptop $ sudo ulimit -n 2048
chets-laptop $ sudo ulimit -u 1024

There we go. Now, with my wife’s laptop willing and ready, let’s take out our trusty for loop:

chets-laptop $ for i in `jot 512 1`; do ssh 192.168.1.110 & done

Now, with that running, I jump over to my wife’s laptop (Terminal already open), and I try to do an ‘ls’. Sure enough:

wifes-poor-laptop $ ls
-bash: fork: Resource temporarily unavailable

Whoops! At this point, with a flood of SSH connections incoming, the only real thing I can do to stop the DoS is unload sshd from launchd. However, since the machine has hit the maximum number of processes allowed, I can’t even run the command to unload sshd from launchd. I can’t kill the sshd processes either, because I’d only be killing each individual parent, and launchd would just keep forking them off with each new connection. Regardless, killing won’t work anyway, just like unloading sshd from launchd:

wifes-poor-laptop $ sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
-bash: fork: Resource temporarily unavailable

also tried:

wifes-poor-laptop $ sudo killall sshd
-bash: fork: Resource temporarily unavailable

Ouch. Of course, I also tried opening some apps (System Preferences, Address Book, etc), and those would just bounce and bounce forever; the system had hit the hard limit, so there was nothing that could be done.

At this point, the ONLY way I could stop the attack was to take the machine off of the network, resulting in the sshd forks timing out and exiting. My wife’s laptop was actually wired at the time; if it were on Airport, I’m not sure if the system would have required an extra process resource to actually disable Airport, meaning a machine on the net via Airport would be totally, 100% useless.

Regardless, I think this is something people should be aware of before starting up Remote Login. Of course, running any type of remote login daemon is always a security risk, but if you’re on an open network with a public facing IP, you’re pretty much exposing your machine to being easily DoS’d by someone who knows how to write a for loop. You could, of course, set up TCP wrappers to buffer some of that, run ipfw, and whatever else, but I’m guessing that most OS X users aren’t going to be doing much in the way of this.

My suggestion: set up your hosts.allow/deny, configure ipfw to look for connection flooding on port 22, take sshd out of launchd, and, of course, only run sshd if you really need to. If someone out there wants to lock up your machine, and you’re running the OS X defaults, they can do it in about 10 seconds, and you won’t have a clue what hit you until you suddenly can’t do anything with your machine anymore.

All things aside, I love OS X and think it’s a great OS. There are just a few design decisions here and there that still need to be tweaked. Running sshd via the equivalent of xinetd is one of them. Good luck!

Leave a comment