<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sidenotes &#187; apple</title>
	<atom:link href="http://chetnichols.org/category/tech/apple/feed/" rel="self" type="application/rss+xml" />
	<link>http://chetnichols.org</link>
	<description>and other random technical bantering, by chet nichols</description>
	<lastBuildDate>Sat, 24 Jul 2010 19:47:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>bring OS X to its knees, thanks to sshd via launchd</title>
		<link>http://chetnichols.org/2009/11/11/bring-os-x-to-its-knees-thanks-to-sshd-via-launchd/</link>
		<comments>http://chetnichols.org/2009/11/11/bring-os-x-to-its-knees-thanks-to-sshd-via-launchd/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 09:16:55 +0000</pubDate>
		<dc:creator>chet</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[tech]]></category>

		<guid isPermaLink="false">http://chetnichols.org/?p=24</guid>
		<description><![CDATA[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, [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous post, I had discussed an interesting issue I came across where we were hitting <em>MaxStartups</em> 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).</p>
<p>Now, that got me thinking. If sshd NEVER hits <em>MaxStartups</em> 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&#8217;m guessing most OS X (and OS X Server) users don&#8217;t change any of these defaults: they keep sshd via launchd, and never run into any type of issue where they&#8217;d have to increase maxprocs or max file descriptors.</p>
<p>With this idea in my head, I chose to use my wife&#8217;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 &gt; Sharing, and then enabled Remote Login. Of course, if  I do a &#8216;ps&#8217; to see if it&#8217;s running, I won&#8217;t see anything, because launchd is just hanging out waiting for someone to hit port 22.</p>
<p>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&#8217;s easy enough- let&#8217;s increase our maxprocs and max fds:</p>
<p><code>chets-laptop $ sudo ulimit -n 2048<br />
chets-laptop $ sudo ulimit -u 1024</code></p>
<p>There we go. Now, with my wife&#8217;s laptop willing and ready, let&#8217;s take out our trusty for loop:</p>
<p><code>chets-laptop $ for i in `jot 512 1`; do ssh 192.168.1.110 &amp; done</code></p>
<p>Now, with that running, I jump over to my wife&#8217;s laptop (Terminal already open), and I try to do an &#8216;ls&#8217;. Sure enough:</p>
<p><code>wifes-poor-laptop $ ls<br />
-bash: fork: Resource temporarily unavailable</code></p>
<p>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&#8217;t even run the command to unload sshd from launchd. I can&#8217;t kill the sshd processes either, because I&#8217;d only be killing each individual parent, and launchd would just keep forking them off with each new connection. Regardless, killing won&#8217;t work anyway, just like unloading sshd from launchd:</p>
<p><code>wifes-poor-laptop $ sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist<br />
-bash: fork: Resource temporarily unavailable</code></p>
<p>also tried:</p>
<p><code>wifes-poor-laptop $ sudo killall sshd<br />
-bash: fork: Resource temporarily unavailable</code></p>
<p>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.</p>
<p>At this point, the <em>ONLY</em> 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&#8217;s laptop was actually wired at the time; if it were on Airport, I&#8217;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.</p>
<p>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&#8217;re on an open network with a public facing IP, you&#8217;re pretty much exposing your machine to being easily DoS&#8217;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&#8217;m guessing that most OS X users aren&#8217;t going to be doing much in the way of this.</p>
<p>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&#8217;re running the OS X defaults, they can do it in about 10 seconds, and you won&#8217;t have a clue what hit you until you suddenly can&#8217;t do anything with your machine anymore.</p>
<p>All things aside, I love OS X and think it&#8217;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!</p>
]]></content:encoded>
			<wfw:commentRss>http://chetnichols.org/2009/11/11/bring-os-x-to-its-knees-thanks-to-sshd-via-launchd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ssh_exchange_identification adventures</title>
		<link>http://chetnichols.org/2009/11/08/ssh_exchange_identification-adventures/</link>
		<comments>http://chetnichols.org/2009/11/08/ssh_exchange_identification-adventures/#comments</comments>
		<pubDate>Sun, 08 Nov 2009 10:59:34 +0000</pubDate>
		<dc:creator>chet</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[tech]]></category>

		<guid isPermaLink="false">http://chetnichols.org/blog/?p=10</guid>
		<description><![CDATA[I ran into a fun issue on Friday evening with one of our servers, so I thought I&#8217;d toss it out into the world just incase anyone else runs into a similar issue. We have a rather heavily loaded administrative server, an Xserve, running Mac OS X Server. Additionally, we run a modified sshd configuration, [...]]]></description>
			<content:encoded><![CDATA[<p>I ran into a fun issue on Friday evening with one of our servers, so I thought I&#8217;d toss it out into the world just incase anyone else runs into a similar issue.</p>
<p>We have a rather heavily loaded administrative server, an Xserve, running Mac OS X Server. Additionally, we run a modified sshd configuration, where sshd runs as a standalone service, instead of via launchd as is with the default system installation. Is it relevant? Yes.</p>
<p>So, Friday evening rolls around (of course), and I get an e-mail from a co-worker saying that when she tries to log in, she gets that oh-so-common error message:</p>
<p><strong>ssh_exchange_identification: Connection closed by remote host</strong></p>
<p>Usually, in all of my experiences, this has been related to TCP wrappers; you&#8217;ve got a hosts.allow or hosts.deny set up, and you&#8217;re blocking (purposely or by accident), and just need to fix the config. Sometimes you&#8217;re totally screwed, but whatever. In our case, however, we aren&#8217;t using TCP wrappers. We could, since the default sshd in OS X does support it:</p>
<p><code>[chet@myhost]$ strings /usr/sbin/sshd  | grep wrap<br />
Connection refused by tcp wrapper<br />
libwrap refuse returns</code></p>
<p>or, if you have Xcode installed, you can use otool (the OS X equivalent to ldd in Linux):</p>
<p><code>[chet@myhost]$ otool -L /usr/sbin/sshd | grep libwrap<br />
/usr/lib/libwrap.7.dylib (compatibility version 7.0.0, current version 7.6.0)</code></p>
<p>However, we don&#8217;t have a hosts.(allow|deny), so that&#8217;s not the issue. Thinking further, I remembered someone mentioning that the box was under more load than usual, and may have hit some type of system limit (maxprocs, maxttys, etc). To test, I basically flooded the box with ssh connection requests using a super-basic loop that a 3rd grader would write:</p>
<p><code>$ for connection in `jot 500 1`; do<br />
$   ssh myhost &amp;<br />
$ done</code></p>
<p>Sure enough, right when I started the loop, I immediately began getting ssh_exchange_identification errors thrown back at me, whereas a single login not amidst a loop would work just fine. Bingo. So, it wasn&#8217;t a system limit per-se, but it was some type of sshd limit that was being triggered within the daemon itself.</p>
<p>Looking through the man pages, I came across an sshd_config option called MaxStartups. Here&#8217;s what the man page had to say:</p>
<blockquote><p><strong>MaxStartups</strong></p>
<p><em> Specifies the maximum number of concurrent unauthenticated con-</em><br />
<em> nections to the sshd daemon.  Additional connections will be</em><br />
<em> dropped until authentication succeeds or the LoginGraceTime</em><br />
<em> expires for a connection.  The default is 10.</em></p></blockquote>
<p>This sounded like a totally plausible cause for the issue. When I would flood, it would make requests so fast that sshd couldn&#8217;t keep up with authentications, so sshd would reach the MaxStartups limit and start blocking (to protect against DoS attacks, etc). To test it out, I changed <em>MaxStartups</em> from 10 to 200, ran my flood loop again, and sure enough, was able to connect without any errors. Perfect.</p>
<p>However, how come we hadn&#8217;t run into it before? Did it have something to do with us running sshd as a standalone daemon instead of via launchd? The standalone configuration is new for us, so we&#8217;re still keeping our eye out for bugs. To test, I ran my same flooding loop on an OS X Server machine running the system default (via launchd) sshd configuration. Sure enough, the issue did <strong>NOT</strong> present itself for that machine. Interesting.</p>
<p>Now, why is this, you may ask? It has to do with the way the sshd daemon runs via launchd.</p>
<p>The launchd service is very similar to xinetd when it comes to running network services: launchd knows what network services are configured under it, and it knows the ports those network services should accept connections from. So, launchd itself will listen on those ports. When a new connection request comes in (example: ssh), launchd will see it&#8217;s for port 22/sshd, fork off an sshd parent, and your connection gets handed off to that parent. If another connection comes in, launchd will fork off yet another sshd parent, and that 2nd user will get the 2nd parent. See the issue?</p>
<p>With the <em>MaxStartups</em> option in sshd_config, it relies on the sshd parent being the process handling all incoming connections, and forking off children for each new connection. If it sees that &gt;= <em>MaxStartups</em> children are in an un-authenticated state, it will block new connections from establishing.</p>
<p>In the case of launchd, however, each connection is a parent forked from launchd, so no parent will ever see more than 1 connection (since it will have no children). In that respect, it totally subverts the sshd_config option for <em>MaxStartups</em>, opening up your machine to DoS attacks via sshd floods. Awesome.</p>
<p>In any case, now that we understand the issue, how come it was presenting itself under a scenario where people <em>weren&#8217;t</em> trying to flood it with ssh connections? The answer lies somewhere between system load, DirectoryServices, and the pam_securityserver.so PAM module.</p>
<p>When an ssh request comes in, and PAM is enabled, sshd will use the options defined in the /etc/pam.d/sshd file to determine what needs to be done to authorize the user. In our case, we have this configuration (slightly modified from the default OS install, since we&#8217;re not running via launchd):</p>
<p><code>[chet@myhost] $ cat /etc/pam.d/sshd<br />
# sshd: auth account password session<br />
auth       required       pam_nologin.so<br />
auth       optional       pam_afpmount.so<br />
auth       sufficient     pam_securityserver.so<br />
auth       sufficient     pam_unix.so<br />
auth       required       pam_deny.so<br />
account    required       pam_securityserver.so<br />
password   required       pam_deny.so<br />
session    required       pam_permit.so<br />
session    optional       pam_afpmount.so</code></p>
<p>Looking at the file, we notice a couple of entries for pam_securityserver.so. This module is actually the bread and butter of the authentication process: it queries the local DirectoryServices agent running on the machine to do the user authentication, and will receive a success or failure from the agent. The DirectoryServices agent can be configured to authenticate for local users, remote users from an LDAP directory server, or a mix of both. It&#8217;s versatile, but it does a good amount of work. In the case of it being bound to a remote LDAP server, it can also be very slow (depending on if you&#8217;re caching account results or not).</p>
<p>Our issue was two-fold: at the time, the host was heavily loaded with some CPU <strong>and</strong> network intensive processes. The CPU intensive processes were slowing down the communication between pam_securityserver.so and DirectoryServices, and the network intensive processes were slowing down the communication between DirectoryServices and our remote LDAP server. Between the both of these, authentications became super slow, and incoming, un-authentication connections were slowly creeping up (especially due to the scripted cron-job logins that had no logic to drop a hung login &#8211; awesome).</p>
<p>However, at that time, things were actually still okay. Slow, but people could still get in. Unfortunately (or luckily), someone sent out a chat message saying the host was acting slow, which of course prompted everyone to try logging in at the same time. At that point, 10 MaxStartups was hit almost immediately (ie: 10 people tried logging in, and since authentications were taking forever, all were stuck as un-authenticated), resulting in the ssh_exchange_identification error being sent back to all subsequent logins immediately (this was a nice bit of detail to note: the sshd daemon itself was still very quick to respond, but as soon as it had to hand an authentication back off to PAM, it just sat around waiting).</p>
<p>Ultimately, the resolution for this was we increased MaxStartups for our heavily-loaded machines (which is still better than the un-regulated launchd sshd), and we will be setting up  separate server to handle all the jobs that were running.</p>
<p>Looking at other options, I noticed while writing this that pam_securityserver.so comes <em>BEFORE</em> pam_unix.so. As a test, I may try using pam_unix.so first, allowing root logins to bypass DirectoryServices, hitting passwd/shadow directly, and hopefully allowing us to jump in on what seems like a hung system due to DS being super slow. I&#8217;ll try to get back with an update if I end up testing this.</p>
<p>That&#8217;s all from me for now. Feel free to comment on your own experiences, knowledge, other ideas, or if you&#8217;ve run into the same thing. Enjoy!</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 124px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">[chet@myhost]$ strings /usr/sbin/sshd  | grep wrap</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 124px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">Connection refused by tcp wrapper</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 124px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">libwrap refuse returns</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 124px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">@(#)$OpenBSD: monitor_wrap.c,v 1.40 2005/05/24 17:32:43 avsm Exp $</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 124px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">outgoing seqnr wraps around</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 124px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">incoming seqnr wraps aroun</div>
]]></content:encoded>
			<wfw:commentRss>http://chetnichols.org/2009/11/08/ssh_exchange_identification-adventures/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
