Nmap Development mailing list archives

Re: http.lua not handling malformed HTTP response gracefully


From: David Fifield <david () bamsoftware com>
Date: Thu, 2 Jul 2009 15:30:50 -0600

On Thu, Jul 02, 2009 at 03:19:19PM -0600, Patrick Donnelly wrote:
On Thu, Jul 2, 2009 at 2:41 PM, Brandon Enright<bmenrigh () ucsd edu> wrote:
Hey all, I ran into a machine on campus (Cannon Printer) that causes
NSE to hang forever in a busy-loop.  Since the script never yields even
host timeout doesn't help.

Thanks to David's sharp eye and troubleshooting genius, I have attached
a simple test case.

You can make a listener with:

sudo ncat -l 80 --sh-exec "cat bad-http.txt"

And you can scan it with:

nmap --script=html-title -p 80 -d2 localhost

With high debugging on, you should see something like:

...
NSOCK (0.1030s) Read request from IOD #1 [x.y.179.88:80] (timeout: 7000ms) EID 34
NSOCK (0.1030s) nsock_loop() started (timeout=50ms). 1 events pending
NSOCK (0.1030s) Callback: READ EOF for EID 34 [x.y.179.88:80]
NSE: TCP x.y.1.115:38187 > x.y.179.88:80 | CLOSE
<hang forever at 100% CPU here>

David points out that the likely culprit is that the HTTP response
includes "Transfer-Encoding: chunked" but the response is not actually
chunked.

All the scripts that make use of http.lua will die when this happens.

You both may already be aware of this: I'm looking at http.lua where
the problem apparently is:

    while ( ptr < ( type( body ) == "string" and body:len() ) or 1 ) do
      local hex = body:match( pattern, ptr )
      if not hex then break end
      chunk_len = tonumber( hex or 0, 16 ) or nil
      if chunk_len then
        start = ptr + hex:len() + 2*body_delim:len()
        ptr = start + chunk_len
        b[#b+1] = body:sub( start, ptr-1 )
      end
    end

In the case David gave, hex is always the string "<HTML>". Because
chunk_len is always going to be "nil", the loop never advances past
the first match in body. I don't know the appropriate way to handle
this (break the loop if chunk_len ever equals nil? advance ptr by 1?).

If hex is not a hex string, then the chunked encoding is definitely
messed up. We can either 1) reject the whole body as bogus, or 2) assume
non-chunked and return the rest of the body verbatim. My vote is to
check the very first place a hex length is expected, and if it's not
hex, return the rest of the body non-chunked. If we get something other
than hex after the first chunk (i.e., after at least one chunk was
processed successfully) then throw out the whole body. If that happens
then the encoding is seriously messed up or there's a bug in our parser.

David Fifield

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: