7541024 2001-11-20 15:04 +0000  /14 rader/ bugtraq <bugtraq@bugtraq.org>
Sänt av: joel@lysator.liu.se
Importerad: 2001-11-21  02:08  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Externa svar till: GOBBLES@hushmail.com
Mottagare: Bugtraq (import) <19822>
Ärende: Off-by-one vulnerability in thttpd!!!
------------------------------------------------------------
Hello fellow readers! 

GOBBLES Team has discovered an off-by-one overflow in thttpd.
Attached is  our advisory on the matter, which includes a summary of
the vulnerability  and a little information on how to exploit it.  We
chose not to release our  exploits for it at this time.

If you have any questions on this, please feel free to ask them. 

Visit http://www.bugtraq.org for more advisories and programs written
by the  GOBBLES Team!
(7541024) /bugtraq <bugtraq@bugtraq.org>/-(Ombruten)
Bilaga (text/plain) i text 7541025
7541025 2001-11-20 15:04 +0000  /219 rader/ bugtraq <bugtraq@bugtraq.org>
Bilagans filnamn: "GOBBLES-02.txt"
Importerad: 2001-11-21  02:08  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Externa svar till: GOBBLES@hushmail.com
Mottagare: Bugtraq (import) <19823>
Bilaga (text/plain) till text 7541024
Ärende: Bilaga (GOBBLES-02.txt) till: Off-by-one vulnerability in thttpd!!!
------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++GOBBLES+SECURITY+RESEARCH+TEAM+INCORPORATED+++++++++++++++++
	ALERT! ALERT! OFF-BY-ONE OVERFLOW IN THTTPD! ALERT! ALERT! 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#include "/usr/share/examples/kld/.../include/note.h"

GOBBLES say he English not very good but he try best to impart idea
across with help from dictionary.com and joe editor ^[L with
ispell. So GOBBLES by no mean linguist but he do best so reader
understand security issue at hand and patch immediately so darkside
malicious cracker out there in wild not given time to do destroying
valuable data and belong to national security.  Please keep in mind
that GOBBLES try to be accurate with information but he can only do
he best to not make error. Like joke goes what fly say to bee: "Just
BEE yourself!" hehehee ok so GOBBLES just be himself and hope public
understand he mean well and not here provide information to attacker
but to team bugtraq penetrator and vendor who help fix issue.

ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo

PRODUCT
*******

program: thttpd 2.20b (latest stable) and earlier
website: http://www.acme.com/software/thttpd/thttpd.html

SECURITY HISTORY
****************

Mr Bernstein disclose gaping hole in thttpd 2.04:

http://archives.neohapsis.com/archives/vuln-dev/1999-q4/0185.html

DiGiT disclose gaping hole in thttpd CGI application 'ssi':

http://packetstorm.decepticons.org/0005-exploits/ssibug

Other bug like '%2e%2e' directory traversal vulnerability also
disclosed to team bugtraq penetrator.

BACKGROUND
**********

GOBBLES members were in lab thinking about new way to punch hole in
Internet when we thought about how WWW need webserver or it be quite
useless hehe. So we start exploring possibility of webserver having
hole and come across thttpd as promising security. GOBBLES now prove
that promise broken. We did like so...

bash-2.05$ cd thttpd-2.20b
bash-2.05$ gtags
bash-2.05$ htags -van

... so we could then use web browser to navigate webserver src because
cscope just require much finger acrobatics he he he ;)

What follows is technical details of hole and you going to see how
mind of GOBBLES work to make critical program fall to its knees >:|

TECHNICAL DETAILS
*****************

bash-2.05$ pwd
/home/GOBBLES/hacking/projects/current/thttpd-2.20b
bash-2.05$ ls *.c
fdwatch.c       match.c         strerror.c      tdate_parse.c   timers.c
libhttpd.c      mmc.c           syslog.c        thttpd.c

Bug is in libhttpd.c/auth_check():

static int
auth_check( httpd_conn* hc, char* dirname  )
    {
    static char* authpath;
    static int maxauthpath = 0;
    struct stat sb;
    char authinfo[500];
    char* authpass;
[...]
    l = b64_decode( &(hc->authorization[6]), authinfo, sizeof(authinfo) );
    authinfo[l] = '\0';


Notice authinfo buffer and its total size (500) go b64_decode
function so username and password in HTTP header 'Authorization'
field may get decode from base64 for processing (processed by the
process hehehe >8^) ). Then notice auth_check() terminate authinfo
with a NUL. Notice only automatic variable above authinfo in source
code is stat structure 'sb' since 'static' qualifier make compiler
put variable in data or bss segment depending on
initialization. Variable 'l' get assigned result of b64_decode()
function. How big it can be??? GOBBLES paste full b64_decode
function...

static int
b64_decode( const char* str, unsigned char* space, int size )
    {
    const char* cp;
    int space_idx, phase;
    int d, prev_d = 0;
    unsigned char c;

    space_idx = 0;
    phase = 0;
    for ( cp = str; *cp != '\0'; ++cp )
        {
        d = b64_decode_table[(int) *cp];
        if ( d != -1 )
            {
            switch ( phase )
                {
                case 0:
                ++phase;
                break;
                case 1:
                c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) );
                if ( space_idx < size )
                    space[space_idx++] = c;
                ++phase;
                break;
                case 2:
                c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) );
                if ( space_idx < size )
                    space[space_idx++] = c;
                ++phase;
                break;
                case 3:
                c = ( ( ( prev_d & 0x03 ) << 6 ) | d );
                if ( space_idx < size )
                    space[space_idx++] = c;
                phase = 0;
                break;
                }
            prev_d = d;
            }
        }
    return space_idx;
    }

Notice formal argument 'size' come from sizeof(authinfo) == 500. Then
data stored in 'space' buffer which really 'authinfo' from other
function. The variable 'space_idx' set to 0 and incremented as it
used to index 'space' array. Size check "space_idx < size" mean
space_idx can only reach 499. But then "space[space_idx++] = c"
post-increment from 499 to 500. At end of function there is "return
space_idx". Moving back...

    l = b64_decode( &(hc->authorization[6]), authinfo,
    sizeof(authinfo) ); authinfo[l] = '\0';

It made 'l' == 500 so "authinfo[500] = '\0'" be made and buffer is
made overflow by one byte! THIS IS VERY BAD PROGRAMMING AND
PROGRAMMER MUST LEARN NOT TO DO THIS SILLY KIND BUGS. WHEN PEOPLE
LEARN?????

Exploitable? Yes. If compiler arrange 'authinfo' first on stack, then
on x86 machine it possible to overwrite saved register ebp value and
fuck over process like described by Olaf Kirch in 1998 team bugtraq
post which describe "Poison NUL Byte" method of punching hole in
software to get in computer.

DEMONSTRATION
*************

1) Apply following diff:

--- libhttpd.c  Tue Nov 20 14:50:00 2001
+++ libhttpd-new.c      Tue Nov 20 14:22:12 2001
@@ -886,6 +886,7 @@
     /* Decode it. */
     l = b64_decode( &(hc->authorization[6]), authinfo, sizeof(authinfo) );
     authinfo[l] = '\0';
+    printf("%02x\n", authinfo[499]); 
     /* Split into user and password. */
     authpass = strchr( authinfo, ':' );
     if ( authpass == (char*) 0 )

This allow us see what final element in array end up like.

2) Build and then:

[terminal 1]

mkdir test
echo "joe:blow" > test/.htpasswd
./thttpd -D -p 7777

[terminal 2] 

(printf "GET /test/ HTTP/1.0\r\nAuthorization: Basic " ; printf `perl
-e 'print "A"x550'` | openssl enc -base64 -e -in /dev/stdin ; printf
\ "\r\n\r\n") | nc 0 7777

[terminal 1]

We see '41'. This mean off-by-one overflow is really present!

EXPLOIT
*******

GOBBLES not release exploit until developer have time patch. Then it
safe to provide exploit for team bugtraq commercial penetrator
research community and so signature IDS vendor can add string for
gobbles-exploit.c (but maybe not catch gobbles-exploit2.c hehehee j/k
or other-exploit.c, but we provide enough information for IDS vendor
to separate string from exploit ;)))) )

GREETS
******

dianora, tsk, snow, carolyn meinel, john vranesevich, steve gibson,
kimble, emmanuel goldstein, box.sk, @stake, securityfocus,
blackhat.com, defcon.org, 2600.com, #phrack@efnet,
#hackphreak@undernet, bugtraq (thanks aleph1 and david ahmad for
devoting your time to a great list), ntbugtraq (russel the love
muscle ;D), cert.org, paul vixie, vesselin bontchev, reese
witherspoon, kirstin dunst, katie holmes, aleister crowley, all our
friends and family, and finally to everyone from #!GOBBLES on the irc.

GOBBLES SECURITY
http://www.bugtraq.org/
(7541025) /bugtraq <bugtraq@bugtraq.org>/-(Ombruten)
7563358 2001-11-23 01:03 +0000  /101 rader/ David Rude II <banned-it@fatelabs.com>
Sänt av: joel@lysator.liu.se
Importerad: 2001-11-24  00:57  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <19865>
Ärende: Re: Off-by-one vulnerability in thttpd!!!
------------------------------------------------------------
From: David Rude II <banned-it@fatelabs.com>
To: bugtraq@securityfocus.com
Message-ID: <20011123010333.12680.qmail@mail.securityfocus.com>

Mailer: SecurityFocus
In-Reply-To: <20011120150406.29986.qmail@tsunami.stormhosting.com>

I have been trying to recreate this kind of
situation with no luck. Below I will go into
detail as to why I beleive this is so. Yes there
is a off-by-one bof here. However I have doubts
about its exploitability.

>Bug is in libhttpd.c/auth_check():
>
>static int
>auth_check( httpd_conn* hc, char* dirname  )
>    {
>    static char* authpath;
>    static int maxauthpath = 0;
>    struct stat sb;
>    char authinfo[500];
>    char* authpass;
>[...]
>    l = b64_decode( &(hc->authorization[6]),
authinfo, sizeof(authinfo) );
>    authinfo[l] = '\0';
>
from what I can tell that struct seems to be on
the stack. If so this causing major problems in
trying to exploit this bug. Perhaps I'm wrong. Any
clarity is welcome.

>    l = b64_decode( &(hc->authorization[6]),
authinfo, sizeof(authinfo) );
>    authinfo[l] = '\0';
>
>It made 'l' == 500 so "authinfo[500] = '\0'" be
made and buffer is made
>overflow by one byte
I have been able to get this far but I get
different results. It looks like half the null is
going to the array and the other half somewhere
else. If I am wrong about the struct this could
mean exploitation but that would mean ebp would be
under control. I have yet to experience that.
 
>Exploitable? Yes. If compiler arrange 'authinfo'
first on stack, then on x86
>machine it possible to overwrite saved register
ebp value and fuck over
>process like described by Olaf Kirch in 1998 team
bugtraq post which
>describe "Poison NUL Byte" method of punching
hole in software to get in
>computer.
I have read that posting. It describes your run of
the mill off-by-one overflow. Which with the
testing I have done does not seem to be the case
in this situation. However I maybe wrong.

>2) Build and then:
>
>[terminal 1]
>
>mkdir test
>echo "joe:blow" > test/.htpasswd
>./thttpd -D -p 7777
>
>[terminal 2] 
>
>(printf "GET /test/ HTTP/1.0\r\nAuthorization:
Basic " ; printf `perl -e
>'print "A"x550'` | openssl enc -base64 -e -in
/dev/stdin ; printf "\r\n\r\n") | nc 0 7777
>
>[terminal 1]
>
>We see '41'. This mean off-by-one overflow is
really present!
>
This is where I get really confused. I have
debugged thttpd during a normal and accurate basic
authentication session and compaired the registers
to the buffer overflow authentication session. ebp
seems to be untouched. I maybe wrong yet again but
I have always thought no control over ebp means no
execution of arbitrary code.

If anyone else has had better luck recreating this
scenario please respond. I would enjoy any
comments or clarity.

banned-it
Fate Research Labs
IDS Division
--------------------------
[e] banned-it@fatelabs.com
[w] www.fatelabs.com
(7563358) /David Rude II <banned-it@fatelabs.com>/--