PHP jailing arbitrary code - php

We have a Java IRC application where users are allowed to execute arbitrary PHP and get the result. Here is one example of what this is used for:
btc: <php>$btc = json_decode(file_get_contents('https://btc-e.com/api/2/1/ticker'), true); $ticker = $btc['ticker']; echo "Current BTC Ticker: High: $".$ticker['high']." Low: $".$ticker['low']." Average: $" . $ticker['avg'];
We also have a python setup, but we like PHP because PHP does not require newlines in the code anywhere. (Because this is IRC, we cannot give it newlines unless we exec a web-loaded .py file)
The issue is how to prevent people from trying to exploit the system, such as in:
<php>echo readfile("/etc/passwd");
Which would, clearly, read out the passwd file for all to see.
We are also having this problem, after we tried to block readfile():
<php>$rf = readfile; echo $rf("/etc/passwd");
How should we go about securing this system? (The full code is on github, for any interested: https://github.com/clone1018/Shocky)
As an aside, no real sensitive information is being exposed, as the whole thing is in a VM, so it isn't a "timebomb" or anything. We still want to lock it down though.

That sounds like plugging one hole in a colander. Filesystem security should be handled by the OS, not the application. And as far as /etc/passwd goes, the OS is already securing it.
Here's the first line of my /etc/passwd - yes, I'm going to post it publicly:
root:x:0:0:root:/root:/bin/bash
Usually, passwords aren't actually stored in /etc/passwd. User information is, but the passwords are replaced with x, with the real password only available to the root user.
However, you should lock down PHP to some degree. You can change many PHP options during runtime with ini_set, including open_basedir. http://www.php.net/manual/en/ini.core.php#ini.open-basedir

If you only want to restrict the file reading maybe this can help
http://www.php.net/manual/en/ini.core.php#ini.open-basedir
If you are using an old version of php < 5.4 you can consider using php safe mode
http://php.net/manual/en/ini.sect.safe-mode.php
Set the following vars for safe mode to restrict php
safe_mode_exec_dir
disable_functions = readfile,system
and many other
Also the user wont be able to read any file for which uid is different, e.g. /etc/password.
Be advised that safe mode is depreciated/ removed from latest versions of php

Related

What to check when shell_exec() does not work?

I have the following code running in an application on IIS:
<?php
echo "begin test";
$temp = shell_exec('whoami 2>&1');
print_r($temp);
echo "<br/>end test";
?>
This outputs:
begin test
end test
This means that shell_exec did not execute. Additionally no exception was thrown, nor was there any warning outputted.
What do i need to check to ensure this executes properly?
Edit: disable_functions in php.ini is blank
The first thing I would do is open your php.ini file and find the part labeled disable_functions. Make sure that the list of disabled functions does not include shell_exec. You can also dump this information to a browser screen via phpinfo. That has the advantage of allowing you to do a ctrl-f for shell_exec. (Be sure to turn the dump off again once you've grabbed what you need.)
In any case, if you're enabling shell_exec on a server where it was disabled, proceed with extreme caution, especially if you're sharing the environment with others. There is likely a very good reason why it's turned off. For example, it's common for popular packages to have vulnerabilities discovered, and a shared hosting admin who can't convince their boss to ban said packages might disable shell_exec as a way to temporarily allow clients to keep running those insecure packages until the packages have actual fixes. For obvious reasons, turning shell_exec back on could be extremely dangerous.
Anyhow, I hope this helps.
The issue turned out to be something to do with the PHP version. Updating from PHP 5 to PHP 8 resolved the issue.

php5 reading remote file the valid way

I recently upgraded from php4 to php5 and with it came the notice that all my remote php file access no longer worked. I've been doing quite a bit of research into this and I dont seem to have a clear answer as to what is the correct way to include remote urls in php5.
The first example is to include the file this way
<?php
$data = file_get_contents("http://example.com/example.inc.php",0);
echo $data;
?>
The 2nd is this way
<?php
$ch = curl_init("http://example.com/example.inc.php");
curl_exec($ch);
curl_close($ch);
?>
and 3rd is to set in my php.ini file
allow_url_include = On
allow_url_fopen = On
and use the good old
<?php include_once('http://example.com/example.inc.php');?>
I want to do this right and secure.
All solutions are correct and there is no real difference in safety AFAIK.
I think the difference can be summed up like this:
The ini-settings provide the behaviour as known from prior versions. The reason why they are disabled by default is the security thread, but that is equal to all three solutions. Including remote files is a security problem, regardless of whether you control the rmeote site or not.
file_get_contents() and the curl extension creates some overhead, since you have to buffer the content, but for php include files that is more a cosmetic thing. Their usage is slightly more complex when reading through a script. But the buffering also adds benefits: you might create a local cache for example or a checksum towards a basic plausibility check. Also a syntax check prior to execution is possible thus preventing the crash of your calling script.
Curl is provided as a php extension. So the curl solution only works when the extension is installed, but it offers a much higher grade of freedom, much more options. If you don't require those stay with the builtin functions.
Well,
First method => Is correct and you shouldnt worry using it.
Second method= > Is correct, but curl extension should be enabled
Third method => Is correct, but using this option is not recommended because enabling allow_url_include likely makes your site vulnerable. For more detail see http://en.wikipedia.org/wiki/Include_vulnerability and this link http://wiki.dreamhost.com/Allow_url_include

Using PHP APC cache in CLI mode using dumpfiles

I've recently started using APC cache on our servers. One of the most important parts of our product is a CLI (Cron/scheduled) process, whose performance is critical. Typically the batchjob consists of running some 16-32 processes in parallel for about an hour (they "restart" every few minutes).
By default, using APC cache in CLI is a waste of time due to the opcode cache not being retained between individual calls. But APC also contains apc_bin_dumpfile() and apc_load_dumpfile() functions.
I was thinking these two function might be used to make APC efficient in CLI mode by having it all compiled sometime outside the batchjob, stored in a single dumpfile and having the individual processes load the dumpfile.
Does anybody have any experience with such a scenario or can you give good reasons why it will or will not work? If any significant gains could reasonably be had, either in memory use or performance? What pitfalls are lurking in the shadows?
Disclaimer: As awesome as APC is when it works in CLI, and it is awesome, it can equally be as frustrating. Use with a healthy load of patience, be thorough, step away from the problem if you're spinning, keep in mind you are working with cache that is why it seems like its doing nothing, it is actually doing nothing. Delete dump file, start with just the basics, if that doesn't work forget it try a new machine, new OS, if it is working make a copy, piece by piece expand functionality - there are loads of things that won't work, if it is working commit or make a copy, add another piece and test again, for sanity-check recheck the copies that were working before, cliches or not; if at first you don't succeed try try again, you can't keep doing the same thing expecting new results.
Ready? This is what you've been waiting for:
Enable apc for cli
apc.enable-cli=1
it is not ideal to create, populate and destroy the APC cache on every CLI request
- previous answer by unknown poster since removed.
You're absolutely right that sucks, lets fix it shall we?
If you try and use APC under CLI and it is not enabled you will get warnings.
something like:
PHP Warning: apc_bin_loadfile(): APC is not enabled,
apc_bin_loadfile not available.
PHP Warning: apc_bin_dumpfile(): APC is not enabled,
apc_bin_dumpfile not available.
Warning: I suggest you don't enable cli in php.ini, it is not worth the frustration, you are going to forget you did it and have numerous other headaches with other scripts, trust me its not worth it, use a launcher script instead. (see below)
apc_loadfile and apc_dumpfile in cli
As per the comment by mightye php we need to disable apc.stat or you will get a warnings
something like:
PHP Warning: apc_bin_dumpfile(): Excluding some files from apc_bin_dump[file].
Cached files must be included using full path with apc.stat=0.
launcher script - php-apc.sh
We will use this script to launch our apc enabled scripts (ex. ./php-apc.sh apc-cli.php) instead of changing the properties in php.ini directly.
#/bin/sh
php -d apc.enable_cli=1 -d apc.stat=0 $1
Ready for the basic functionality? Sure you are =)
basic APC persisted - apc-cli.php
<?php
/** check if dump file exists, you don't want to use file_exists */
if (false !== $dump_file = stream_resolve_include_path('apc.dump'))
/** so where were we lets have a look see shall we */
if (false !== apc_bin_loadfile($dump_file))
/** fetch what was stored last run just for fun */
if (false !== $value = apc_fetch('my.awesome.apc.store'))
echo "$value from apc\n";
/** store what gets fetched the next run just for fun */
apc_store('my.awesome.apc.store', 'awesome in cli');
/** what a shlep lets not do that all over again shall we */
apc_bin_dumpfile(array(),null,'apc.dump');
Notice: Why not use file_exists? Because file_exists == stat you see and we want to reap the reward that is apc.stat=0 so; work within the include path; use absolute and not relative paths - as returned by stream_resolve_include_path(); avoid include_once, require_once use the non *_once counterparts; check your stat usage, when not using APC(Muchos important senor), with the help of a StreamWrapper echo for calls to method url_stat; Oops: Fatal scope over-run error! aborting notice thread. see url_stat
message: Error caused by StreamWrapper outside the scope of this discussion.
The smoke test
Using the launcher execute the basic script
./php-apc.sh apc-cli.php
A whole bunch of nothing happened that's what we want right, why else do you want to use cache? If it did output anything then it didn't work, sorry.
There should be a dump file called apc.dump see if you can find it? If you can't find it then it didn't work, sorry.
Good we have the dump file there were no errors lets run it again.
./php-apc.sh apc-cli.php
What you want to see:
awesome in cli from apc
Success! =)
There are few in PHP as satisfying as a working APC implementation.
nJoy!
I would definitely not use it in the CLI as when you restart it, it's almost as if it was never running in the first place!
The better way of using APC is to have it running on the webserver itself all the time, this way with it being active it will actually do what it's supposed to do!
I tryed with curl and APC.it works
use these commands in CLI
curl --data "param1=value2" http://testsite.com/test.php
so it will post data to test.php and you writes the code in it.

How to view PHP or Apache error log online in a browser?

Is there a way to view the PHP error logs or Apache error logs in a web browser?
I find it inconvenient to ssh into multiple servers and run a "tail" command to follow the error logs. Is there some tool (preferably open source) that shows me the error logs online (streaming or non-streaming?
Thanks
A simple php code to read log and print:
<?php
exec('tail /var/log/apache2/error.log', $error_logs);
foreach($error_logs as $error_log) {
echo "<br />".$error_log;
}
?>
You can embed error_log php variable in html as per your requirement. The best part is tail command will load the latest errors which wont make too load on your server.
You can change tail to give output as you want
Ex. tail myfile.txt -n 100 // it will give last 100 lines
See What commercial and open source competitors are there to Splunk? and I would recommend https://github.com/tobi/clarity
Simple and easy tool.
Since everyone is suggesting clarity, I would also like to mention tailon. I wrote tailon as a more modern and secure alternative to clarity. It's still in its early stages of development, but the functionality you need is there. You may also use wtee, if you're only interested in following a single log file.
You good make a script that reads the error logs from apache2..
$apache_errorlog = file_get_contents('/var/log/apache2/error.log');
if its not working.. trying to get it with the php functions exec or shell_exec and the command 'cat /var/log/apache2/error.log'
EDIT: If you have multi servers(i quess with webservers on it) you can create a file on the machine, when you make a request to that script(hashed connection) you get the logs from that server
I recommend LogHappens: https://loghappens.com, it allows you to view the error log in web, and this is what it looks like:
LogHappens supports kinds of web server log format, it comes with parses for Apache and CakePHP, and you can write your own.
You can find it here: https://github.com/qijianjun/logHappens
It's open source and free, I forked it and do some work to make it work better in dev env or in public env. That is:
Support token for security, one can't access the site without the token in config.php
Support IP whitelists for security and privacy
Sopport config the interval between ajax requests
Support load static files from local (for local dev env)
I've found this solution https://code.google.com/p/php-tail/
It's working perfectly. I only needed to change the filesize, because I was getting an error first.
56 if($maxLength > $this->maxSizeToLoad) {
57 $maxLength = $this->maxSizeToLoad;
58 // return json_encode(array("size" => $fsize, "data" => array("ERROR: PHPTail attempted to load more (".round(($maxLength / 1048576), 2)."MB) then the maximum size (".round(($this->maxSizeToLoad / 1048576), 2) ."MB) of bytes into memory. You should lower the defaultUpdateTime to prevent this from happening. ")));
59 }
And I've added default size, but it's not needed
125 lastSize = <?php echo filesize($this->log) || 1000; ?>;
I know this question is a bit old, but (along with the lack of good choices) it gave me the idea to create this tiny (open source) web app. https://github.com/ToX82/logHappens. It can be used online, but I'd use an .htpasswd as a basic login system. I hope it helps.

Cleanup php files from virus

I'll get mallwared site hosted on linux hosting. All php files now start from lines:
<?php
$md5 = "ad05c6aaf5c532ec96ad32a608566374";
$wp_salt = array( ... );
$wp_add_filter = create_function( ... );
$wp_add_filter( ... );
?>
How I can cleanup it's with bash/sed or something?
You should restore your backup.
FILES="*.php"
for f in $FILES
do
cat $f | grep -v 'wp_salt|wp_add_filter|wp_add_filter' > $f.clean
mv $f.clean $f
done
Just a warning, the wp_add_filter() recursively evaluates encoded php code, which in turn calls another script that is encoded and evaluated. This larger script not only injects malicious code throughout your site but appears to collect credentials, and execute other hacks. You should not only clean your site, but make sure the flaw is fixed and any credentials that might have been exposed are changed. In the end, it appears to be a wordpress security issue but I've not confirmed this. I've added some comments on this over at http://www.php-beginners.com/solve-wordpress-malware-script-attack-fix.html, which includes a clean-up script and more information on how to decode the malicious script.
You can do it with PHP (fopen, str_replace and fwrite) . There shouldn't be any encoding problems.
I just hit with this on a very full hosting account, every web file full of php?!
Much digging and post reading everywhere I came across this guys cleaner code (see http://www.php-beginners.com/solve-wordpress-malware-script-attack-fix.html) - and tried it on a couple of the least important sites first.
So far so good. Pretty much ready to dig in and utilize it account wide to try and wipe this right off.
The virus/malware seems to be called "!SShell v. 1.0 shadow edition!" and infected my hosting account today. Along with the cleaner at http://www.php-beginners.com/solve-wordpress-malware-script-attack-fix.html, you actually need to discover the folder containing the shell file that gives the hackers full access to your server files and also discover the "wp-thumb-creator.php" that's the file that does all the php injection. I've posted more about this # my blog: http://www.marinbezhanov.com/web-development/6/malware-alert-september-2011-sshell-v.1.0/

Categories