TUCoPS :: BSD :: fbsbufov.txt

FreeBSD Buffer overflows in fts, du, and find in FreeBSD 2.2.7/2.2.8.


[ http://www.rootshell.com/ ]

Date: Wed, 12 May 1999 14:32:42 +0400
From: Stas Kisel <stas@SONET.CRIMEA.UA>
To: BUGTRAQ@netspace.org
Subject: fts, du, find

Hi.

I use FreeBSD-2.2.8 and FreeBSD-2.2.7 and I know that these versions are
no longer supported, but:
1. There are many people still using 2.2
2. This bug probably applies to FreeBSD-3.1 and ever to OpenBSD and other.

Approximately a month ago I've found a very strange behaviour of 'du'
with long direstory structures. I left this alone due to lack of time,
but some days ago I saw an article on bugtraq concerning similar
behaviour of 'find'.

There is a one bug in libc causing this behaviour. I have a patch, but
I did not tested it much ;)

Both 'find' and 'du' use 'fts' (fts_read,...) functions to traverse
directory structure.
fts uses realloc() to reallocate memory in quite complex lists.
There is a bug in adjusting pointers after realloc().
So when dealing with large directory structures (when realloc() needed),
some pointers can point to free()-ed memory.

I have no exploit and probably will no have a free time (I think
3 days is more than enough) for doing it, but I beleive it is
possible to exploit this bug using carefully designed directory
tree to execute arbitrary commands as root during
/etc/daily->/etc/security->find.
REMOTE ROOT EXPLOIT (POSSIBLE).
At least it is possible to hide setuid binary this way in home dir or in /tmp.

The following patch is designed for FreeBSD-2.2.8-RELEASE libc.
There was the following ID in the beginning of the source file.
/*      $OpenBSD: fts.c,v 1.9 1997/08/02 00:13:49 millert Exp $ */
I've only tested this patch on one machine during one day, so
it is probably buggy.
If you'll apply this patch, please drop me a line if there was any side effect
and I'll do a followup in the bugtraq, say, on the Friday.

------------------ patch ----------------------------------------
--- /usr/src/lib/libc/gen/fts.c.orig    Tue May 11 13:37:49 1999
+++ /usr/src/lib/libc/gen/fts.c Wed May 12 13:16:08 1999
@@ -740,8 +740,26 @@
         * If had to realloc the path, adjust the addresses for the rest
         * of the tree.
         */
-       if (adjaddr)
+       if (adjaddr){
                fts_padjust(sp, adjaddr);
+               /* Adjust the list, because we want to return it robust. */
+/* fix p->fts_path and p->fts_accpath
+   p->fts_accpath can be:
+       either cur->fts_path    (adjust, because cur is already adjusted)
+       either p->fts_path      (adjust)
+       either p->fts_name      (do not adjust)
+   I'm also almost sure that in first case cur->fts_path=p->fts_path...
+*/
+#define        ADJUST1(p) if((p)->fts_path != adjaddr){        \
+       if((p)->fts_accpath != (p)->fts_name){          \
+               (p)->fts_accpath =                      \
+                       (char *)adjaddr + ((p)->fts_accpath - (p)->fts_path);\
+       }                                               \
+       (p)->fts_path = adjaddr;                        \
+}
+               for (p = head; p; p = p->fts_link)
+                       ADJUST1(p);
+       }

        /*
         * If not changing directories, reset the path back to original
@@ -974,18 +992,18 @@
 {
        FTSENT *p;

-#define        ADJUST(p) {                                                     \
+#define        ADJUST2(p) {                                                    \
        (p)->fts_accpath =                                              \
            (char *)addr + ((p)->fts_accpath - (p)->fts_path);          \
        (p)->fts_path = addr;                                           \
 }
        /* Adjust the current set of children. */
        for (p = sp->fts_child; p; p = p->fts_link)
-               ADJUST(p);
+               ADJUST2(p);

        /* Adjust the rest of the tree. */
        for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
-               ADJUST(p);
+               ADJUST2(p);
                p = p->fts_link ? p->fts_link : p->fts_parent;
        }
 }
------------------ endpatch ----------------------------------------

--
Stas Kisel
Open Tavrical College           Sysadmin        stas@sonet.crimea.ua
Simferopol State University     Web-designer    stas@ccssu.crimea.ua

------------------------------------------------------------------------------------------

Date: Fri, 14 May 1999 04:33:34 -0400
From: Jordan Ritter <jpr5@DARKRIDGE.COM>
To: BUGTRAQ@netspace.org
Subject: Re: fts, du, find

On Wed, 12 May 1999, Stas Kisel wrote:

> 2. This bug probably applies to FreeBSD-3.1 and ever to OpenBSD and other.

I found this back a few months ago when working on the wu-ftp stuff..
OpenBSD definitely has the same problem.  last thing I remember thinking
was that it was dying because realloc() was failing (as the fts stuff
realloc()'s memory as the path grows) ..



Jordan Ritter
Network Security Engineer
Netect/Bindview Corp  Boston, MA

"Quis custodiet ipsos custodes?"

------------------------------------------------------------------------------------------

Date: Fri, 14 May 1999 14:37:03 +0400
From: Stas Kisel <stas@SONET.CRIMEA.UA>
To: BUGTRAQ@netspace.org
Subject: Re: fts...(improved patch)

> From: Jordan Ritter <jpr5@darkridge.com>
> OpenBSD definitely has the same problem.  last thing I remember thinking
> was that it was dying because realloc() was failing (as the fts stuff
> realloc()'s memory as the path grows) ..

fts realloc (pathlen+~1000b) of memory only, so realloc succeds.
The bug is in the adjusting pointers after realloc().

Next day after sending patch I've found another circumstanses that
triggered similar bug in fts.
This time some pointers were adjusted which did not belong to realloc()-ed
memory chunk.

Improved patch is below. Sorry for inconvenience.
Probably there are some similar bugs in fts code or patch. Please let me
know if you'll see any.

\bye
Stas

----------------------------- patch ----------------------------------
--- /usr/src/lib/libc/gen/fts.c.orig    Tue May 11 13:37:49 1999
+++ /usr/src/lib/libc/gen/fts.c Fri May 14 14:02:58 1999
@@ -740,8 +740,26 @@
         * If had to realloc the path, adjust the addresses for the rest
         * of the tree.
         */
-       if (adjaddr)
+       if (adjaddr){
                fts_padjust(sp, adjaddr);
+               /* Adjust the list, because we want to return it robust. */
+/* fix p->fts_path and p->fts_accpath
+   p->fts_accpath can be:
+       either cur->fts_path    (adjust, because cur is already adjusted)
+       either p->fts_path      (adjust)
+       either p->fts_name      (do not adjust)
+   I'm also almost sure that in first case cur->fts_path=p->fts_path...
+*/
+#define        ADJUST1(p) if((p)->fts_path != adjaddr){        \
+       if((p)->fts_accpath != (p)->fts_name){          \
+               (p)->fts_accpath =                      \
+                       (char *)adjaddr + ((p)->fts_accpath - (p)->fts_path);\
+       }                                               \
+       (p)->fts_path = adjaddr;                        \
+}
+               for (p = head; p; p = p->fts_link)
+                       ADJUST1(p);
+       }

        /*
         * If not changing directories, reset the path back to original
@@ -974,18 +992,20 @@
 {
        FTSENT *p;

-#define        ADJUST(p) {                                                     \
-       (p)->fts_accpath =                                              \
-           (char *)addr + ((p)->fts_accpath - (p)->fts_path);          \
+#define        ADJUST2(p) {                                                    \
+       if((p)->fts_accpath != (p)->fts_name){                          \
+               (p)->fts_accpath =                                      \
+                   (char *)addr + ((p)->fts_accpath - (p)->fts_path);  \
+       }                                                               \
        (p)->fts_path = addr;                                           \
 }
        /* Adjust the current set of children. */
        for (p = sp->fts_child; p; p = p->fts_link)
-               ADJUST(p);
+               ADJUST2(p);

        /* Adjust the rest of the tree. */
        for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
-               ADJUST(p);
+               ADJUST2(p);
                p = p->fts_link ? p->fts_link : p->fts_parent;
        }
 }
----------------------------- /patch ----------------------------------

------------------------------------------------------------------------------------------

Date: Fri, 14 May 1999 19:14:02 +0200
From: Przemyslaw Frasunek <venglin@GADACZKA.DHS.ORG>
Reply-To: venglin@lagoon.freebsd.org.pl
To: BUGTRAQ@netspace.org
Subject: Re: fts, du, find

> 2. This bug probably applies to FreeBSD-3.1 and ever to OpenBSD and other.

Yes, I've tested it on 3.1-STABLE.

> I have no exploit and probably will no have a free time (I think
> 3 days is more than enough) for doing it, but I beleive it is
> possible to exploit this bug using carefully designed directory
> tree to execute arbitrary commands as root during
> /etc/daily->/etc/security->find.
> REMOTE ROOT EXPLOIT (POSSIBLE).

I think, that it will be hard to write an exploit. I've tested it on
my 2.2.8-RELEASE at home.

'Find' segfaults, when it tries to do:

  (void)puts(entry->fts_path);

because of junk pointer to structure 'entry'. IMHO it _always_
points to 0x200291d6, so it tries to execute (IMHO) _always_ the
same commands:

0x200291d6 <puts+34>:   repnz scasb %es:(%edi),%al
0x200291d7 <puts+35>:   scasb  %es:(%edi),%al
0x200291d8 <puts+36>:   movl   %ecx,%eax
0x200291d9 <puts+37>:   enter  $0xd0f7,$0x89
0x200291da <puts+38>:   notl   %eax
0x200291db <puts+39>:   rorb   0x488de455(%ecx)
0x200291dc <puts+40>:   movl   %edx,0xffffffe4(%ebp)
0x200291dd <puts+41>:   pushl  %ebp
0x200291de <puts+42>:   inb    $0x8d,%al
0x200291df <puts+43>:   leal   0xffffffff(%eax),%ecx
0x200291e0 <puts+44>:   decl   %eax
0x200291e1 <puts+45>:   decl   0x938de84d(%ecx)
0x200291e2 <puts+46>:   movl   %ecx,0xffffffe8(%ebp)
0x200291e3 <puts+47>:   decl   %ebp
0x200291e4 <puts+48>:   call   0xc1532576 <end+2705991902>

and here it segfaults.

--
* Fido: 2:480/124 ** WWW: lagoon.freebsd.org.pl/~venglin ** GSM:48-601-383657 *
* Inet: venglin@lagoon.freebsd.org.pl ** PGP:D48684904685DF43EA93AFA13BE170BF *


TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH