I am working on a project for a python tutorial website and this entails me allowing users to execute python code on my website. To do this i am using the exec function in PHP, the code is below
session_start();
$code = str_replace("\\n", PHP_EOL, $_GET['code']);
$code = str_replace("\\t", " ", $code);
$filepath = "../tmp/" . $_SESSION['username'] . (string) rand() . ".py";
$file = fopen($filepath, "w") or die("Cant open file");
fwrite($file, $code);
fclose($file);
$output = null;
exec("python " . $filepath, $output);
unlink($filepath);
foreach( $output as $line )
{
echo $line;
echo '<br>';
}
What this PHP script does is take the code submitted by the user, save it to a file, execute the file and it then deletes that file. but overly this will allow the user to do what ever they want on my server they can access anything through python. I have implemented some checking of the code before it is executed e.g. checking whether certain library's are used but there are to many to check for them all. i was wondering if there was a way i could sandbox the exec function so if i user tried to use the python library SYS to do something it wouldn't give them access to my system?
Cheers.
You don't want to sandbox the exec, but the python interpreter. Another option is to use chroot.
Related
This is a php script for a user login system that I am developing.
I need it to read from, and write to, the /students/students.txt file, but it won't even read the content already contained in the file.
<?php
//other code
echo "...";
setcookie("Student", $SID, time()+43200, "/");
fopen("/students/students.txt", "r");
$content = fread("/students/students.txt", filesize("/students/students.txt"));
echo $content;
fclose("/students/students.txt");
fopen("/students/students.txt", "w");
fwrite("/students/students.txt", $content."\n".$SID);
fclose("/students/students.txt");
//other code
?>
You are not using fopen() properly. The function returns a handle that you then use to read or edit the file, for example:
//reading a file
if ($handle = fopen("/students/students.txt", "r"))
{
echo "info obtained:<br>";
while (($buffer = fgets($handle))!==false)
{ echo $buffer;}
fclose($handle);
}
//writing/overwriting a file
if ($handle = fopen("/students/students.txt", "w"))
{
fwrite($handle, "hello/n");
fclose($handle);
}
Let me know if that worked for you.
P.S.: Ty to the commentators for the constructive feedback.
There are many ways to read/write to file as others have demonstrated. I just want to illustrate the mistake in your particular approach.
fread takes a file handle as param, NOT a string that represents the path to the file.
So your line:
$content = fread("/students/students.txt", filesize("/students/students.txt")); is incorrect.
It should be:
$file_handle = fopen("/students/students.txt", "r");
$content = fread($file_handle, filesize("/students/students.txt"));
Same thing when you write contents to file using fwrite. Its reference to the file is a File Handle opened using fopen NOT the filepath. when opening a file using fopen() you can also check if the $file_handle returned is a valid resource or is false. If false, it means the fopen operation was not successful.
So your code:
fopen("/students/students.txt", "w");
fwrite("/students/students.txt", $content."\n".$SID);
fclose("/students/students.txt");
Needs to be re-written as:
$file_handle = fopen("/students/students.txt", "w");
fwrite($file_handle, $content."\n".$SID);
fclose($file_handle);
You can see that fclose operates on file handles as well.
File Handle (as per php.net):
A file system pointer resource that is typically created using fopen().
Here are a couple of diagnostic functions that allow you to validate that a file exists and is readable. If it is a permission issue, it gives you the name of the user that needs permission.
function PrintMessage($text, $success = true)
{
print "$text";
if ($success)
print " [<font color=\"green\">Success</font>]<br />\n";
else
print(" [<font color=\"red\">Failure</font>]<br />\n");
}
function CheckReadable($filename)
{
if (realpath($filename) != "")
$filename = realpath($filename);
if (!file_exists($filename))
{
PrintMessage("'$filename' is missing or inaccessible by '" . get_current_user() . "'", false);
return false;
}
elseif (!is_readable($filename))
{
PrintMessage("'$filename' found but is not readable by '" . get_current_user() . "'", false);
return false;
}
else
PrintMessage("'$filename' found and is readable by '" . get_current_user() . "'", true);
return true;
}
I've re-written your code with (IMO) a cleaner and more efficient code:
<?php
$SID = "SOMETHING MYSTERIOUS";
setcookie("Student", $SID, time()+43200, "/");
$file = "/students/students.txt"; //is the full path correct?
$content = file_get_contents($file); //$content now contains /students/students.txt
$size = filesize($file); //do you still need this ?
echo $content;
file_put_contents($file, "\n".$SID, FILE_APPEND); //do you have write permissions ?
file_get_contents
file_get_contents() is the preferred way to read the contents of a
file into a string. It will use memory mapping techniques if supported
by your OS to enhance performance.
file_put_contents
This function is identical to calling fopen(), fwrite() and
fclose() successively to write data to a file. If filename does not
exist, the file is created. Otherwise, the existing file is
overwritten, unless the FILE_APPEND flag is set.
Notes:
Make sure the full path /students/students.txt is
correct.
Check if you've read/write permissions on /students/students.txt
Learn more about linux file/folder permissions or, if you don't access to the shell, how to change file or directory permissions via ftp
Try to do this:
fopen("students/students.txt", "r");
And check to permissions read the file.
I am working on a system where i would like to create and destroy cronjobs.
Now when i create the following cronjobs for example:
1**** /path/users.php?id=2
1**** /path/users.php?id=3
Then i would like to kill the first cronjob users.php?id=2
I am wondering if each cron creates a specific processid (PID) through unix and if so, how can i catch this specific processid?
I have tried the echo $$ command however, i doubt that this command generates this specific Cron PID.
If you directly call the script with php and not via http you can place this in your php script:
file_put_contents("/absolute_path/cronjob_users_id_2.pid", getmypid());
This writes the PID of the process in a file.
If the script eventually comes to an end you can simply delete the file:
unlink($pidfile);
Try this
function remove($id)
{
$file = file(path/to/cron_file);
$content = '';
foreach( $file as $line )
{
list($url, $t_id) = explode('?id=', $line);
if( trim($t_id) != $id )
{
$content .= $line;
}
}
file_put_contents(path/to/cron_file, $content);
}
I have a very simple PHP script that calls shell_exec to start a 3rd party application.
No matter what application I try to run (including notepad.exe),
if the script contains the call to shell_exec, the script is called multiple times,
if the script doesn't contain this call, it runs just once.
I can provide any source code needed, let me know what do you want to see, I just absolutely don't know where to look.
Windows 2008 R2, PHP 5.5.1, IIS 7.5, Amazon EC2 server
And no, there isn't any loop inside the script, because I have placed
file_put_contents('log.txt', $_SERVER['REQUEST_URI'], FILE_APPEND);
as the first script row and I can see it written multiple times in the log.
EDIT:
It doesn't happen on my local host. And it happens with exec also.
PHP script stripped down to bare minimum:
<?php
//Report any errors
ini_set("MAX_EXECUTION_TIME", "-1");
ini_set('max_input_time', -1);
ini_set ("display_errors", "1");
error_reporting(E_ALL);
require_once('PhpConsole.php');
PhpConsole::start(true, true, dirname(__FILE__));
function writeLog($content, $logname)
{
$temp = $content ." at " .date("D M j G:i:s T Y") ."\r\n";
$f = fopen($logname, 'a+');
fwrite($f,$temp,strlen($temp));
fclose($f);
}
function createBackground()
{
//Set the correct content type
header('content-type: image/png');
//Create our basic image stream 225px width, 225px height
$image1 = imagecreate(1362, 762);
// Set the background color
$white = imagecolorallocate($image1, 255, 255, 255);
// Save the image as a png and output
imagepng($image1, "saves/back.png");
// Clear up memory used
imagedestroy($image1);
}
function buildFramesSequence()
{
array_map('unlink', glob("saves/*"));
array_map('unlink', glob("*.mp4"));
unlink("list.txt");
$url = realpath('') ."/" .$_GET["jfile"] ;
$contents = file_get_contents($url);
$results = json_decode($contents, true);
$noOfFrames = count( $results['ani']);
$lastframe = "saves/back.png";
createBackground();
$elements = createElements($results['pre']);
$frame_elements = array();
$prev_element = null;
for ($i = 0; $i <$noOfFrames; $i++)
{
$format = 'image%1$05d.png';
$imgname = sprintf($format, $i);
copy($lastframe, "saves/" .$imgname);
}
}
function createVideo()
{
writeLog("before build", "log.txt");
buildFramesSequence();
writeLog("after build", "log.txt");
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$localpath1 = realpath('') ."/ffmpeg/ffmpeg.exe";
} else {
$localpath1 = "ffmpeg";
}
$localpath2 = realpath('') ."/saves/image%05d.png";
$mp3name = $_GET["mfile"];
$localpath3 = realpath('') ."/" .$mp3name;
$temp = substr($mp3name, 0, -1);
$localpath4 = realpath('') ."/" .$temp ."4";
writeLog(" before ffmpeg", "log.txt");
$output = shell_exec("notepad.exe");
// $output = shell_exec("ffmpeg $localpath1 .' -f image2 -r 20 -i ' .$localpath2 .' -i ' .$localpath3 .' -force_fps ' .$localpath4. ' 2>&1 &');
// exec("notepad.exe", $output = array());
// debug($output);
writeLog($localpath4, "list.txt");
return $output;
}
file_put_contents('log.txt', $_SERVER['REQUEST_URI'], FILE_APPEND);
set_time_limit(0);
$output = createVideo();
echo $output;
?>
This is a very strange issue that still happens to this day with exec() system() shell_exec() etc. If your command creates a file the quickest solution is to check whether that file exists, like so:
[ -f path/file.mp4 ] || #Your command here#
This checks whether the file path/file.mp4 exists, if not, the second condition runs, which is your command. To check the opposite use the ampersand, like so:
[ -f path/file.mp3 ] && #Command here#
I'm not sure if anyone is still having problems with this, but maybe yours is the same issues that I just had. I was creating a file with exec, and appending a datetime stamp to it.
I was ending up with 5 files. Turns out, because I was redirecting all calls to my index.php thru htaccess, then when I had some images that were directing to relative path assets/images/image.jpg, then it would redirect that thru my index page and call my script multiple times. I had to add a slash to the image path: /assets/images/image.jpg.
Hope this help someone.
I'm trying to make this save a file and it creates the file, but it's always empty. This is the code for it:
<?php
$code = htmlentities($_POST['code']);
$i = 0;
$path = 'files/';
$file_name = '';
while(true) {
if (file_exists($path . strval($i) . '.txt')) {
$i++;
} else {
$name = strval($i);
$file_name = $path . $name . '.txt';
break;
}
}
fopen($file_name, 'w');
fwrite($file_name, $code);
fclose($file_name);
header("location: index.php?file=$i");
?>
I echoed out $code to make sure it wasn't empty, and it wasn't. I also tried replacing
fwrite($file_name, $code);
with this:
fwrite($file_name, 'Test');
and it was still empty. I have written to files a couple of times before in PHP, but I'm still really new to PHP and I have no idea whats wrong. Could someone tell me what I'm doing wrong or how to fix this? Thanks
Reading/Writing to/from a file or stream requires a resource handle:
$resource = fopen($file_name, 'w');
fwrite($resource, $code);
fclose($resource);
The resource handle $resource is essentially a pointer to the open file/stream resource. You interact with the created resource handle, not the string representation of the file name.
This concept also exists with cURL as well. This is a common practice in PHP, especially since PHP didn't have support for OOP when these methods came to be.
Take a look of the samples on php.net
I am attempting to download fairly large files (up to, possibly over 1GB) from a remote HTTP server through a PHP script. I am using fgets() to read the remote file line by line and write the file contents into a local file that is created through tempnam(). However, the downloads of very large files (several hundred MB) are failing. Is there any way I can rework the script to catch the errors that are occurring?
Because the download is only part of a larger overall process, I would like to be able to handle the downloads and deal with errors in the PHP script rather than having to go to wget or some other process.
This is the script I am using now:
$tempfile = fopen($inFilename, 'w');
$handle = #fopen("https://" . $server . ".domain.com/file/path.pl?keyID=" . $keyID . "&format=" . $format . "&zipped=true", "r");
$firstline = '';
if ($handle) {
while (!feof($handle)) {
$buffer = fgets($handle, 4096);
if ($firstline == '') $firstline = $buffer;
fwrite($tempfile, $buffer);
}
fclose($handle);
fclose($tempfile);
return $firstline;
} else {
throw new Exception ('Unable to open remote file.');
}
I'd say you're looking for stream_notification_callback (especially the STREAM_NOTIFY_FAILURE & STREAM_NOTIFY_COMPLETED constants)