Security vulnerability with exec(), shell_exec(), curl_exec() - php

Occasionally, I use exec(), shell_exec(), and curl_exec(). Below are typical uses. Assume that where ever I have a PHP variable in them (i.e. $html in the first one), there is a chance that the user has the ability to modify its content.
What should I be concerned about from a security vulnerability perspective? Is escapeshellcmd() and escapeshellarg() the answer, and if so where should it be used?
$cmd='echo "html + '.$html.'" | htmldoc --format pdf > '.$filename;
$cmd='/usr/bin/convert '.$docs.' '.$filename;
$cmd='HOME='.$dir.'; /usr/bin/libreoffice3.5 --headless -convert-to pdf --outdir '.$dir.' '.$file_org;
$cmd='wget -O '.$file_org.' "'.$url.'"';
$cmd='/opt/wkhtmltopdf/bin/wkhtmltopdf "'.$url.'" '.$paramaters;
$cmd='/usr/bin/php -q '.$worker.' '.$session_id.' >/dev/null &';
exec($cmd);
$cmd='sendfax -n -m -w -i '.$id.' -o JohnDoe -D -S "hello#gmail.net" -s "us-leg" -f "'.$from.'" -d "'.$to.'" '.$doc_list;
$cmd = "faxstat -s | grep \"^$jid \"";
$output = shell_exec($cmd);
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_USERAGENT, $_GET['user_agent'] ? $_GET['user_agent'] : $_SERVER['HTTP_USER_AGENT'] );
curl_setopt($ch,CURLOPT_POSTFIELDS,array('aaa'=>$aaa,'bbb'=>$bbb));
$result = curl_exec($ch);

If you don’t validate and/or escape the input values properly, anyone can execute arbitrary commands on your system in behalf of the user that runs PHP.
For command arguments, there is escapeshellarg. Make sure you escape the whole argument value, e.g.:
$cmd='echo '.escapeshellarg('html + '.$html).' | htmldoc --format pdf > '.escapeshellarg($filename);
$cmd='/usr/bin/convert '.escapeshellarg($docs).' '.escapeshellarg($filename);
// […]
$cmd='sendfax -n -m -w -i '.escapeshellarg($id).' -o JohnDoe -D -S "hello#gmail.net" -s "us-leg" -f '.escapeshellarg($from).' -d '.escapeshellarg($to).' '.escapeshellarg($doc_list);

Related

php system() command files due to '&' in password

I'm running the following command:
$cmd = escapeshellcmd( "echo '$password' | sudo -S mv \"$old\" \"$new\" " );
system( $cmd, $out );
This works when $password doesn't contain & but fails if it does.
How do I get this to allow & and any other special characters in the password ?
Thanks
Don't use escapeshellcmd() on the whole command, use escapeshellarg() on individual arguments.
$password_esc = escapeshellarg($password);
$cmd = "echo $password_esc | sudo -S mv '$old' '$new'";
system($cmd, $out);
You don't need quotes around $password_esc because escapeshellarg() adds them.

PHP how to run multi bash command in background

To run one command in the background, it works well.
$cmd = 'ffmpeg -re -i ./97.mp4 -vcodec copy -acodec copy -f flv -y rtmp://example.com/c/190843?auth_key=7e2682b5 > output 2>&1 </dev/null &';
exec($cmd, $output, $return_var);
Then I need to sleep for some time before the ffmpeg command. I refer to How do I run multiple background commands in bash in a single line? which works well directly in the bash console.
While not works in the below PHP script, which will return when the bash command finishes running.
$cmd = '(sleep 5; ffmpeg -re -i ./97.mp4 -vcodec copy -acodec copy -f flv -y rtmp://example.com/c/190843?auth_key=7e2682b5 > output 2>&1 </dev/null) &';
exec($cmd, $output, $return_var);
I think you also need to handle sleep's stdout/stderr.
( sleep 5 > /dev/null 2>&1; ...; ) &
Or you can put the redirection after ( ... ):
( sleep 5; ffmpeg ...no redir here...; ) < /dev/null > /dev/null 2>&1 &
To run multiple commands from on bash command; concatenate using &&.
For instance:
sleep 5 && echo hello && sleep 2 && echo world
This trick can be particularly useful in cron tasks to be able to sequence multiple items within the same minute, as a different sleep value can be used as an offset before starting the command.

PHP exec output text with ansi2html problem

I use ansi2html to covert colors for HTML
But when I use exec in php for run bash file, the output is not correct.
exec("inxi.sh 2>&1", $returnOut, $stdout);
echo $returnOut[0];
<pre style="color:#bbb;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:break-word">␃12System: ␃␃12Host␃ TiTAN ␃12Kernel␃ 5.3.0-59-generic x86_64 ␃12bits␃ 64 ␃12compiler␃ gcc ␃12v␃ 9.2.1 ␃12Console␃ N/A ␃
If I run bash file with terminal its return:
<pre style="color:#bbb;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:break-word"><span style="color:#55f">System:</span>
inxi.sh
#!/bin/bash
inxi -xxx -C -D -G -I -m -M -n -R -s -S --usb -c 2 | ansi2html -n

exec issue with netstat and lsof

I want to check if a certain tunnel exists from inside PHP using (any of these commands):
$(which lsof) -i -n | grep ssh
$(which netstat) -a | grep "localhost:ssh"
The issue is that when I run the commands in the shell everything is fine but from php running them like:
$reply = exec(CMD);
always return nothing.
Any ideas?
Thank you!
You could redirect stderr to stdout and get the $output and $return_var. To do that, change your exec() call like this:
exec('$(which lsof) -i -n | grep ssh 2>&1', $output, $return_var);
var_dump($return_var);
var_dump($output);
More info about exec here: http://php.net/manual/en/function.exec.php (have a look at $output and $return_var parameters).
I think the issue is more to do with how PHP interprets your command...
In this case (assuming instead of CMD you write same command you try in shell), it would try to:
$reply = exec($(which lsof) -i -n | grep ssh);
means it would try to substitute the bold part as a PHP variable, and try to execute the resultant string. As the output of "-i -n |grep ssh" is null, so you get nothing as a result.
I would suggest you to instead:
$lsof = exec(which lsof);
$reply = exec($lsof -i -n | grep ssh);

wget Failing in php exec

I have a little script that I'm trying to run but it dies at exec()
<pre><?php
ini_set("display_errors", 1);
$command = "wget --save-cookies cookies.txt \
--post-data '***' \
--keep-session-cookies \
http://site.com/ac_login.php;
wget --load-cookies cookies.txt \
--keep-session-cookies \
-p http://site.com/ac_landing.php;";
exec($command, $output) or die('fail');
foreach ($output as $num => $line) {
echo $num + 1 . ": " . $line . "\n";
}
?></pre>
If I remove the \ at the end of each line I get a response of
1: wget: missing URL
2: Usage: wget [OPTION]... [URL]...
3:
4: Try `wget --help' for more options.
5: wget: missing URL
6: Usage: wget [OPTION]... [URL]...
7:
8: Try `wget --help' for more options.
I tried moving all the commands to one line but then it dies again. What am I doing wrong? How can I retrieve the error in this script? Adding in a 3rd param for result in exec returns empty.
I'm using this for reference https://stackoverflow.com/a/1432161/763468
The commands work in an SSH console.
First off, I don't think you need that semi-colon after the file name
-p http://site.com/ac_landing.php;
to
-p http://site.com/ac_landing.php
Did you try one command per exec call?
exec("wget --save-cookies cookies.txt --post-data '***' --keep-session-cookies http://site.com/ac_login.php");
exec("wget --load-cookies cookies.txt --keep-session-cookies -p http://site.com/ac_landing.php");

Categories