[Twisted-Python] Broker leak in spread server on login failure = denial of service?
Jp Calderone
exarkun at divmod.com
Fri Sep 9 18:01:12 EDT 2005
On Fri, 9 Sep 2005 16:31:28 -0500, "David K. Hess" <dhess at verscend.com> wrote:
>
>I believe I've discovered a broker leak when a checker denies a login and
>that it can be used to launch a denial of service attack on a spread
>server.
>
>When a checker throws a Failure exception, since requestAvatar in the realm
>doesn't get called, the realm (or anything else) doesn't end up with a
>reference it can use to disconnect the network connection that was denied
>login.
>
>If a malicious (or just buggy as was my case) client tries to login over
>and over again and doesn't shutdown each connection from the client side,
>the server will continue to leak brokers until (under Windows) the select()
>call begins to fail because there are greater than 512 (with a stock Python
>build) file descriptors open and being monitored by the reactor. At this
>point, your server is dead as the reactor goes into an infinite loop
>retrying failing select() calls when this happens.
It's easier than this. A client could connect and send no bytes at all. The socket would remain open forever with the default factory behavior, allowing a user to exhaust all available file descriptors.
This is an attack possible on any server that doesn't limit new connections or time out existing ones somehow.
>
>What I think might be best is if another method in the realm (say
>"loginFailed(self, mind)") was called with the remote reference so the
>server could then call mind.broker.transport.loseConnection() on it. It
>would be nice too if this was after the Failure had been sent back across
>the connection and not before.
>
>clientConnectionMade in PBServerFactory also looks promising but it doesn't
>seem possible to figure out which connection is authenticating from within
>the checker.
>
>Can anybody offer some advice on how best to handle this?
Rather than extending the cred interface, which may not even be invoked, I'd start by altering the behavior of the server factory. Either impose a per-IP connection limit, or a connection rate limit, or a timeout for idle connections, or something along these lines. You might want to look at twisted.protocols.policies.LimitTotalConnectionsFactory or TimeoutFactory.
Hope this helps,
Jp
More information about the Twisted-Python
mailing list