mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-10-01 12:07:46 +03:00
Fixed files overwriting in installer; added OWASP CRS.
This commit is contained in:
318
iis/ModSecurityIIS/owasp_crs/util/zap2modsec.pl
Normal file
318
iis/ModSecurityIIS/owasp_crs/util/zap2modsec.pl
Normal file
@@ -0,0 +1,318 @@
|
||||
#!/opt/local/bin/perl -T
|
||||
|
||||
#############################################
|
||||
# -=[ Virtual Patching Converter Script ]=- #
|
||||
# Converts OWASP ZAP XML Ouput #
|
||||
# https://code.google.com/p/zaproxy/ #
|
||||
# #
|
||||
# zap2modsec.pl #
|
||||
# Version: 1.0 #
|
||||
# #
|
||||
# Copyright 2011 #
|
||||
# Trustwave's SpiderLabs Research Team #
|
||||
# www.trustwave.com #
|
||||
# #
|
||||
# Based On Code Originally Created by: #
|
||||
# The Denim Group #
|
||||
# www.denimgroup.com #
|
||||
#############################################
|
||||
|
||||
use XML::Smart;
|
||||
use Switch;
|
||||
use Data::Types qw(:all);
|
||||
use Data::Validate::URI qw(is_uri);
|
||||
use Getopt::Std;
|
||||
use Acme::Comment type=>'C++', one_line=>1; #Block commenting, can be removed later
|
||||
|
||||
#############
|
||||
# Variables #
|
||||
#############
|
||||
|
||||
# [Configuration Vars]
|
||||
my %param;
|
||||
getopt("f",\%param);
|
||||
$filename = $param{f};
|
||||
my $all_vulnerabilities_filename = "$filename";
|
||||
|
||||
unless ($filename) {
|
||||
print "Flag:\n\n\t -f:\t path to ZAP xml report file\nUsage:\n\n\t./zap2modsec.pl -f ./zap_report.xml\n\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
my $modsec_rules_file = "./modsecurity_crs_48_virtual_patches.conf";
|
||||
|
||||
# [End Config Vars]
|
||||
|
||||
my $VULN_CLASS_XSS = "Cross Site Scripting";
|
||||
my $VULN_CLASS_SQLI = "SQL Injection";
|
||||
my $VULN_CLASS_SQLI_FINGERPRINT = "SQL Injection Fingerprinting";
|
||||
my $VULN_CLASS_LFI = "Path Traversal";
|
||||
my $VULN_CLASS_RFI = "Remote File Inclusion";
|
||||
my $VULN_CLASS_HTTPRS = "HTTP Response Splitting";
|
||||
|
||||
# Only the vulnerabilities in this array will have
|
||||
# rules generated for them.
|
||||
my @supported_vulns = ($VULN_CLASS_XSS, $VULN_CLASS_SQLI, $VULN_CLASS_SQLI_FINGERPRINT, $VULN_CLASS_LFI, $VULN_CLASS_RFI, $VULN_CLASS_HTTPRS);
|
||||
|
||||
my $num_rules_generated=0;
|
||||
my $num_not_supported=0;
|
||||
my $num_bad_urls=0;
|
||||
|
||||
my $wait_for_keypress=1;
|
||||
my $request_failed=0;
|
||||
|
||||
my $all_vulns_xml;
|
||||
my @type;
|
||||
my @id;
|
||||
my $vuln_count;
|
||||
|
||||
my $num_attacks_flag=0;
|
||||
my $num_attacks_noflag=0;
|
||||
|
||||
# End Vars ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
#############
|
||||
# Main #
|
||||
#############
|
||||
|
||||
# Clean up env so perl doesn't complain
|
||||
# when trying to run the restart snort
|
||||
# script.
|
||||
delete @ENV{qw(IFS CDPATH ENV BASH_ENV PATH)};
|
||||
|
||||
$all_vulns_xml = XML::Smart->new($all_vulnerabilities_filename);
|
||||
|
||||
@type = $all_vulns_xml->{OWASPZAPReport}{site}{alerts}{alertitem}('[@]','alert');
|
||||
@url = $all_vulns_xml->{OWASPZAPReport}{site}{alerts}{alertitem}('[@]','uri');
|
||||
@param = $all_vulns_xml->{OWASPZAPReport}{site}{alerts}{alertitem}('[@]','param');
|
||||
|
||||
open(my $MODSEC_RULES, '>' , $modsec_rules_file) || die "Unable to open modsecurity rules file $modsec_rules_file";
|
||||
$MODSEC_RULES->autoflush(1);
|
||||
|
||||
$vuln_count = 0;
|
||||
|
||||
foreach my $current_type (@type){
|
||||
print "==================================================================================================\n";
|
||||
print "Vulnerability[$vuln_count] - Type: $current_type\n";
|
||||
|
||||
if(exists {map { $_ => 1 } @supported_vulns}->{$current_type}){
|
||||
parseData(to_string($current_type));
|
||||
}else {
|
||||
print "Vulnerability Type: $type is not supported in this version.\n";
|
||||
$num_not_supported++;
|
||||
}
|
||||
$vuln_count++;
|
||||
}
|
||||
|
||||
close($MODSEC_RULES);
|
||||
|
||||
print "==================================================================================================\n";
|
||||
|
||||
print "\n\n************ END OF SCRIPT RESULTS *****************\n";
|
||||
print "Number of Vulnerabilities Processed: $vuln_count\n";
|
||||
print "Number of ModSecurity rules generated: $num_rules_generated\n";
|
||||
print "Number of Unsupported vulns skipped: $num_not_supported\n";
|
||||
print "Number of bad URLs (rules not gen): $num_bad_urls\n";
|
||||
print "****************************************************\n\n";
|
||||
print "----------------------------------------------------\n";
|
||||
print "To activate the virtual patching file ($modsec_rules_file),\n";
|
||||
print "copy it into the CRS \"base_rules\" directory and then create\n";
|
||||
print "a symlink to it in the \"activated_rules\" directory.\n";
|
||||
print "-----------------------------------------------------\n\n";
|
||||
|
||||
|
||||
###############
|
||||
# Subroutines #
|
||||
###############
|
||||
sub parseData
|
||||
{
|
||||
my($vuln_str) = @_;
|
||||
my $vuln_detail_filename;
|
||||
my $current_vuln_xml;
|
||||
my $current_vuln_url;
|
||||
my $current_vuln_param;
|
||||
my $current_uricontent;
|
||||
my @current_params;
|
||||
my $id = $vuln_count;
|
||||
|
||||
print "Found a $vuln_str vulnerability.\n";
|
||||
|
||||
$current_vuln_xml = XML::Smart->new($all_vulnerabilities_filename);
|
||||
$current_vuln_url = $url[$vuln_count];
|
||||
|
||||
print URL_LIST "$current_vuln_url\n";
|
||||
|
||||
# Validate url (need seperate sub?)
|
||||
print "Validating URL: $current_vuln_url\n";
|
||||
if(is_uri(to_string($current_vuln_url))){
|
||||
print "URL is well-formed\n";
|
||||
print "Continuing Rule Generation\n";
|
||||
} else {
|
||||
print "URL is NOT well-formed. Breaking Out of Rule Generation\n";
|
||||
$num_bad_urls++;
|
||||
|
||||
# Waits for keypress in test mode so you can
|
||||
# see why the URL failed validation.
|
||||
if($test_mode){
|
||||
wait_for_keypress();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$current_uricontent = get_uricontent($current_vuln_url);
|
||||
|
||||
|
||||
# Only need param if XSS attack,SQLINJ,XPATH
|
||||
# and maybe for HTTPRS, DT.
|
||||
# NOT for PRL and DI
|
||||
|
||||
if(($vuln_str ne $VULN_CLASS_PRL) && ($vuln_str ne $VULN_CLASS_DI)){
|
||||
@current_params = $param[$vuln_count];
|
||||
|
||||
}
|
||||
if(($vuln_str ne $VULN_CLASS_PRL) && ($vuln_str ne $VULN_CLASS_DI)){
|
||||
print "Current vulnerable Param(s): @current_params\n";
|
||||
}
|
||||
|
||||
generate_patch($vuln_str,$current_uricontent,@current_params);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub generate_patch
|
||||
{
|
||||
my($type,$uricontent,@params,$current_vuln_xml) = @_;
|
||||
my $rule = "";
|
||||
$id = "1".$vuln_count;
|
||||
|
||||
switch($type)
|
||||
{
|
||||
case ($VULN_CLASS_XSS)
|
||||
{
|
||||
if($uricontent ne "" && @params){
|
||||
foreach(@params){
|
||||
if($_ ne ""){
|
||||
# Check to see if each vulnerable parameter is valid
|
||||
# then generate a rule using both uricontent and the
|
||||
# parameter
|
||||
$rule = "SecRule REQUEST_FILENAME \"$uricontent\" \"chain,phase:2,t:none,block,msg:'Virtual Patch for $type',id:'$id',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'%{matched_var_name}',severity:'2'\"\n\tSecRule \&TX:\'\/XSS.*ARGS:$_\/\' \"\@gt 0\" \"setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score}\"";
|
||||
|
||||
print $MODSEC_RULES "#\n# OWASP ZAP Virtual Patch Details:\n# ID: $id\n# Type: $type\n# Vulnerable URL: $uricontent\n# Vulnerable Parameter: $_\n#\n".$rule."\n\n";
|
||||
print "$VULN_CLASS_XSS (uricontent and param) rule successfully generated and saved in $modsec_rules_file.\n";
|
||||
$num_rules_generated++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ($VULN_CLASS_SQLI)
|
||||
{
|
||||
|
||||
if($uricontent ne "" && @params){
|
||||
foreach(@params){
|
||||
if($_ ne ""){
|
||||
$rule = "SecRule REQUEST_FILENAME \"$uricontent\" \"chain,phase:2,t:none,block,msg:'Virtual Patch for $type',id:'$id',tag:'WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE1',tag:'PCI/6.5.2',logdata:'%{matched_var_name}',severity:'2'\"\n\tSecRule \&TX:\'\/SQL_INJECTION.*ARGS:$_\/\' \"\@gt 0\" \"setvar:'tx.msg=%{rule.msg}',setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score}\"";
|
||||
|
||||
print $MODSEC_RULES "#\n# OWASP ZAP Virtual Patch Details:\n# ID: $id\n# Type: $type\n# Vulnerable URL: $uricontent\n# Vulnerable Parameter: $_\n#\n".$rule."\n\n";
|
||||
print "$VULN_CLASS_SQLI (uricontent and param) rule successfully generated and saved in $modsec_rules_file.\n";
|
||||
$num_rules_generated++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ($VULN_CLASS_BLIND_SQLI)
|
||||
{
|
||||
|
||||
if($uricontent ne "" && @params){
|
||||
foreach(@params){
|
||||
if($_ ne ""){
|
||||
$rule = "SecRule REQUEST_FILENAME \"$uricontent\" \"chain,phase:2,t:none,block,msg:'Virtual Patch for $type',id:'$id',tag:'WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE1',tag:'PCI/6.5.2',logdata:'%{matched_var_name}',severity:'2'\"\n\tSecRule \&TX:\'\/SQL_INJECTION.*ARGS:$_\/\' \"\@gt 0\" \"setvar:'tx.msg=%{rule.msg}',setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score}\"";
|
||||
|
||||
print $MODSEC_RULES "#\n# OWASP ZAP Virtual Patch Details:\n# ID: $id\n# Type: $type\n# Vulnerable URL: $uricontent\n# Vulnerable Parameter: $_\n#\n".$rule."\n\n";
|
||||
print "$VULN_CLASS_SQLI (uricontent and param) rule successfully generated and saved in $modsec_rules_file.\n";
|
||||
$num_rules_generated++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ($VULN_CLASS_LFI)
|
||||
{
|
||||
if($uricontent ne "" && @params){
|
||||
foreach(@params){
|
||||
if($_ ne ""){
|
||||
$rule = "SecRule REQUEST_FILENAME \"$uricontent\" \"chain,phase:2,t:none,block,msg:'Virtual Patch for $type',id:'$id',tag:'WEB_ATTACK/LFI',tag:'WASCTC/WASC-33',logdata:'%{matched_var_name}',severity:'2'\"\n\tSecRule \&TX:\'\/LFI.*ARGS:$_\/\' \"\@gt 0\" \"setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score}\"";
|
||||
|
||||
print $MODSEC_RULES "#\n# OWASP ZAP Virtual Patch Details:\n# ID: $id\n# Type: $type\n# Vulnerable URL: $uricontent\n# Vulnerable Parameter: $_\n#\n".$rule."\n\n";
|
||||
print "$VULN_CLASS_LFI (uricontent and param) rule successfully generated and saved in $modsec_rules_file.\n";
|
||||
$num_rules_generated++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ($VULN_CLASS_RFI)
|
||||
{
|
||||
if($uricontent ne "" && @params){
|
||||
foreach(@params){
|
||||
if($_ ne ""){
|
||||
$rule = "SecRule REQUEST_FILENAME \"$uricontent\" \"chain,phase:2,t:none,block,msg:'Virtual Patch for $type',id:'$id',tag:'WEB_ATTACK/RFI',tag:'WASCTC/WASC-05',logdata:'%{matched_var_name}',severity:'2'\"\n\tSecRule \&TX:\'\/RFI.*ARGS:$_\/\' \"\@gt 0\" \"setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score}\"";
|
||||
|
||||
print $MODSEC_RULES "#\n# OWASP ZAP Virtual Patch Details:\n# ID: $id\n# Type: $type\n# Vulnerable URL: $uricontent\n# Vulnerable Parameter: $_\n#\n".$rule."\n\n";
|
||||
print "$VULN_CLASS_LFI (uricontent and param) rule successfully generated and saved in $modsec_rules_file.\n";
|
||||
$num_rules_generated++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ($VULN_CLASS_HTTPRS)
|
||||
{
|
||||
if($uricontent ne "" && @params){
|
||||
foreach(@params){
|
||||
if($_ ne ""){
|
||||
$rule = "SecRule REQUEST_FILENAME \"$uricontent\" \"chain,phase:2,t:none,block,msg:'Virtual Patch for $type',id:'$id',tag:'WEB_ATTACK/RESPONSE_SPLITTING',tag:'WASCTC/WASC-25',logdata:'%{matched_var_name}',severity:'2'\"\n\tSecRule \&TX:\'\/RESPONSE_SPLITTING.*ARGS:$_\/\' \"\@gt 0\" \"setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score}\"";
|
||||
|
||||
print $MODSEC_RULES "#\n# OWASP ZAP Virtual Patch Details:\n# ID: $id\n# Type: $type\n# Vulnerable URL: $uricontent\n# Vulnerable Parameter: $_\n#\n".$rule."\n\n";
|
||||
print "$VULN_CLASS_RFI (uricontent and param) rule successfully generated and saved in $modsec_rules_file.\n";
|
||||
$num_rules_generated++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sub get_uricontent
|
||||
{
|
||||
my($url) = @_;
|
||||
my $regex = "http:\/\/+[a-zA-Z0-9.:-]*\/";
|
||||
|
||||
# First, trim the first part out of the URL:
|
||||
# http://.../
|
||||
$url =~ /$regex/;
|
||||
substr($url,index($url,$&),length($&)) = "";
|
||||
|
||||
# If the URL contains a php or cgi query with
|
||||
# one or more params and values, trim those out.
|
||||
# Trim from the question mark to the end.
|
||||
if($url =~ /\?/){
|
||||
substr($url,index($url,"?")) = "";
|
||||
}
|
||||
return $url;
|
||||
|
||||
}
|
Reference in New Issue
Block a user