$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_disable_index_views(); $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; $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; $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; $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 //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 disable directory listings for all directories, add this line to the * site’s root .htaccess file. * NOTE: AllowOverride must be enabled in the httpd.conf file for this to work! */ static function getrules_disable_index_views() { global $aio_wp_security; $rules = ''; if($aio_wp_security->configs->get_value('aiowps_disable_index_views')=='1') { $rules .= AIOWPSecurity_Utility_Htaccess::$disable_index_views_marker_start . PHP_EOL; //Add feature marker start $rules .= 'Options All -Indexes' . PHP_EOL; $rules .= AIOWPSecurity_Utility_Htaccess::$disable_index_views_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; $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; $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; $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; $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; $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; } } }