someone1 Posted March 22, 2006 Share Posted March 22, 2006 Hello all,My Host has recently emailed me explaining to me that my website has been hacked. I use the simpiliest form of PHP on my website, an ALL html layout with a simple inlcude statement for my content area. It seems that when the include variable is set equal to "http://fanklinsys.nm.ru/sponsorship_api.php" that the user has full access to my files and MySQL db's. They can delete files, folder, CHMOD them, upload files (and i've tested these all) and some things more. My host is requesting that a security update be made to the script but i'm not sure how to prevent this completely other than blocking that URL (which won't stop them from uploading the script somewhere else or renaming the file). If anybody is familiar with this exploit, please help me out with a way to block it![code]<?php if (isset($_GET['page'])) {include($page); } else {include('news/news.php'); }; ?>[/code] Quote Link to comment Share on other sites More sharing options...
kenrbnsn Posted March 22, 2006 Share Posted March 22, 2006 Do not, in any circumstances, include a file where the name comes from the URL without checking that it is a file you know about.You wrote that your code looks like:[code]<?php if (isset($_GET['page'])) {include($page); } else {include('news/news.php'); }; ?>[/code]This means that a hacker could do [a href=\"http://your.domain.here/yourfile.php?page=../../../../.passwd\" target=\"_blank\"]http://your.domain.here/yourfile.php?page=..../../../.passwd[/a]and you would display your host's password file or they could enter a URL that points to a shell script and really screw you up.Here are a few things you should check for before including the file:[list][*] Does the filename contain the string "http://", if so reject it[*] Does the filename contain the string "../", if so reject it[*] Does the filename contain an extension? Accept only strings with no extensions. Your script should always provide the extension.[*] Have a predetermined list of files that are acceptable and only allow those.[/list]Go to the PHP Security Consortium's [a href=\"http://phpsec.org/\" target=\"_blank\"]web site.[/a] There is a lot of very good information there. Always program defensively -- assume someone is going to try to break you code.Ken Quote Link to comment Share on other sites More sharing options...
obsidian Posted March 22, 2006 Share Posted March 22, 2006 another point to add, although, this does limit the flexibility of the code somewhat: instead of allowing the script to read the full include path from the QUERY_STRING, have all your valid options in a database table and simply pass a reference to that item from the database or even a flat text file. this way, you always have a control setup over what pages are allowed. it's much easier to try to list ALLOWED arguments than to try to come up with an exhaustive list of those pages that ARE NOT allowed. Quote Link to comment Share on other sites More sharing options...
redbullmarky Posted March 22, 2006 Share Posted March 22, 2006 obsidian, apologies if this is covering what you were getting at.in my opinion, $_GET, $_POST and $_COOKIE (GPC) are the three to really be super-paranoid about if you want a secure site, as they're the 3 php superglobals that primarily deal with input from the user.if you're not doing some sort of processing, no matter how simple the script is, on these three, then you're asking for trouble as either can be exploited with certain code to either make your script act erratically or reveal/do things that you don't want. whilst 'SQL Injection' is mainly aimed at people dealing with mysql databases, the principles involved and the methods to cut out injection relate to scripting whether you use a database or not.if your system is kinda like a templating system, then use an array/mysql/flatfile system to store and retrieve the information you need rather than allowing a user to get 'straight to the heart' of your code'. so if you had a templating system, you might have something like:[code]$module = $_GET['action'];$all_actions = array('thisone'=>'thisone.php', 'thatone'=>'thatone.php', 'theother'=>'theother.php');if (isset($all_actions[$module])){ include($all_actions[$module]);}else{ echo 'get out of here!!!!!!'; exit;}[/code]obviously there is more to consider, like checking for invalid characters in the URL parameter, but what the above does is puts a barrier or two in between the user and the script.from my old college teacher:a bouncer at the door of a night club will stop most under-age drinkers getting in, but there's always one that can get through. put an extra one or two on the door, who all ask for age identification, and things get much harder for them. it's not much different in web security. stop everything that comes through, check it thoroughly, etc, and maybe your site won't get shut down like a club that lets under-age drinkers in. Quote Link to comment Share on other sites More sharing options...
someone1 Posted March 23, 2006 Author Share Posted March 23, 2006 thank you all for the helpful responsesi have one last question:Is there a way i can make an array of all strings that if found in the include path to be blocked?right now, i'm doing this to block all http:// and ftp:// attempts, but i have a list of strings to search for, and if found, to not load a page, but i'd rather not make a million if statements:[code]<?php $findme = "://";$pos = strpos($page, $findme);if($pos === false){ if (isset($_GET['page'])) {include($page); } else {include('news/news.php'); }; } ?>[/code] Quote Link to comment Share on other sites More sharing options...
ToonMariner Posted March 23, 2006 Share Posted March 23, 2006 I have tried this approach (and would be greatful for any comment).Firstly where possible avoid includes from any user dictated flow control...If unavoidable I prepend every path in the include with $_SERVER['DOC_ROOT']; hopefully forcing it to only include a file that is on this server..... Quote Link to comment Share on other sites More sharing options...
btherl Posted March 23, 2006 Share Posted March 23, 2006 You can do this:[code]$page = $_GET['page'];$bad_strings = array( "://", "../",);foreach ($bad_string as $b) { if (strpos($page, $b) !== false) { die("I'm not including that!!"); }}[/code]Another thing you can do is:[code]$page = $_GET['page'];if (ereg("[^a-zA-Z0-9]", $page)) { die("I'm not including that!!");}[/code]That will reject anything which is not a letter or a number. If you want to allow other characters, you can include them in that regexp. In particular, this rejects ".", "/", and anything else needed to include something from another directory.Even better is:[code]$page = $_GET['page'];$allowed = array( "news", "forum",);if (!in_array($page, $allowed)) { die("no no no no no, a million times no!");}[/code]These are all implementations of kenrbnsn's suggestions.Toonmariner, you may have a problem with files like "../../../../../etc/passwd". Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.