Programmatically append to file in PHP - php

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);

Related

Encrypt file using GPG with exec()

I'm trying to encrypt a file using GPG through exec(). The file I want to encrypt is created before running this command.
$fesha = date("mdY");
$file_name = "FILE_$fesha.txt";
$myfile = fopen($file_name, "w");
//MySQL query
fwrite($myfile, $txt);
fclose($myfile);
$password = "*password*";
$commando = "gpg --encrypt --passphrase=\"$password\" --armor --batch --yes --trust-model always -r **email#public.key** \"$file_name\"";
echo shell_exec($commando);
echo $commando;
I run the PHP script while watching the "output" folder, the text file is created without any issues,
but the asc file is never created.
If I manually run the output from the PHP file (the actual GPG command) the encrypted file is created without any issue or error message.
I've been trying to solve this for a couple of hours.
I tried to use the class approach ($gpg = new gnupg();) but I was unable to install all the PECL modules/extensions.
Any help will be greatly appreciated.
After hours and hours of research, trial and error with more command parameters, trying with permissions on the server-side, tried to add www-data user to the admin realm, modifying permissions on /home/www-data/.gnupg and /home/mainuser/.gnupg folders...
I did something "dumb" and send this command ($commando = "gpg --gen-key";) to see if I can generate a secret key through the PHP script because I kinda figure out it had to do with permissions at this point and I was not able to log in as www-data into the terminal.
Obviously I got no interactive response, but I guess It just created an empty key or something because after I tried the original command again:
$commando = "gpg --encrypt --passphrase=\"$password\" --armor --batch --yes --trust-model always -r email#public.key \"$file_name\"";
It actually worked!
The server created the text file and the encrypted file.
So, I do not want to believe that silly thing ("gpg --gen-key") actually "solved the mystery", I want to believe it was a combination of all I did.
Just in case someone else has this issue, I found these articles really helpful.
Using GPG (GnuPG with PHP on Server.
gpg: WARNING: unsafe ownership on homedir /home/user/.gnupg
What are the correct permissions for the .gnupg enclosing folder?
I updated /etc/passwd and changed the home directory for www-data. Next I copied with recursion the /root/.gnupg to the home directory of www-data and change the owner to www-data. Seemed to work. GPG provides like a 80% smaller file size. Use 2>&1 to expose output after line return.

Don't want php script to execute the shell command as apache user when it is executed through browser?

I have created a PHP script that generates some .gz files, when I execute the PHP script through command line (cli), it generate the .gz file having 'desert' as user but when the script is executed through browser it generates the .gz file with 'nobody' as user which should not happen. I want the generated file to have 'desert' user rather than 'nobody' user when the script is executed through browser.
Here is the code I have created:
$file='test';
$newFileGZipCommand = 'cat '.$file.'_new | gzip > '.$file.'.gz';
//$newFileGZipCommand = 'sudo -u desert cat '.$file.'_new | gzip > '.$file.'.gz'; // This does not work
$newFileGZipCommandExecute = shell_exec($newFileGZipCommand);
//chmod($file.'.gz',0777) or die("Unable to change file permission");
//chown($file.'.gz', 'directu') or die("Unable to change file Owner");
I tried doing changing the file permissions and owner through chmod() and chown() functions in php but it say "chown(): operation not permitted".
Any pointer to this is highly appreciated.
[Note: I cannot change the httpd.conf or any other configuration files]
Sudo normally requires an interactive shell to enter your password. That's obviously not going to happen in a PHP script. If you're sure you know what you're doing and you've got your security issues covered, try allowing the Apache user to run sudo without a password, but only for certain commands.
For example, adding the following line in your sudoers file will allow Apache to run sudo without a password, only for the gzip command.
nobody ALL=NOPASSWD: gzip
Adjust the path and add any arguments to suit your needs.
Caution:
There might still be complications due to the way PHP calls shell
commands.
Remember that it's very risky to allow the web server to
run commands as root!
Another alternative:
Write a shell script with the suid bit to make it run as root no matter who calls it.
Probably a better alternative:
Write the commands to a queue and have cron pick them up, validate them (only allow known good requests), and run them, then mark that queue complete with the date and result.
Your end-user can then click/wait for update using ajax.
Hope it helps resolve your answer.

shell_exec not working not able to convert pdftotext

I am trying to convert a pdf file into text file. When I run the command through terminal its working fine but when try to execute it through PHP it's not working.
I am stuck in this situation from last four hour spend lots of time in google but no solution available. Can any body resolve this issue?
File owner - nobody
shell_exec('/usr/bin/pdftotext /opt/lampp/htdocs/foldername/filename.pdf');
Can anyone provide any helpful solution?
I also tried to change usr folder ownership from root to nobody and provide 777 permission on folder and its context.
Your command to run pdftotext is not correct.
There should be a second argument telling pdftotext to write to a specific file or just use a dash "-" to write to stdout, unless you actually want the program to create a text-file with the filename as the pdf (this would require write permissions in the /opt/lampp/.../ folder)
This is at least true for pdftotext version 0.12.4
"Pdftotext reads the PDF file, PDF-file, and writes a text file, text-file. If text-file is not specified, pdftotext converts file.pdf
to file.txt. If text-file is ยด-', the text is sent to stdout."
So, the solution to your question would simply be add a dash after the filename, like so:
<?php
$pdftext = shell_exec('/usr/bin/pdftotext /opt/lampp/htdocs/foldername/filename.pdf -');
echo $pdftext;
Provided that the binary exists and PHP is allowed to use shell_exec and you have permissions and that the pdf-file exists and you have permissions.
from how to test if PHP system() function is allowed? and not turned off for security reasons
function isAvailable($func) {
if (ini_get('safe_mode')) return false;
$disabled = ini_get('disable_functions');
if ($disabled) {
$disabled = explode(',', $disabled);
$disabled = array_map('trim', $disabled);
return !in_array($func, $disabled);
}
return true;
}
You may need to check if isAvailable('shell_exec')
On shared hosting this function might be disabled.
If it's not disabled, check the Apache log, it's all you can do.
try exec and also make sure safe mode off in your php.ini file like this safe_mode = Off
exec('/usr/bin/pdftotext /opt/lampp/htdocs/foldername/filename.pdf')
also run this cmd in terminal to check if software is working
This is usually a function disabled by many webserver, you can check:
var_dump(ini_get('disable_functions')); // not available if shell_exec disabled
var_dump(ini_get('safe_mode')); // not available if true
Since You are running Linux you may have a rights Problem
Check your file is owned by apache.
chown apache apache file.php
Check youir file has rights
chmod 644 file.php
Maybe check your sudoers file aswell
Sudoers ManPage

PHP exec() not working properly

I am having difficulty with the PHP exec() function. It seems to not be calling certain functions. For instance, the code echo exec('ls'); produces no output whatsoever (it should, there are files in the directory). That main reason this is a problem for me is that I'm trying execute a .jar from a PHP exec() call.
As far as I know I'm calling the java program properly, but I'm not getting any of the output. The .jar can be executed from the command line on the server. (For the record, it's an apache server).
My php for the .jar execute looks like this:
$output = array();
exec('java -jar testJava.jar', $output);
print_r($output);
All I get for output from this exec() call is Array().
I have had success with exec() executing 'whoami' and 'pwd'. I can't figure out why some functions are working and some aren't. I'm not the most experienced person with PHP either, so I'm not too sure how to diagnose the issue. Any and all help would be appreciated.
The reason why you are not able to execute ls is because of permissions.
If you are running the web server as user A , then you can only ls only those directories which have permissions for user A.
You can either change the permission of the directory or you can change the user under which the server is running by changing the httpd.conf file(i am assuming that you are using apache).
If you are changing the permissions of the directory, then make sure that you change permissions of parent directories also.
To change the web server user, follow following steps:
Open the following file:
vi /etc/httpd/conf/httpd.conf
Search for
User apache
Group apache
Change the user and group name. After changing the user and group, restart the server using following command.
/sbin/service httpd restart
Then you will be able to execute all commands which can be run by that user.
EDIT:
The 'User' should be a non-root user in httpd.conf. Apache by default doesnot serve pages when run as root. You have to set user as a non-root user or else you will get error.
If you want to force apache to run as root, then you have to set a environment variable as below:
env CFLAGS=-DBIG_SECURITY_HOLE
Then you have to rebuild apache before you can run it as root.
I have found the issue - SELinux was blocking PHP from accessing certain functions. Putting SELinux into permissive mode has fixed the issues (although, I'd rather not have to leave SELinux in permissive mode; I'd rather find a way of allowing certain functions if I can).
I have a solution:
command runs from console, but not from php via exec/system/passthru.
The issue is the path to command. It works with the absolute path to command
So that:
wkhtmltopdf "htm1Eufn7.htm" "pdfIZrNcb.pdf"
becomes:
/usr/local/bin/wkhtmltopdf "htm1Eufn7.htm" "pdfIZrNcb.pdf"
And now, it's works from php via exec
Where command binary you can see via whereis wkhtmltopdf
Tore my hair out trying to work out why PHP exec works from command line but not from Apache. At the end, I found the following permissions:
***getsebool -a | grep httpd*** ---->
**httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_sys_script_anon_write --> off**
USE: setsebool -P httpd_ssi_exec 1
SEE: https://linux.die.net/man/8/httpd_selinux
Your problem is not an execution issue but the syntax of the exec command. The second argument is always returned as an array and contains a single line of the output in each index. The return value of the exec function will contain the final line of the commands output. To show the output you can use:
foreach($output as $line) echo "$line\n";
See http://php.net/manual/en/function.exec.php for details. You can also get the command's exit value with a third argument.

How to check what user php is running as?

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

Categories