5564326 2000-10-08  22:03  /66 rader/ Brevbäraren (som är implementerad i) Python
Mottagare: Bugtraq (import) <13153>
Ärende: sendmail -bt negative index bug...
------------------------------------------------------------
From: Michal Zalewski <lcamtuf@DIONE.IDS.PL>
To: BUGTRAQ@SECURITYFOCUS.COM
Message-ID: <Pine.LNX.4.10.10010081417330.1498-100000@localhost>

This problem, AFAIK, affects all known Sendmail
releases. Exploitability has been not proven, so no need to be afraid
(for now ;).

[ Btw: I'm looking for a good job - http://lcamtuf.hack.pl/job.html ]

Sendmail, launched with -bt command-line switch, enters it's special
"address test" mode. It is not dropping root privledges (why?), and
accepting user-supplied input. Several commands provided in this mode
had broken implementation. One of the most serious bugs is missing
check before calling setclass() functions. I discovered it while
playing with sendmail binary (well, .C{a_lot_of_As}something exited
with SEGV, and I thought it's an overflow ;). Unfortunately, it
appeared to be missing return condition before calling setclass(),
which caused this macro to be called with negative index value
(-1). But hey... Well, I played a little bit more, and found simple
.Cxval commands (x == one-character class name) are handled
differently from .C{name}val commands. In first case, class number
passed to setclass() is equal to numerical value of character
representing macro name. Why - well, see the implementation, idea
wasn't bad - but using signed char value to index positive-indexed
table (0..255) wasn't really good idea. I tried another trick -
.Cósomething (where 'ó' was the class name). And yes - success! This
time, as 'ó' character, stored as signed (default on eg. Linux boxes)
character, was equal to -13:

Program received signal SIGSEGV, Segmentation fault.
0x80828ea in setclass (class=-13, str=0xbfffdf7c "s") at readcf.c:2803
2803                    setbitn(class, s->s_class);

See...

#define _BITWORD(bit)   ((bit) / (BYTEBITS * sizeof (int)))
#define _BITBIT(bit)    ((unsigned int)1 << ((bit) % (BYTEBITS * sizeof (int))))

/* set bit number N */
#define setbitn(bit, map)       (map)[_BITWORD(bit)] |= _BITBIT(bit)

So, after parsing, we have:

  s->s_class[-4] |= 524288;

What can I say? As there's no range checking in C, negative indexes
just so dangerous as excessive indexes (aka buffer overflows ;)! I
don't want to speculate on exploitability of this code (you have to
examine if there's something interesting in memory after specific
array, and, eventually, look for other bugs of this type, eg. in .D
commands), but I'm affraid negative index bugs are too often
overlooked or ignored:

-- demo.c --
main() {
  int test[10];
  char text[5]="test";
  test[-2]=0x6b636168;
  puts(text);
}
-- EOF --

Regards,
_______________________________________________________
Michal Zalewski [lcamtuf@tpi.pl] [tp.internet/security]
[http://lcamtuf.na.export.pl] <=--=> bash$ :(){ :|:&};:
=-----=> God is real, unless declared integer. <=-----=
(5564326) ------------------------------------------(Ombruten)