Hey, I'm trying to use PHP to execute a shell command which will run remotely run a server on my box. Here is my PHP Code:
if ($key == "test") { echo "<font color='green'>Key is valid. Server satrted.</font>";
$start = system('cd /root/st/; ls;');
}
The problem is, the ls command runs from the same directory as the web server, which returns all of the files from /var/www/html instead of /root/st/. I have also tried the chdir command to no avail. Anyone know how you would get the directory to change so that the command could be run from a specified directory? Thanks.
Does the user that PHP is running as (eg, the user invoking the CLI script) have permission to read the directory? If you're going into /root/ but aren't root, you'd need to either add cd to sudoers for the current user, or choose another directory.
Edit: note that adding cd to sudoers is not even remotely okay for anything other than a local, you-only script. :)
There are two ways I would approach this.
1: use proper unix commands, and see if they work. IE:
if ($key == "test") { echo "<font color='green'>Key is valid. Server satrted.</font>";
$start = system('ls /root/st/');
}
2: Make it run a script on the system, that can go outside the webserver's chroot.
if ($key == "test") { echo "<font color='green'>Key is valid. Server satrted.</font>";
$start = system('server.sh');
}
and server.sh is
#!/bin/bash
cd /root/st
ls
PHP has a chdir() function. Not sure if it applies to exec/system calls, but worth a try.
Store the location in a variable, say $loc = '/root/st' and then do ls $loc in your code. Hope this helps.
Your problem is not the directory the script is running in (or more precisely the current working directory of the user running the script), but that cd /root/st/ will fail on any reasonable configured UNIX/Linux system. /root is usually owned by root and can't be accessed by any other user.
Using you snippet this will silently fail because you unconditionally chained the cd and the ls commands with a semicolon instead of &&.
Related
I am trying to programmatically append an RSA public key to the authorized_keys file through a website and haven't been able to make any solutions I found work. I have tried using PHP's file_put_contents() function but I run into a permission denied error, and I have a python script that works, but I cannot seem to get PHP to execute it with either the exec() command or shell_exec(). Here's the relevant PHP code:
if(#$_POST['action']=='submit'){
$key = $_POST['key_field'];
//file_put_contents("/home/biosproject/.ssh/authorized_keys", $key, FILE_APPEND);
$test = "/usr/bin/python savetofile.py \"".$key."\"";
$tmp = shell_exec($test);
}
I'm aware that I need to sanitize the input but the site is currently in development so I'm just testing it like this in the meantime. Right now I'm using XAMPP which runs Apache. Is there something I'm missing or could try? For the PHP exec/shell_exec, I have tried using the full pathnames for all parts of the command, but nothing has worked yet. The python script is as follows:
#!usr/bin/python
import sys
key = sys.argv[1]
with open("/home/biosproject/.ssh/authorized_keys","a") as append:
diditwork = append.write(key)
print key
As I mentioned before, this script is functional, but I can't call it from the PHP script.
EDIT:
My authorized_keys file looks like so: -rw-rw-rw- 1 biosproject www-data 1200 Apr 15 13:17 /home/biosproject/.ssh/authorized_keys
UPDATE:
I fixed the problem by bypassing permissions using a cron job that appends the necessary information from a database entry instead. Works great now!
The Python script won't help you here - it's a permissions issue with the /home/biosproject/.ssh/authorized_keys file, i.e. Apache doesn't have permission to modify it, and nor will any process it spawns, which would include your Python script.
Simplest fix would be to change the file permissions so it's writable by Apache. Assuming apache runs as group www-data, do...
sudo chgrp www-data /home/biosproject/.ssh/authorized_keys
sudo chmod g+w /home/biosproject/.ssh/authorized_keys
...although I forget if ssh complains if authorized_keys is set to g+w.
Update
It occurs to me that www-data will also need +x access to all parent directories of /home/biosproject/.ssh/authorized_keys to be able to change it, although I'm pretty sure that ssh will complain if you change the .ssh directory permissions in this way.
You'll either have to run apache with the same UID as the owner of the /home/biosproject/.ssh directory, or use a setuid script to make the changes.
Explanation about my inline code:
$text = "nice text to append :P";
// open a file handler with a+ flag that means "open file for append and if it does not exist, create it"
$fo = fopen("filename.ext", "a+");
// append $text to file handler with a \n at the end
fwrite($fo, $text . PHP_EOL);
Ok I need to run my Apache web server as root. For this I typed whoami; in terminal. It gives me output: root. But when I check my apache server running as a root user or not by executing following php-script: < ?php echo whoami; ?> It gives me output: nobody. So any suggestions to execute/login as a root user in apache??
I would suggest creating an external PHP file on your server that would handle everything related with this extension. And then, you could call this script with shell_exec in combination with sudo.
This way, you could put your webserver user in your sudoers file and let it run php-cli as root.
Then, in your script you could simply use:
$output = shell_exec("sudo /bin/php /yourscript.php");
This would be a much more secure solution than running Apache as root, which in my opinion, is a verry bad idea, even if you know what you are doing.
If you know what you are doing, look at the file /etc/apache2/envvars :
You can customize these variables
export APACHE_RUN_USER=root
export APACHE_RUN_GROUP=root
I echo the concerns running the apache process as root. Its just a bad idea.
Thats why I recently published a project that allows PHP to obtain and interact with a real Bash shell. Get it here: https://github.com/merlinthemagic/MTS
After downloading you would simply use the following code:
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd('php /var/scripts/test.php');
//the return will be a string containing the return of the script
echo $return1;
I need to detect if php is running as nobody. How do I do this?
Are there any other names for "nobody"? "apache"? Any others?
<?php echo exec('whoami'); ?>
If available you can probe the current user account with posix_geteuid and then get the user name with posix_getpwuid.
$username = posix_getpwuid(posix_geteuid())['name'];
If you are running in safe mode however (which is often the case when exec is disabled), then it's unlikely that your PHP process is running under anything but the default www-data or apache account.
Kind of backward way, but without exec/system:
file_put_contents("testFile", "test");
$user = fileowner("testFile");
unlink("testFile");
If you create a file, the owner will be the PHP user.
This could also likely be run with any of the temporary file functions such as tempnam(), which creates a random file in the temporary directory and returns the name of that file. If there are issues due to something like the permissions, open_basedir or safe mode that prevent writing a file, typically, the temp directory will still be allowed.
More details would be useful, but assuming it's a linux system, and assuming php is running under apache, it will run as what ever user apache runs as.
An easy way to check ( again, assuming some unix like environment ) is to create a php file with:
<?php
print shell_exec( 'whoami' );
?>
which will give you the user.
For my AWS instance, I am getting apache as output when I run this script.
You can try using backticks like this:
echo `whoami`;
I would use:
lsof -i
lsof -i | less
lsof -i | grep :http
You can type any of these in your ssh command line and you will see which user is listening to each service.
You can also check this file:
more /etc/apache2/envvars
and look for these lines:
export APACHE_RUN_USER=user-name
export APACHE_RUN_GROUP=group-name
To filter out envvars file data, you can use grep:
more /etc/apache2/envvars | grep APACHE_RUN_
Straight from the shell you can run:
php -r "echo exec('whoami');"
exec('whoami') will do this
<?php
echo exec('whoami');
?>
In my setup I want to check if the current process has permission to create folders, subfolders and files before I begin a process and suggest a solution if it looks like I can't. I wanted to run stat(<file>) on various things to ensure the permissions match those of the running process (I'm using php-fpm so it varies depending on the pool).
The posix based solution Mario gave above, seems perfect, however it seems the posix extension is --disabled so I couldn't do the above and as I want to compare the results with the response from running stat() running whoami in a separate shell isn't helpful either (I need the uid and gid not the username).
However I found a useful hint, I could stat(/proc/self) and stat(/proc/self/attr) and see the uid and gid of the file.
Hope that helps someone else
Proposal
A tad late, but even though the following is a work-around, it solves the requirement as this works just fine:
<?
function get_sys_usr()
{
$unique_name = uniqid(); // not-so-unique id
$native_path = "./temp/$unique_name.php";
$public_path = "http://example.com/temp/$unique_name.php";
$php_content = "<? echo get_current_user(); ?>";
$process_usr = "apache"; // fall-back
if (is_readable("./temp") && is_writable("./temp"))
{
file_put_contents($native_path,$php_content);
$process_usr = trim(file_get_contents($public_path));
unlink($native_path);
}
return $process_usr;
}
echo get_sys_usr(); // www-data
?>
Description
The code-highlighting above is not accurate, please copy & paste in your favorite editor and view as PHP code, or save and test it yourself.
As you probably know, get_current_user() returns the owner of the "current running script" - so if you did not "chown" a script on the server to the web-server-user it will most probably be "nobody", or if the developer-user exists on the same OS, it will rather display that username.
To work around this, we create a file with the current running process. If you just require() this into the current running script, it will return the same as the parent-script as mentioned; so, we need to run it as a separate request to take effect.
Process-flow
In order to make this effective, consider running a design pattern that incorporates "runtime-mode", so when the server is in "development-mode or test-mode" then only it could run this function and save its output somewhere in an include, -or just plain text or database, or whichever.
Of course you can change some particulars of the code above as you wish to make it more dynamic, but the logic is as follows:
define a unique reference to limit interference with other users
define a local file-path for writing a temporary file
define a public url/path to run this file in its own process
write the temporary php file that outputs the script owner name
get the output of this script by making a request to it
delete the file as it is no longer needed - or leave it if you want
return the output of the request as return-value of the function
add the file info.php to the following directory - your default http/apache directory - normally /var/www/html
with the following contents
<?php
phpinfo();
?>
Then httpd/apache restart
the go to your default html directory
http://enter.server.here/info.php
would deliver the whole php pedigree!
You can use these commands :
<? system('whoami');?>
or
<? passthru('whoami');?>
or
<? print exec('whoami');?>
or
<? print shell_exec('whoami');?>
Be aware, the get_current_user() returns the name of the owner of the current PHP script !
I usually use
<?php echo get_current_user(); ?>
I will be glad if it helped you
$_SERVER["USER"]
$_SERVER["USERNAME"]
<?php phpinfo(); ?>
save as info.php and
open info.php in your browser
ctrl+f then type any of these:
APACHE_RUN_USER
APACHE_RUN_GROUP
user/group
you can see the user and the group apache is running as.
$user = $_SERVER['REMOTE_USER'];
http://php.net/manual/en/reserved.variables.server.php
Authenticated user
I have one server (test) which has "php" command that I can run CLI with. The other server (hosting) runs only with "php5-cli" command.
Example:
exec("php file.php"); // Works on test server
exec("php5-cli file.php"); // Works on hosting server
How can my script detect which one to use?
Make a config value specific to each server. On some servers you will encounter php5 as a cli command, instead of php:) And the system administrator may easily rename or symlink the executable to any name he likes.
edit:
try something along the lines of :
$output = Array();
$result = -1;
exec("php -f myScript.php", $output, $result);
if($result==-1){
// you should try to exec use the other method here
echo "app 'php' not found";
}else{
// the exec was a success
}
php-config --php-binary
php-config5 --php-binary
But you probably run into similar problems of no guarantee what that command is called (or that it exists). Not sure how many hosting companies use it.
Make sure which php.ini is included when using each of them.
Could you symlink php-cli as php or vise versa?
That way either would work.
Why not make a symlink to the executable on one of the servers ln -s so that one of them is available on both servers.
That should solve this problem.
I have a php script:
$extract_dir = "./";
$extract_file = "extractME.zip";
$zip = new ZipArchive;
$res = $zip->open($extract_file);
if ($res === TRUE) {
$zip->extractTo($extract_dir);
$zip->close();
echo "ok";
} else {
echo "failed";
}
But when I execute this script, via http://www.mywebsite.com/extract.php
All the files on FTP are show with OWNER 'root', but not the user ex . 'neo' as it should be. So the user cant edit/rename/delete these files.
Is it possible to fix this anyhow (I own the server), that files will be extracted with 'USERNAME' OWNERSHIP ?
ozzwanted, for some reason your web server (apache) is running as root so any file it makes will be made as root. This should never be the case. apache usually runs as 'www-data' or 'httpd', or 'nobody' or 'god' depending on the linux distro.
I suggest you look into this from a sysadmin point of view and have someone sort it out for you before you end up getting exploited. (assuming this is a live server)
You can use www.php.net/chown function or your can run a 'chown' command on the command line or do it from PHP with something like system() or exec() functions.
Good luck.
It extract as the user running the webserver (note: you should not be running it as root). Try using chown.