[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