#!/usr/bin/perl # q(uick)audit.pl: portable src auditing tool -- designed in perl5. [id: 6931b] # q(uick)audit.pl: version[02] -- by: vade79[v9@fakehalo.org] :www.fakehalo.org. # # this script/application is for quickly auditing code via .c/.cc source files. # it checks for standard stack/heap overflows, format bugs, exec calls, env vars # and misc. functions related to possible security issues. this may not always # be the best way to go about auditing, since it is not as good as doing it by # hand - but, i've found it to be rather useful for simple auditing. # # use: "./qaudit.pl" :: for interface qaudit. # use: "./qaudit.pl ..." :: for direct qaudit. # (1/4):presets. $ansi=1; # change this to 0 if you dont want ansi codes. @misc_grep=('sprintf','strcpy','strcat','scanf','gets','malloc'); # scan + "(". @type=('BOF_CHK','FMT_CHK','EXE_CHK','ENV_CHK','MSC_CHK');$prompt="qaudit>"; # (2/4):subroutines. sub outn{print STDERR "${bld}$srcfile:*NOTICE:${reg}@_";} sub outb{print STDERR "${bld}$srcfile:$type[0]:".($l+2).":${reg}@_";} sub outf{print STDERR "${bld}$srcfile:$type[1]:".($l+2).":${reg}@_";} sub oute{print STDERR "${bld}$srcfile:$type[2]:".($l+2).":${reg}@_";} sub outev{print STDERR "${bld}$srcfile:$type[3]:".($l+2).":${reg}@_";} sub outm{print STDERR "${bld}$srcfile:$type[4]:".($l+2).":${reg}@_";} sub outerror{print STDERR "${bld}ERROR:${reg}@_";} sub line{print STDERR "${bld}" . "-"x80 . "${reg}\n";} sub clean_line{ my $b=0,$tmpstring=shift; while((ord(substr($tmpstring,$b,1))==9||ord(substr($tmpstring,$b,1))==32)&&substr($tmpstring,$b,1)){$b++;} return substr($tmpstring,$b,(length($tmpstring)-$b)); } sub bounds_scan{ if(!@source||!$srcfile){&outerror("${bld}*:${reg} no source file set. (no data)\n");} else{ &outn("${bld}START: entering bounds check mode.${reg}\n"); undef $chars,$schars,$fc;my @c,@tmpc,$i,$fc,$chars,@schars;$l=0; while($source[$l]){ if($source[$l]=~"char"&&$source[$l]=~"\\["&&$source[$l]=~"\\]"){ $i=0;@c=split(/\[/,$source[$l]); while($c[$i]){ @tmpc=split(/ /,$c[$i]); $fc=$tmpc[($tmpc-1)];$fc=~s/\[//g;$fc=~s/\]//g;$fc=~s/\(//g; $fc=~s/\)//g;$fc=~s/\{//g;$fc=~s/\}//g;$fc=~s/\*//g;$fc=~s/\|//g; $fc=~s/\&//g;$fc=~s/\t//g;$fc=~s/\r//g;$fc=~s/\n//g; if($tmpc[($tmpc-1)]eq$fc){ if(!($chars=~$fc)){ if($chars){$chars="$chars $fc";} else{$chars=$fc;} } } $i++; } } $l++; } if($chars){&outn("${bld}INFO: character array(s) to scan: $chars.${reg}\n");} @schars=split(/ /,$chars);$i=0; while($schars[$i]){ $l=0;while($source[$l]){ if($source[$l]=~$schars[$i]){&outb("${bld}$schars[$i]:${reg} ".&clean_line($source[$l]));} $l++; } $i++; } &outn("${bld}STOP: exiting bounds check mode.${reg}\n"); } } sub format_scan{ if(!@source||!$srcfile){&outerror("${bld}*:${reg} no source file set. (no data)\n");} else{ &outn("${bld}START: entering format bug check mode.${reg}\n"); $l=0;while($source[$l]){ if(($source[$l]=~"printf\\("&&!($source[$l]=~"\"")&&!($source[$l]=~"\'")&&!($source[$l]=~"sprintf"&&!($source[$l]=~"nprintf")))&&$source[$l]=~"\\("){ &outf("${bld}WARNING:${reg} ".&clean_line($source[$l])); } elsif(($source[$l]=~"vprintf"||$source[$l]=~"vsprintf"||$source[$l]=~"vfprintf")&&$source[$l]=~"\\("){ &outf("${bld}WARNING:${reg} ".&clean_line($source[$l])); } $l++; } &outn("${bld}STOP: exiting format bug check mode.${reg}\n"); } } sub exec_scan{ if(!@source||!$srcfile){&outerror("${bld}*:${reg} no source file set. (no data)\n");} else{ &outn("${bld}START: entering exec check mode.${reg}\n"); $l=0;while($source[$l]){ if(($source[$l]=~"system"||$source[$l]=~"exec"||$source[$l]=~"popen")&&$source[$l]=~"\\("){ &oute("${bld}WARNING:${reg} ".&clean_line($source[$l])); } $l++; } &outn("${bld}STOP: exiting exec check mode.${reg}\n"); } } sub env_scan{ if(!@source||!$srcfile){&outerror("${bld}*:${reg} no source file set. (no data)\n");} else{ &outn("${bld}START: entering environmental variable check mode.${reg}\n"); $l=0;while($source[$l]){ if(($source[$l]=~"getenv"||$source[$l]=~"setenv"||$source[$l]=~"putenv")&&$source[$l]=~"\\("){ &outev("${bld}WARNING:${reg} ".&clean_line($source[$l])); } $l++; } &outn("${bld}STOP: exiting environmental variable check mode.${reg}\n"); } } sub misc_scan{ if(!@source||!$srcfile){&outerror("${bld}*:${reg} no source file set. (no data)\n");} else{ &outn("${bld}START: entering miscellaneous check mode.${reg}\n"); my $k;$l=0;while($source[$l]){ $k=0;while($misc_grep[$k]){ if($source[$l]=~$misc_grep[$k]&&$source[$l]=~"\\("){&outm("${bld}WARNING:${reg} ".&clean_line($source[$l]));} $k++; } $l++; } &outn("${bld}STOP: exiting miscellaneous check mode.${reg}\n"); } } sub read_file{ my $tmpsrcfile;$srcfile=shift;if(!-f$srcfile){undef $srcfile;} open(SOURCE,$srcfile);$sc=;@source=; close(SOURCE);@tmpsrcfile=split(/\//,$srcfile); if($tmpsrcfile[($tmpsrcfile)-1]){$srcfile=$tmpsrcfile[($tmpsrcfile)-1];} } sub audit_file{ &read_file(shift);&line();&format_scan();&bounds_scan(); &exec_scan();&env_scan();&misc_scan();&line(); } sub new_file{ my $tmpsrcfile=shift;undef $srcfile,@source; if(substr($tmpsrcfile,(length($tmpsrcfile)-2),2)ne".c" &&substr($tmpsrcfile,(length($tmpsrcfile)-3),3)ne".cc"){print "${bld}invalid source file: $tmpsrcfile.${reg}\n";} elsif(!-f$tmpsrcfile){&outerror("${bld}*:${reg} no such file: $tmpsrcfile.\n");} else{&audit_file($tmpsrcfile);} } # (3/4):init. if($ansi){$bld="\x1b[1;37m";$reg="\x1b[0m";} printf "${bld}qaudit.pl::q\(uick\)audit: version[02]. by: vade79[v9\@fakehalo.org].${reg}\n"; &line();sleep(1); if(!$ARGV[0]){ my $input,@trunc,$tmpsrcfile; while(1){ print STDERR "${bld}$prompt${reg} "; $input=;chomp $input; @trunc=split(/ /,$input); if(substr($trunc[0],0,1)eq"f"){ if(!$trunc[1]){print "${bld}file syntax: file .${reg}\n";} else{ $tmpsrcfile=$trunc[1]; if(substr($tmpsrcfile,(length($tmpsrcfile)-2),2)ne".c" &&substr($tmpsrcfile,(length($tmpsrcfile)-3),3)ne".cc"){print "${bld}invalid source file: $tmpsrcfile.${reg}\n";undef $tmpsrcfile;} elsif(-f$tmpsrcfile){print "${bld}source file set to: $tmpsrcfile.${reg}\n";} else{print "${bld}no such file: $tmpsrcfile.${reg}\n";undef $tmpsrcfile;} } } elsif(substr($trunc[0],0,1)eq"a"){ if(-f$tmpsrcfile){ print "${bld}executing audit on: $tmpsrcfile${reg}\n"; &new_file($tmpsrcfile); } else{print "${bld}no file has been selected to audit, use \"file\".${reg}\n";} } elsif(substr($trunc[0],0,1)eq"e"){print "${bld}exiting qaudit.${reg}\n";exit(0);} else{print "${bld}interface commands: file audit exit.${reg}\n";} } } else{ $a=0;while($ARGV[$a]){&new_file($ARGV[$a]);$a++;} } print "${bld}exiting qaudit.${reg}\n";exit(0); # (4/4):eof.