[Twisted-Python] Broker leak in spread server on login failure = denial of service?

David K. Hess dhess at verscend.com
Fri Sep 9 16:36:31 MDT 2005


On Sep 9, 2005, at 5:01 PM, Jp Calderone wrote:

> 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.

Excellent points.

>
>>
>> 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.

 From my point of view, I don't want to punish the many for the sins  
of the few. I know exactly who I want to disconnect when a login  
fails. Also, unfortunately, my communication patterns don't support  
idle timeouts *after login* so I can't use a timeout to get rid of  
these.

What I want is what you would find in a normal Unix login. If there  
is no activity at the login prompt then after a while you get a  
disconnect. If you don't properly authenticate, you get a disconnect.  
Once you are logged in, no timeouts. I'd like that kind of behavior  
in my factory/realm/checker (even when the client doesn't initiate  
authentication).

I guess what I'll try is using clientConnectionMade to register a  
callLater of say 5 seconds on the broker's transport.loseConnection 
(). I can then cancel it if requestAvatar is called in the realm.  
That will cover both the denied login and 0 bytes transmitted cases.

> Hope this helps,

Yes, it did. Thanks!

Dave

>
> Jp
>
> _______________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com
> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
>





More information about the Twisted-Python mailing list