$markerline )
{ //for each line in the file
if (strpos($markerline, '# BEGIN ' . $section) !== false)
{ //if we're at the beginning of the section
$state = false;
}
if ($state == true)
{ //as long as we're not in the section keep writing
fwrite($f, trim($markerline) . PHP_EOL);
}
if (strpos($markerline, '# END ' . $section) !== false)
{ //see if we're at the end of the section
$state = true;
}
}
@fclose($f);
return 1;
}
return 1;
}
static function getrules()
{
$rules = "";
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_block_wp_file_access();
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_basic_htaccess();
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_blacklist();
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_disable_trace_and_track();
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_forbid_proxy_comment_posting();
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_deny_bad_query_strings();
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_advanced_character_string_filter();
$rules .= AIOWPSecurity_Utility_Htaccess::getrules_5g_blacklist();
//TODO: The following utility functions are ready to use when we write the menu pages for these features
//Add more functions for features as needed
//$rules .= AIOWPSecurity_Utility_Htaccess::getrules_somefeature();
//Add outer markers if we have rules
if ($rules != '')
{
$rules = "# BEGIN All In One WP Security" . PHP_EOL . $rules . "# END All In One WP Security" . PHP_EOL;
}
return $rules;
}
/*
* This function will write rules to prevent people from accessing the following files:
* readme.html, license.txt and wp-config-sample.php.
*/
static function getrules_block_wp_file_access()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_prevent_default_wp_file_access')=='1')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$prevent_wp_file_access_marker_start . PHP_EOL; //Add feature marker start
$rules .= '
order allow,deny
deny from all
order allow,deny
deny from all
order allow,deny
deny from all
' . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$prevent_wp_file_access_marker_end . PHP_EOL; //Add feature marker end
}
return $rules;
}
static function getrules_blacklist()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$aiowps_server = AIOWPSecurity_Utility_Htaccess::get_server_type();
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_enable_blacklisting')=='1')
{
//Let's do the list of blacklisted IPs first
$hosts = explode(PHP_EOL, $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'));
if (!empty($hosts) && !(sizeof($hosts) == 1 && trim($hosts[0]) == ''))
{
if ( $aiowps_server == 'apache' || $aiowps_server == 'litespeed' )
{
$rules .= AIOWPSecurity_Utility_Htaccess::$ip_blacklist_marker_start . PHP_EOL; //Add feature marker start
$rules .= "Order allow,deny" . PHP_EOL .
"Allow from all" . PHP_EOL;
}
$phosts = array();
foreach ($hosts as $host)
{
$host = trim($host);
if (!in_array($host, $phosts))
{
if (strstr($host, '*'))
{
$parts = array_reverse (explode('.', $host));
$netmask = 32;
foreach ($parts as $part)
{
if (strstr(trim($part), '*'))
{
$netmask = $netmask - 8;
}
}
$dhost = trim( str_replace('*', '0', implode( '.', array_reverse( $parts ) ) ) . '/' . $netmask );
if (strlen($dhost) > 4)
{
if ($aiowps_server == 'apache' || $aiowps_server == 'litespeed')
{
$trule = "Deny from " . $dhost . PHP_EOL;
if (trim($trule) != 'Deny From')
{
$rules .= $trule;
}
}
else
{
$rules .= "\tdeny " . $dhost . ';' . PHP_EOL;
}
}
}
else
{
$dhost = trim( $host );
if (strlen($dhost) > 4)
{
if ($aiowps_server == 'apache' || $aiowps_server == 'litespeed' )
{
$rules .= "Deny from " . $dhost . PHP_EOL;
}
else
{
$rules .= "\tdeny " . $dhost. ";" . PHP_EOL;
}
}
}
}
$phosts[] = $host;
}
$rules .= AIOWPSecurity_Utility_Htaccess::$ip_blacklist_marker_end . PHP_EOL; //Add feature marker end
}
//Now let's do the user agent list
$user_agents = explode(PHP_EOL, $aio_wp_security->configs->get_value('aiowps_banned_user_agents'));
if (!empty($user_agents) && !(sizeof($user_agents) == 1 && trim($user_agents[0]) == ''))
{
if ($aiowps_server == 'apache' || $aiowps_server == 'litespeed')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$user_agent_blacklist_marker_start . PHP_EOL; //Add feature marker start
//Start mod_rewrite rules
$rules .= "" . PHP_EOL . "RewriteEngine On" . PHP_EOL . PHP_EOL;
$count = 1;
foreach ( $user_agents as $agent )
{
$rules .= "RewriteCond %{HTTP_USER_AGENT} ^" . trim( $agent );
if ( $count < sizeof( $user_agents ) )
{
$rules .= " [NC,OR]" . PHP_EOL;
$count++;
}
else
{
$rules .= " [NC]" . PHP_EOL;
}
}
$rules .= "RewriteRule ^(.*)$ - [F,L]" . PHP_EOL . PHP_EOL;
}
else
{
$count = 1;
$alist = '';
foreach ( $user_agents as $agent )
{
$alist .= trim( $agent );
if ( $count < sizeof( $user_agents ) )
{
$alist .= '|';
$count++;
}
}
$rules .= "\tif (\$http_user_agent ~* " . $alist . ") { return 403; }" . PHP_EOL;
}
}
//close mod_rewrite
if (strlen($aio_wp_security->configs->get_value('aiowps_banned_user_agents')) > 0)
{
if (($aiowps_server == 'apache' || $aiowps_server == 'litespeed'))
{
$rules .= "" . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$user_agent_blacklist_marker_end . PHP_EOL; //Add feature marker end
}
}
}
return implode( PHP_EOL, array_diff( explode( PHP_EOL, $rules ), array( 'Deny from ', 'Deny from' ) ) );
}
/*
* TODO - info
*/
static function getrules_basic_htaccess()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_enable_basic_firewall')=='1')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$basic_htaccess_rules_marker_start . PHP_EOL; //Add feature marker start
//limit indexing of directories
$rules .= 'Options All -Indexes' . PHP_EOL;
//protect the htaccess file - this is done by default with apache config file but we are including it here for good measure
$rules .= '' . PHP_EOL;
$rules .= 'order allow,deny' . PHP_EOL;
$rules .= 'deny from all' . PHP_EOL;
$rules .= '' . PHP_EOL;
//disable the server signature
$rules .= 'ServerSignature Off' . PHP_EOL;
//limit file uploads to 10mb
$rules .= 'LimitRequestBody 10240000' . PHP_EOL;
// protect wpconfig.php.
$rules .= '' . PHP_EOL;
$rules .= 'order allow,deny' . PHP_EOL;
$rules .= 'deny from all' . PHP_EOL;
$rules .= '' . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$basic_htaccess_rules_marker_end . PHP_EOL; //Add feature marker end
}
return $rules;
}
/*
* This function will write rules to disable trace and track.
* HTTP Trace attack (XST) can be used to return header requests
* and grab cookies and other information and is used along with
* a cross site scripting attacks (XSS)
*/
static function getrules_disable_trace_and_track()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_disable_trace_and_track')=='1')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$disable_trace_track_marker_start . PHP_EOL; //Add feature marker start
$rules .= 'RewriteEngine On' . PHP_EOL;
$rules .= 'RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)' . PHP_EOL;
$rules .= 'RewriteRule .* - [F]' . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$disable_trace_track_marker_end . PHP_EOL; //Add feature marker end
}
return $rules;
}
/*
* This function will write rules to prevent proxy comment posting.
* This will deny any requests that use a proxy server when posting
* to comments eliminating some spam and proxy requests, script
* courtesy of perishablepress.com
*/
static function getrules_forbid_proxy_comment_posting()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_forbid_proxy_comments')=='1')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$forbid_proxy_comments_marker_start . PHP_EOL; //Add feature marker start
$rules .= 'RewriteCond %{REQUEST_METHOD} =POST' . PHP_EOL;
$rules .= 'RewriteCond %{HTTP:VIA}%{HTTP:FORWARDED}%{HTTP:USERAGENT_VIA}%{HTTP:X_FORWARDED_FOR}%{HTTP:PROXY_CONNECTION} !^$ [OR]' . PHP_EOL;
$rules .= 'RewriteCond %{HTTP:XPROXY_CONNECTION}%{HTTP:HTTP_PC_REMOTE_ADDR}%{HTTP:HTTP_CLIENT_IP} !^$' . PHP_EOL;
$rules .= 'RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]' . PHP_EOL;
$rules .= 'RewriteRule .* - [F,NS,L]' . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$forbid_proxy_comments_marker_end . PHP_EOL; //Add feature marker end
}
return $rules;
}
/*
* This function will write rules to prevent malicious string attacks on your site using XSS.
* NOTE: Some of these strings might be used for plugins or themes and doing so will disable the functionality.
* This script is from perishablepress and is fairly safe to use and should not break anything important
*/
//TODO - the currently commented out rules (see function below) break the site - need to investigate why or if we can tweak the rules a bit
static function getrules_deny_bad_query_strings()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_deny_bad_query_strings')=='1')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$deny_bad_query_strings_marker_start . PHP_EOL; //Add feature marker start
$rules .= 'RewriteCond %{QUERY_STRING} ../ [NC,OR]' . PHP_EOL;
//$rules .= 'RewriteCond %{QUERY_STRING} boot.ini [NC,OR]' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} tag= [NC,OR]' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} ftp: [NC,OR]' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} http: [NC,OR]' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} https: [NC,OR]' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} mosConfig [NC,OR]' . PHP_EOL;
//$rules .= 'RewriteCond %{QUERY_STRING} ^.*([|]|(|)||\'|"|;|?|*).* [NC,OR]' . PHP_EOL;
//$rules .= 'RewriteCond %{QUERY_STRING} ^.*(%22|%27|%3C|%3E|%5C|%7B|%7C).* [NC,OR]' . PHP_EOL;
//$rules .= 'RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F|127.0).* [NC,OR]' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} ^.*(globals|encode|config|localhost|loopback).* [NC,OR]' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} ^.*(request|select|insert|union|declare|drop).* [NC]' . PHP_EOL;
$rules .= 'RewriteRule ^(.*)$ - [F,L]' . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$deny_bad_query_strings_marker_end . PHP_EOL; //Add feature marker end
}
return $rules;
}
/*
* This function will write rules to produce an advanced character string filter to prevent malicious string attacks from Cross Site Scripting (XSS)
* NOTE: Some of these strings might be used for plugins or themes and doing so will disable the functionality.
* This script is from perishablepress and is fairly safe to use and should not break anything important
*/
//TODO - the rules below break the site - need to investigate why or if we can tweak the rules a bit
//RedirectMatch 403 ^
//RedirectMatch 403 $
//RedirectMatch 403 |
//RedirectMatch 403 ..
//Redirectmatch 403 select(
//Redirectmatch 403 convert(
//RedirectMatch 403 .inc
//RedirectMatch 403 include.
static function getrules_advanced_character_string_filter()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_advanced_char_string_filter')=='1')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$advanced_char_string_filter_marker_start . PHP_EOL; //Add feature marker start
$rules .= '
RedirectMatch 403 `
RedirectMatch 403 {
RedirectMatch 403 }
RedirectMatch 403 ~
RedirectMatch 403 "
RedirectMatch 403 <
RedirectMatch 403 >
RedirectMatch 403 //
RedirectMatch 403 %0
RedirectMatch 403 %A
RedirectMatch 403 %B
RedirectMatch 403 %C
RedirectMatch 403 %D
RedirectMatch 403 %E
RedirectMatch 403 %F
RedirectMatch 403 %22
RedirectMatch 403 %27
RedirectMatch 403 %28
RedirectMatch 403 %29
RedirectMatch 403 %3C
RedirectMatch 403 %3E
RedirectMatch 403 %3F
RedirectMatch 403 %5B
RedirectMatch 403 %5C
RedirectMatch 403 %5D
RedirectMatch 403 %7B
RedirectMatch 403 %7C
RedirectMatch 403 %7D
# COMMON PATTERNS
Redirectmatch 403 _vpi
Redirectmatch 403 xAou6
Redirectmatch 403 db_name
Redirectmatch 403 /query/
RedirectMatch 403 ImpEvData
Redirectmatch 403 .XMLHTTP
Redirectmatch 403 proxydeny
RedirectMatch 403 function.
Redirectmatch 403 remoteFile
Redirectmatch 403 servername
Redirectmatch 403 &rptmode=
Redirectmatch 403 sys_cpanel
RedirectMatch 403 db_connect
RedirectMatch 403 doeditconfig
RedirectMatch 403 check_proxy
Redirectmatch 403 system_user
Redirectmatch 403 /(null)/
Redirectmatch 403 clientrequest
Redirectmatch 403 option_value
RedirectMatch 403 ref.outcontrol
# SPECIFIC EXPLOITS
RedirectMatch 403 errors.
RedirectMatch 403 config.
RedirectMatch 403 display.
RedirectMatch 403 register.
Redirectmatch 403 password.
RedirectMatch 403 maincore.
RedirectMatch 403 authorize.
Redirectmatch 403 macromates.
RedirectMatch 403 head_auth.
RedirectMatch 403 submit_links.
RedirectMatch 403 change_action.
Redirectmatch 403 com_facileforms/
RedirectMatch 403 admin_db_utilities.
RedirectMatch 403 admin.webring.docs.
Redirectmatch 403 Table/Latest/index.
' . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$advanced_char_string_filter_marker_end . PHP_EOL; //Add feature marker end
}
return $rules;
}
/*
* This function contains the rules for the 5G blacklist produced by Jeff Starr from perishablepress.com
* NOTE: Since Jeff regularly updates and evolves his blacklist rules, ie, 5G->6G->7G.... we will update this function to reflect the latest blacklist release
*/
static function getrules_5g_blacklist()
{
global $aio_wp_security;
@ini_set( 'auto_detect_line_endings', true );
$rules = '';
if($aio_wp_security->configs->get_value('aiowps_enable_5g_firewall')=='1')
{
$rules .= AIOWPSecurity_Utility_Htaccess::$five_g_blacklist_marker_start . PHP_EOL; //Add feature marker start
$rules .= '# 5G BLACKLIST/FIREWALL (2013)
# @ http://perishablepress.com/5g-blacklist-2013/
# 5G:[QUERY STRINGS]
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} (\"|%22).*(<|>|%3) [NC,OR]
RewriteCond %{QUERY_STRING} (javascript:).*(\;) [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3) [NC,OR]
RewriteCond %{QUERY_STRING} (\\|\.\./|`|=\'$|=%27$) [NC,OR]
RewriteCond %{QUERY_STRING} (\;|\'|\"|%22).*(union|select|insert|drop|update|md5|benchmark|or|and|if) [NC,OR]
RewriteCond %{QUERY_STRING} (base64_encode|localhost|mosconfig) [NC,OR]
RewriteCond %{QUERY_STRING} (boot\.ini|echo.*kae|etc/passwd) [NC,OR]
RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC]
RewriteRule .* - [F]
# 5G:[USER AGENTS]
# SetEnvIfNoCase User-Agent ^$ keep_out
SetEnvIfNoCase User-Agent (binlar|casper|cmsworldmap|comodo|diavol|dotbot|feedfinder|flicky|ia_archiver|jakarta|kmccrew|nutch|planetwork|purebot|pycurl|skygrid|sucker|turnit|vikspider|zmeu) keep_out
Order Allow,Deny
Allow from all
Deny from env=keep_out
# 5G:[REQUEST STRINGS]
RedirectMatch 403 (https?|ftp|php)\://
RedirectMatch 403 /(https?|ima|ucp)/
RedirectMatch 403 /(Permanent|Better)$
RedirectMatch 403 (\=\\\'|\=\\%27|/\\\'/?|\)\.css\()$
RedirectMatch 403 (\,|\)\+|/\,/|\{0\}|\(/\(|\.\.\.|\+\+\+|\||\\\"\\\")
RedirectMatch 403 \.(cgi|asp|aspx|cfg|dll|exe|jsp|mdb|sql|ini|rar)$
RedirectMatch 403 /(contac|fpw|install|pingserver|register)\.php$
RedirectMatch 403 (base64|crossdomain|localhost|wwwroot|e107\_)
RedirectMatch 403 (eval\(|\_vti\_|\(null\)|echo.*kae|config\.xml)
RedirectMatch 403 \.well\-known/host\-meta
RedirectMatch 403 /function\.array\-rand
RedirectMatch 403 \)\;\$\(this\)\.html\(
RedirectMatch 403 proc/self/environ
RedirectMatch 403 msnbot\.htm\)\.\_
RedirectMatch 403 /ref\.outcontrol
RedirectMatch 403 com\_cropimage
RedirectMatch 403 indonesia\.htm
RedirectMatch 403 \{\$itemURL\}
RedirectMatch 403 function\(\)
RedirectMatch 403 labels\.rdf
RedirectMatch 403 /playing.php
RedirectMatch 403 muieblackcat
# 5G:[REQUEST METHOD]
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]
# 5G:[BAD IPS]
Order Allow,Deny
Allow from all
# uncomment/edit/repeat next line to block IPs
# Deny from 123.456.789
' . PHP_EOL;
$rules .= AIOWPSecurity_Utility_Htaccess::$five_g_blacklist_marker_end . PHP_EOL; //Add feature marker end
}
return $rules;
}
/*
* This function will do a quick check to see if a file's contents are actually .htaccess specific.
* At the moment it will look for the following tag somewhere in the file - "# BEGIN WordPress"
* If it finds the tag it will deem the file as being .htaccess specific.
* This was written to supplement the .htaccess restore functionality
*/
static function check_if_htaccess_contents($file)
{
$is_htaccess = false;
$file_contents = file_get_contents($file);
if (!$file_contents || $file_contents == 0)
{
return -1;
}
if ((strpos($file_contents, '# BEGIN WordPress') !== false) || (strpos($file_contents, '# BEGIN') !== false))
{
$is_htaccess = true; //It appears that we have some sort of .htacces file
}
else
{
//see if we're at the end of the section
$is_htaccess = false;
}
if ($is_htaccess)
{
return 1;
}
else
{
return -1;
}
}
}