disable all php dangerous functions

Recently my server was hacked (find my root password and changed). Was possible via brute force attack or running a php uploaded script or a trojan program.
I didn't find because hdd was compromised.OS reinstalled.

Anyway, i was reading php security issues and i want to disable dangerous functions. I have a list , but you can add other items will be helpfull for me.

I need to run register_globals On until i will rebuild the script.

Thank you in advance.
disable_functions = "
apache_child_terminate, 
apache_setenv, 
apache_get_modules, 
apache_get_version,
apache_getenv, 
apache_note,virtual
define_syslog_variables, 
escapeshellarg, 
escapeshellcmd, 
eval, 
exec, 
fopen
fsockopen,  
fp, 
fput, 
ftp_connect, 
ftp_exec, 
ftp_get, 
ftp_login, 
ftp_nb_fput, 
ftp_put, 
ftp_raw, 
ftp_rawlist, 
gzopen,
highlight_file, 
ini_alter, 
ini_get_all, 
ini_restore, 
inject_code, 
mysql_pconnect, 
openlog, 
passthru, 
php_uname, 
phpAds_remoteInfo, 
phpAds_XmlRpc, 
phpAds_xmlrpcDecode, 
phpAds_xmlrpcEncode, 
popen, 
posix_getpwuid, 
posix_kill, 
posix_mkfifo, 
posix_setpgid, 
posix_setsid, 
posix_setuid, 
posix_uname, 
proc_close, 
proc_get_status, 
proc_nice,
proc_open, 
proc_terminate, 
shell_exec, 
syslog, 
system, 
suexec
xmlrpc_entity_decode
symlink,
dl, 
pclose,      
pfsockopen, 
leak, 
readlink, 
link
"
 
 
safe_mode On
enable_dl   off
allow_url_fopen   off
display_errors	Off
display_startup_errors	Off
expose_php  Off
file_uploads = off
open_basedir to set On via WHM

Open in new window

rowtc2Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Bernard S.CTOCommented:
<<I need to run register_globals On >>
Since you know this is the major source of unsafety, I would consider blocking that without trying to block individual functions.

My suggestion:
- place register_globals to OFF as is normal security practice
- run your script and check where they fail because of this
- at that place, write a sanitization:
  -- where previously you were using $my_value for the first time, place instead
  -- $my_value=$_GET['my_value']; $my_value=htmlspecialchars(trim($my_value));
(or some other safer variant). In fact, I would use frequently the failproof expression
       $my_value=htmlspecialchars(trim( ' ' . @$_GET['my_value'])); which would be the emptystring '' if there is no my_value in the GET
- once you have cleaned up all of these, you might consider regrouping all of your sanitization codes at the beginning of each php script.
There are other ways to solve that, but since they are really unsafe... don't lose time.

If you want some initial help to find the most blatant problems, use a tool like xenu http://home.snafu.de/tilman/xenulink.html it will tell you which of your links are broken.

FINAL NOTE: be very careful with places where you are using one of these variables to run a script.
eg, you need to overprotect code like
include $my_direct_variable;  
because that means that calling this page with an URL like page.php?my_direct_variable=script.php
I can run whichever script.php I have been able to plavce on your site.
A safer way, with register_globals off would be 2 steps:
$my_direct_variable=trim( ' ' . $_GET['my_direct_variable']);
$legal_values= array(
'home' => 'index',
'secret_admin' => 'adminxx',
'news' => 'news'
);
if ( '' < @$legal_values[$my_direct_variable]) { include 'root/' . $legal_values[$my_direct_variable] . '.php'. ...}
0
Ray PaseurCommented:
register_globals allows hackers to inject variables into your script's namespace.  Relying on it is a TERRIBLE idea.  Using it at all is also a bad idea, but in some shared hosting environments, the host leaves it on to support legacy systems.  Since I program my scripts to work with register_globals OFF, I need a way to unregister_globals() at the start of each script.  See the code snippet.

Also, for security, you might want to follow the work and writings of this fellow.  Chris is the "go-to" guy in the mid-Atlantic and is well known nationwide for his thoughtful and detailed work in web security.

http://shiflett.org/

Good luck with it, ~Ray


function unregister_globals() {
	if (ini_get('register_globals')) {
		$array = array('_REQUEST', '_FILES');
		foreach ($array as $value) {
			if(isset($GLOBALS[$value])){
				foreach ($GLOBALS[$value] as $key => $var) {
					if (isset($GLOBALS[$key]) && $var === $GLOBALS[$key]) {
						// echo 'FOUND '.$key.' = '.$var.' IN $'.$value."\n";
						unset($GLOBALS[$key]);
					}
				}
			}
		}
	}
}

Open in new window

0
Bernard S.CTOCommented:
@Ray: nice script to deregister the arguments

@rowtc2: Ray's script will save your day if you cannot register globals off with a php.ini or htaccess
Of course you would first take a copy (then sanitize) all the args you need, then runc this script to wipe out any globals.
0
Firewall Management 201 with Professor Wool

In this whiteboard video, Professor Wool highlights the challenges, benefits and trade-offs of utilizing zero-touch automation for security policy change management. Watch and Learn!

Ray PaseurCommented:
@fibo: Thanks for your kind words.  One other idea that might be useful... Sometimes scripts unwittingly rely on register_globals (leftover code from earlier times) and instead of doing this:

$thing = $_POST["thing"];
if ($thing = 'ABC') echo "THING IS ABC";

... they just do this:

if ($thing = 'ABC') echo "THING IS ABC";

You can catch this stuff "on the fly" by looking for the undefined variables.  Add this to the top of the script and look for the notices.

error_reporting(E_ALL);

Be aware, however, that the undefined variables will only generate notices when they are used, so undefined vars in conditional code might not be found unless you had a test case with 100% code coverage.

Cheers, ~Ray
0
rowtc2Author Commented:
Thank you for your answers..
I have dedicated server. I can set register_globals like i wish. The site script was made using register_globals on .
I know i must change the script but will take a  time .


Until i will rebuild the script i want to disable dangerous functions , like i have write in first post .  I make a list in my first post ,,reading some forums.

My task  now is to limit other potential threats until i rebuild the script .
0
Ray PaseurCommented:
"limit other potential threats..."

The philosophy that drives this effort is called "Accept only known good inputs" - and that applies not only to forms, but to the values in $_SESSION, $_COOKIE, etc.  In other words, any value you did not generate in your script from trusted data is not trustworthy and must be validated against your set of appropriate rules.  It's usually best to isolate the validation in functions so you can write a single statement to clean up your variables.  I use things like "clean_integer_string()" to check data base keys.  There are lots of techniques and programming standards, but isolation and validation seem most helpful to me.

Regards to all, ~Ray
function clean_integer_string($str)
{
// CAST TO STRING AND ELIMINATE OUTSIDE BLANKS
   $new = trim("$str");
// ELIMINATE NON-DIGIT CHARACTERS
   $str = ereg_replace("[^0-9]", "", $new));
// IF THE VALUES DO NOT MATCH, SOMETHING IS NON-NUMERIC
   if ($str != $new) return FALSE;
// IF THE VALUE IS EMPTY, SOMETHING IS WRONG
   if ($str == '')   return FALSE;
// RETURN A CLEAN NUMERIC STRING
   return $str;
}
 
// USAGE
if (!$clean = clean_integer_string(' 123 ')) // RETURNS '123'
if (!$clean = clean_integer_string('A123 ')) // RETURNS FALSE
if (!$clean = clean_integer_string(' 1 3 ')) // RETURNS FALSE
if (!$clean = clean_integer_string('-123 ')) // RETURNS FALSE
if (!$clean = clean_integer_string('0'))     // RETURNS '0'
if (!$clean = clean_integer_string('0003 ')) // RETURNS '0003'

Open in new window

0
rowtc2Author Commented:
No forms, input text ,upload or  user inputs allowed on site :)  
Is a site with product presentations

Only way can be via url (to write some line code in url and to execute)..
ex: http://www.mysite.com/UNION+select+1,2,3,4  (i see things like this on some black forums).
0
Ray PaseurCommented:
Understood.  It is a rule of the WWW that nothing in a GET string may ever be used to change the underlying data model, so if a client can put things into the URL that are used in a query, you have a problem.  That's why the "accept only known good values" rule is helpful!
0
Bernard S.CTOCommented:
1 - a slight comment in
if ($thing = 'ABC') echo "THING IS ABC";

This is an error I make often.
Of course, it should be
if ($thing == 'ABC') echo "THING IS ABC";

Another way to catch this error which might go unnoticed is to systematically use the form
if ('ABC' = $thing ) echo "THING IS ABC";
where the error will be noticed.

2 - You can use values received by GET... but by checking them against the authorized limited scope of pre-defined values.

A minimum would to search /clean strings like '.php' or 'http://' if you do not need them. And htmlspecialchars will handle the problem of various html tags such as <script>... but if you compare against your ^redefined set of values should be safe.
0
Ray PaseurCommented:
Regarding this single-equal construct, I can only say that I am the widely acknowledged king of typos!

if ($thing = 'ABC') echo "THING IS ABC";

Another way I can do this wrong is to forget the quotes:

if ($thing == ABC) echo "THING IS EQUAL TO THE VALUE OF THE DEFINED CONSTANT ABC";

I like your "constant-first" construction.
0
Bernard S.CTOCommented:
@Ray: I had never realized the problem of unquoted ABC... done!
0
Ray PaseurCommented:
Yeah, the unquoted string is particularly horrifying when the thing is used as an index into an associative array.  Everything works fine until someone in another module says, "DEFINE('START_DATE', '2009-05-22');
and suddenly the fields from the data base that are indexed like this...

$row[START_DATE]

... are polluted.  That's one reason I like to use ALL CAPS with defined constants.

As long as we are on the subject, can we get a big thumbs-down for extract($_GET) ?
0
Bernard S.CTOCommented:
@Ray: I did not know extract($_GET)... and anyway I would not use it.

The first script you gave would help buiding a safe-equivalent of extract...
0
Ray PaseurCommented:
I actually use extract() but only on the results set of DB queries, where I queried for explicit fields.  I think a better approach to handling the external data from GET, POST and the like is something like this - it forces the data through a validation function.  Once you have done that, you never touch $_GET again - instead you use $safe_GET
<?php // RAY_clean_GET.php
 
// SAMPLE CALLING SEQUENCE
// href="RAY_clean_GET.php?a=A&b=2&c=XX"
 
// ACCEPTABLE INDEX VALUES AND THE CORRESPONDING VALIDATION PROCESSES
$validator = array(
    'a' => 'validation_function_1',
    'b' => 'validation_function_2',
    'c' => 'validation_function_2'
);
 
// A PLACE TO KEEP THE SAFE VALUES
$safe_GET = array();
 
// THE ACCEPTABLE KEYS
$validator_keys = array_keys($validator);
 
// ITERATE OVER $_GET
foreach ($_GET as $key => $val)
{
// TEST FOR AN ALLOWABLE KEY
    if (!in_array($key, $validator_keys))
    {
        die('UNDER ATTACK!');
    }
 
    $validation_function = $validator[$key];
    $safe_GET[$key] = $validation_function($val);
}
 
// SHOW WHAT WE FOUND AFTER CLEANUP
var_dump($safe_GET);
 
 
// THESE ARE THE VALIDATION FUNCTIONS
function validation_function_1($str) // TEST FOR A SINGLE UPPERCASE 'A'
{
    if ('A' != $str) return FALSE;
    return 'A';
}
 
function validation_function_2($str) // ACCEPT ONLY A SINGLE NUMERIC DIGIT
{
// CAST TO STRING AND ELIMINATE OUTSIDE BLANKS
   $new = trim("$str");
// USE ONLY ONE CHARACTER
   $new = substr($new,0,1);
// ELIMINATE NON-DIGIT CHARACTERS
   $str = ereg_replace("[^0-9]", "", $new);
// IF THE VALUES DO NOT MATCH, SOMETHING IS NON-NUMERIC
   if ($str != $new) return FALSE;
// IF THE VALUE IS EMPTY, SOMETHING IS WRONG
   if ($str == '')   return FALSE;
// RETURN A CLEAN NUMERIC STRING
   return $str;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.