2. Triggering the bug
One of DcLabs members, ipax, using a fuzzer noticed that when sending a big buffer and using the “HEAD” HTTP Method the software crashed with a segfault signal.

He then asked me to take a look and, some time later, here we are ;). Ok, first thing to do is download a copy of the software and (God bless open source) compile it with debugging symbols, then running our “trigger” again, we were able to identify the crash:

Ok, no ringing bells in this function – all I can see here is the “arg” referenced by gdb as overwritten. So, if its function argument was overwritten it probably happened due to a most internal function and its stack frames.

Looking at this code we can clearly see another function being called:“job = swebs_get_job_from(someone);”
Let’s dig into it then:

Now I can hear the bells ;)! We’ve a couple of static stack buffers and a non-boundary check aware function (snprintf()) being used on one of them.
First bet: logrec[] isn’t bigger enough to receive the contents supplied by sprintf().

4. Source-Code Diving
Now we’ve two paths: 1) Start from here and up to socket reading – 2) Look for socket reading and follow the HEAD’s method flow.

So far so good, swebs_read_http_request() calls http_recv_header() and it reads MAX_HDR_LEN from socket. We can see the programmer decided to go with a poll() to handle server’s connections, all we need to know now is that there is a “trigger” in that waitfor struct calling logger_th() and then calling swebs_record_log().

The name “job->hdr.request_line” has a suggestive name to store our request HTTP.
Now we can suppose:
– Program reads 2840 bytes from socket
– It also defines MAX_REQUEST_LINE_LEN to 800
– Variable “logrec” should be no greater than MAX_REQUEST_LINE_LEN+1 (NULL byte?)
– The maximum request size used on our fuzzer should be near of 800 bytes

Time to follow the yellow brick path.
As we’ve already stated the bug happens when we send a huge HEAD request, let’s see how it handles with HEAD:

At http_parse_request_header() we can see some checks
1. Copy “\r\n” position on buffer to “s”, so s == end of request
1.1 “check len?” … :/
2. Copy the whole http request in data until “\r\n” to h->request_line
3. Now we’ve a while validating the method length with MAX_METH_LEN(8) bytes
4. Then http_bad_method() validate a valid method
5. At last, the pair sscanf()+if validates if the request is compliant (HTTP/X.Y)

Deu to item 1., it copy all 2840 bytes (or at least until it finds “\r\n”) into variable h->request_line, that is the exactly same job->hdr.request_line into our vulnerable function.

Recap: The flaw happens at swebs_record_log() due to a static buffer of 800+1 (MAX_REQUEST_LINE_LEN+1) bytes, that is “fed” with sprintf() and string format: "%s\t[%s]\t\"%s\"\t(%d+

%d/%d)\t%d", its clear we aren’t alone at playground… The exact value to overwrite this buffer must be calculated among all variables in sprintf().

5. Exploit
I wrote this exploit and the advisory was published at bugtraq, and exploit is also available at Exploit-DB.

Since even exploit-db mess up with our exploits indentation, I’ll post it here too.

There was two “tricky moments” during this exploit birth, we can see it below:

* First Exploit Crux *
As stated earlier, our buffer isn’t alone into logrec[] stack space and, mandatorily (because of those checks), we need to end our buffer with: “HTTP/X.Y” string BUT there is a heap variable pointing to this point of our request, see: