Re: Defending against the Apache killer

2011-08-24 Thread Baptiste
On Tue, Aug 23, 2011 at 8:09 AM, Willy Tarreau w...@1wt.eu wrote:
 On Mon, Aug 22, 2011 at 07:57:10PM +0200, Baptiste wrote:
 Hi,

 Why not only dropping this Range:bytes=0- header?

 Agreed. Protecting against this vulnerability is not a matter of limiting
 connections or whatever. The attack makes mod_deflate exhaust the process'
 memory. What is needed is to remove the Range header when there are too
 many occurrences of it.

 Their attack puts up to 1300 Range values. Let's remove the header if
 there are more than 2 :

    reqidel ^Range if { hdr_cnt(Range) gt 2 }

 That should reliably defeat the attack.

 Regards,
 Willy




Actually, this is slightly different.
According to the Perl script, a single Range header is sent, but it is
forge with a lot of range value.
IE: Range: 0-,5-1,5-2,5-3,[...]

Since there is no hdr_size ACLs for now, the only way is to use a
hdr_reg to do this:
reqidel ^Range if { hdr_reg(Range) ([0-9]+-[0-9]+,){10,} }

But the regexp above does not work (haproxy 1.5-dev6), the comma is
not matched
don't know yet if it's an haproxy bug or not, I'll tell you once I
have finished investigating.

cheers



Re: Defending against the Apache killer

2011-08-24 Thread Baptiste
On Wed, Aug 24, 2011 at 12:44 PM, Baptiste bed...@gmail.com wrote:
 On Tue, Aug 23, 2011 at 8:09 AM, Willy Tarreau w...@1wt.eu wrote:
 On Mon, Aug 22, 2011 at 07:57:10PM +0200, Baptiste wrote:
 Hi,

 Why not only dropping this Range:bytes=0- header?

 Agreed. Protecting against this vulnerability is not a matter of limiting
 connections or whatever. The attack makes mod_deflate exhaust the process'
 memory. What is needed is to remove the Range header when there are too
 many occurrences of it.

 Their attack puts up to 1300 Range values. Let's remove the header if
 there are more than 2 :

    reqidel ^Range if { hdr_cnt(Range) gt 2 }

 That should reliably defeat the attack.

 Regards,
 Willy




 Actually, this is slightly different.
 According to the Perl script, a single Range header is sent, but it is
 forge with a lot of range value.
 IE: Range: 0-,5-1,5-2,5-3,[...]

 Since there is no hdr_size ACLs for now, the only way is to use a
 hdr_reg to do this:
 reqidel ^Range if { hdr_reg(Range) ([0-9]+-[0-9]+,){10,} }

 But the regexp above does not work (haproxy 1.5-dev6), the comma is
 not matched
 don't know yet if it's an haproxy bug or not, I'll tell you once I
 have finished investigating.

 cheers


I confirm, this looks like a bug in HAProxy, maybe in the way HAProxy
loads the regexp from the configuration file:
Here is a req.txt file simulating the attack:
HEAD / HTTP/1.1
Host: 10.0.3.20
Range: 
bytes=0-,5-0,5-1,5-2,5-3,5-4,5-5,5-6,5-7,5-8,5-9,5-10,5-11,5-12,5-13,5-14,5-15,5-16,5-17,5-18,5-19,5-20,5-21,5-22,5-23,5-24,5-25,5-26,5-27,5-28,5-29,5-30,5-31,5-32,5-33,5-34,5-35,5-36,5-37,5-38,5-39,5-40,5-41,5-42,5-43,5-44,5-45,5-46,5-47,5-48,5-49,5-50,5-51,5-52,5-53,5-54,5-55,5-56,5-57,5-58,5-59,5-60,5-61,5-62,5-63,5-64,5-65,5-66,5-67,5-68,5-69,5-70,5-71,5-72,5-73,5-74,5-75,5-76,5-77,5-78,5-79,5-80,5-81,5-82,5-83,5-84,5-85,5-86,5-87,5-88,5-89,5-90,5-91,5-92,5-93,5-94,5-95,5-96,5-97
Accept-Encoding: gzip
Connection: close


And a working regexp tested with egrep:
egrep -v ([0-9]+-[0-9]+,){10,} req.txt
HEAD / HTTP/1.1
Host: 10.0.3.20
Accept-Encoding: gzip
Connection: close

The following regexp works in HAProxy: ([0-9]+-[0-9]+)
The same with the coma does not work: ([0-9]+-[0-9]+,)
This one works: ([0-9]+-[0-9]+?)
And this one does not: ([0-9]+-[0-9]+?)\{10,\}

Maybe I'm doing something wrong.
If your need more details, please let me know.

cheers



Re: Defending against the Apache killer

2011-08-24 Thread Cyril Bonté
Hi all,

On Wednesday 24 August 2011 13:02:18 Baptiste wrote:
(...)
  Since there is no hdr_size ACLs for now, the only way is to use a
  hdr_reg to do this:
  reqidel ^Range if { hdr_reg(Range) ([0-9]+-[0-9]+,){10,} }
  
  But the regexp above does not work (haproxy 1.5-dev6), the comma is
  not matched
  don't know yet if it's an haproxy bug or not, I'll tell you once I
  have finished investigating.
  
  cheers
 
 I confirm, this looks like a bug in HAProxy, maybe in the way HAProxy
 loads the regexp from the configuration file:

This is not how HAProxy loads the regex but how it applies them to the 
headers.
The comma character (,) is considered as a value separator. HAProxy will then 
try to apply the regex to each value found in the Range header.
For this header :
Range: 
bytes=0-,5-0,5-1,5-2,5-3,5-4,5-5,5-6,5-7,5-8,5-9,5-10,5-11,5-12,5-13,5-14,5-15,5-16,5-17,5-18,5-19,5-20,5-21,5-22,5-23,5-24,5-25,5-26,5-27,5-28,5-29,5-30,5-31,5-32,5-33,5-34,5-35,5-36,5-37,5-38,5-39,5-40,5-41,5-42,5-43,5-44,5-45,5-46,5-47,5-48,5-49,5-50,5-51,5-52,5-53,5-54,5-55,5-56,5-57,5-58,5-59,5-60,5-61,5-62,5-63,5-64,5-65,5-66,5-67,5-68,5-69,5-70,5-71,5-72,5-73,5-74,5-75,5-76,5-77,5-78,5-79,5-80,5-81,5-82,5-83,5-84,5-85,5-86,5-87,5-88,5-89,5-90,5-91,5-92,5-93,5-94,5-95,5-96,5-97

It will check byte=0-
then 5-0
then 5-1
then ...


-- 
Cyril Bonté



Re: Defending against the Apache killer

2011-08-24 Thread Baptiste
On Wed, Aug 24, 2011 at 1:44 PM, Cyril Bonté cyril.bo...@free.fr wrote:
 Hi all,

 On Wednesday 24 August 2011 13:02:18 Baptiste wrote:
 (...)
  Since there is no hdr_size ACLs for now, the only way is to use a
  hdr_reg to do this:
  reqidel ^Range if { hdr_reg(Range) ([0-9]+-[0-9]+,){10,} }
 
  But the regexp above does not work (haproxy 1.5-dev6), the comma is
  not matched
  don't know yet if it's an haproxy bug or not, I'll tell you once I
  have finished investigating.
 
  cheers

 I confirm, this looks like a bug in HAProxy, maybe in the way HAProxy
 loads the regexp from the configuration file:

 This is not how HAProxy loads the regex but how it applies them to the
 headers.
 The comma character (,) is considered as a value separator. HAProxy will then
 try to apply the regex to each value found in the Range header.
 For this header :
 Range:
 bytes=0-,5-0,5-1,5-2,5-3,5-4,5-5,5-6,5-7,5-8,5-9,5-10,5-11,5-12,5-13,5-14,5-15,5-16,5-17,5-18,5-19,5-20,5-21,5-22,5-23,5-24,5-25,5-26,5-27,5-28,5-29,5-30,5-31,5-32,5-33,5-34,5-35,5-36,5-37,5-38,5-39,5-40,5-41,5-42,5-43,5-44,5-45,5-46,5-47,5-48,5-49,5-50,5-51,5-52,5-53,5-54,5-55,5-56,5-57,5-58,5-59,5-60,5-61,5-62,5-63,5-64,5-65,5-66,5-67,5-68,5-69,5-70,5-71,5-72,5-73,5-74,5-75,5-76,5-77,5-78,5-79,5-80,5-81,5-82,5-83,5-84,5-85,5-86,5-87,5-88,5-89,5-90,5-91,5-92,5-93,5-94,5-95,5-96,5-97

 It will check byte=0-
 then 5-0
 then 5-1
 then ...


 --
 Cyril Bonté



ahah :)
You're both all right.
Sorry, I totaly forgot this part of the RFC:
Multiple message-header fields with the same field-name MAY be
present in a message if and only if the entire field-value for that
header field is defined as a comma-separated list [i.e., #(values)].
It MUST be possible to combine the multiple header fields into one
field-name: field-value pair, without changing the semantics of the
message, by appending each subsequent field-value to the first, each
separated by a comma. The order in which header fields with the same
field-name are received is therefore significant to the interpretation
of the combined field value, and thus a proxy MUST NOT change the
order of these field values when a message is forwarded.


So the hdr_cnt from willy works.
I did not try this option since this is not how the Perl script of the
first mail build the attack.

sorry for the noise and glad to see tha HAProxy works well :)



Re: X-Forwarded-For contortions

2011-08-24 Thread Bryan Talbot
I think this will address my issue, thanks a lot!  Sorry for not
getting back to your questions sooner; I just returned from an
end-of-summer trip.

I'll check it out soon.  It's in 1.4 trunk but not in any release yet, correct?


-Bryan


On Fri, Aug 19, 2011 at 2:04 PM, Willy Tarreau w...@1wt.eu wrote:
 Hi Bryan,

 On Tue, Aug 16, 2011 at 07:51:07AM +0200, Willy Tarreau wrote:
 Hi Bryan,

 On Mon, Aug 15, 2011 at 11:13:18AM -0700, Bryan Talbot wrote:
  That would work but there are several CIDR networks that contain a trusted
  proxy.  The CDN is global and has proxies on most continents and many of
  them are on different networks.
 
  Since the option forwardfor can only handle a single network in the
  if|unless argument the only real use case it can support is where all the
  upstream proxies come from the same network -- like for an upstream SSL
  terminator.
 
  The logic I need is:
 
  if traffic is from a trusted upstream proxy of multiple networks
    leave existing XFF header alone
  else
    strip any XFF header from request and add our own

 Well, I think we could see it slightly differently :

   if traffic is from a trusted upstream proxy of multiple networks
     leave existing XFF header alone
   else
     strip any XFF header from request

   if (no XFF is present)
     and add our own

 This way we could use the ACLs to delete any existing occurrence
 and have a simple flag to indicate the addition is conditionnal.
 For instance we could have a dont-replace flag on the fwdfor
 config line to indicate that it should only be set and not replaced.

 However we have to keep in mind that XFF is performed both in the
 frontend and the backend, so the conditional logic must be compatible
 between both. This means that if either of the front or back has the
 option without the dont-replace flag, it will still be replaced.

 I did it, though I changed the argument name to if-none to make it
 less ambiguous especially in the case where both the frontend and the
 backend have the option. It is even supported in the defaults section
 (but this should be avoided since it has security implications).

 Thus, for your case above, you'd simply remove the header if the IP
 comes from an untrusted host, then conditionally add it :

   reqidel ^x-forwarded-for if !from_proxies
   option forwardfor if-none

 I'm attaching the patch, but it's already pushed upstream.

 Regards,
 Willy





Send frontend response before getting response from remote web server

2011-08-24 Thread Guy Knights
Hi,

We have some HTTP calls from our app that we'd like to fire and forget, but
we need the Haproxy frontend send a response to the requester immediately
after it passes the request to the backend queue. The intention is to
replace our Gearman setup and thus save us some time in maintenance and
management as we can then just deal in HTTP calls, it also saves us having
to write PHP scripts for gearman processing. What we need is to just be able
to execute a curl call and send a response back as as soon as possible so
the curl call can complete and the script can finish processing.

The chain we want is:

1. Local webserver --- request --- Haproxy frontend
2. Local webserver --- local OK response --- Haproxy frontend --- request
(queue) --- Haproxy backend
3. Haproxy backend --- request --- Remote webserver
4. Haproxy backend --- remote response --- Remote webserver
5. dumped --- remote response --- Haproxy backend

We did some research and it seems like both of the following are possible:

1. Send an automatic HTTP response code from the frontend to the requesting
web server.
2. Put the request in the backend queue to be sent to the remote server

However, with the above it doesn't seem like we can send the response from
the frontend *immediately* after we put the request in the backend queue.

I hope that makes sense. Can anyone provide any feedback on whether
something like this is possible?

Thanks,
Guy



-- 
Guy Knights
Systems Administrator
Eastside Games
www.eastsidegamestudio.com
g...@eastsidegamestudio.com