Run a sed command from shell_exec in php - php

Please help me as I have been trying to get this to work for two days.
I have a text file which has the array to define username and passwords.
$USERS['user'] = 'pass1';
I am trying to make a PHP to change this password
//name - call_pwd.php
$commandline='./change_password ' . $_SESSION["logged"] . " " . $_POST["old_password"] . " " . $_POST["new_password"]
$output = shell_exec("$commandline");
Here is the bash file I made to change this password. Because I am not good at it I have to use so many variables to make it easily.
#!/bin/bash
#name - change_password
username=`echo "$1"`
old_password=`echo "$2"`
new_password=`echo "$3"`
old_string=`echo "\['$username'\] = '$old_password'"`
new_string=`echo "['$username'] = '$new_password'"`
sed -i "s/${old_string}/${new_string}/" passwords.php
if [ "$?" == 0 ]
then
echo "Password changed Successfully."
else
echo "Could not change password, try again."
fi
When I run this script from the root prompt it works fine and changes the password. But from PHP it won't work. It keeps giving me the message "Could not change password, try again."
As I read " and ' needs to be escaped if you want to use sed with php and I tried that with
sed -i \"s/${old_string}/${new_string}/\" passwords.php
sed -i \""s/${old_string}/${new_string}/\"" passwords.php
The permissions on passwords.php is full permission for all users.
I have also tried putting absolute paths everywhere but that also didn't work.
The $output variable on my call_pwd.php comes out as when I echo $commandline $old_string and $new_string
change_password user pass1 pass2
\['user'\] = 'pass1'
['user'] = 'pass2'
Could not change password, try again.
Please help me. Thanks.
Apologies for such a long post.

Why are you doing it this way? You could do everything in PHP with [un]serialize() and file_[put/get]_contents().
$ php -r '
$USERS = [ "user" => "pass1" ];
file_put_contents("passwords.php", serialize($USERS));'
$ cat passwords.php;
a:1:{s:4:"user";s:5:"pass1";}
$ php -r '
$USERS = unserialize(file_get_contents("passwords.php"));
$USERS["user"] = "newpass";
file_put_contents("passwords.php", serialize($USERS));'
$ cat passwords.php
a:1:{s:4:"user";s:7:"newpass";}
I won't make any comment on the security implications of doing this, but if you want to simply change some values in a text file when you are already using PHP, why not just use PHP?

Related

How can I stop command injection when using shell_exec in php7?

I have an html form that asks the user to input a domain name, this is posted to the php7.0 page below for processing by a shell script which then passes output through aha for writing to an html page which is then displayed.
The problem I have is how can I prevent users from injecting commands like:
domain.com | rm * -rf
I thought this could be done using safe_mode and restricting the directory from which commands can be run but it seems this feature is now deprecated.
$domain_arg = escapeshellarg( $_POST['domain'] );
$today = date("Y-m-d-H:i:s");
$cmd = "/home/ubuntu/dtest/dtest.sh $domain_arg | aha -b -t 'Domain test of $domain_arg' > /var/www/website/results/$domain_arg.$today.html";
$output = shell_exec($cmd);
header("Location: http://the.web.com/results/$result.$today.html");
You use escapeshellarg on the arguments before running them, the result is a single quoted string such as 'domain.com | rm *'. Your problem is that you're not using this as a shell argument, but as a portion of a shell argument:
aha -b -t 'Domain test of $domain_arg'
This will absolutely cause the problems you're describing. Try something like this instead:
<?php
$domain_arg = escapeshellarg($_POST["domain"]);
$log_msg = escapeshellarg("Domain test of $_POST[domain]");
$today = date("Y-m-d-H:i:s");
$log_file = preg_replace(
"/[^\w:\\/.-]/i",
"_",
"/var/www/website/results/$_POST[domain].$today.html"
);
$cmd = "/home/ubuntu/dtest/dtest.sh $domain_arg | aha -b -t $log_msg > $log_file";
$output = shell_exec($cmd);
$result = rawurlencode($output); // just guessing that's where it comes from
$today = rawurlencode($today);
header("Location: http://the.web.com/results/$result.$today.html");
You should rather use escapeshellcmd() instead of escapeshellarg().

Passing GET/POST parameteres to php via commandline

I'll excuse myself behorehand because i'm quite sure there'll be some obvious solution or an answer already out there, but after quite some extensive search I just cant find it.
I'm developing a simplified web server as a project in .net. What i want to do is calling the php.exe for each HTML request to execute any php code within the file, and then return the result to my server where it will be served to the client.
This was quite simple without passing GET/POST parameters, but I can't find the way to make this work.
Right now i have this as my function to write the call the php via command line
Public Shared Function phpparse(ByVal requesttype As String, ByVal argnames() As String, ByVal argvals() As String)
Dim proc As Process = New Process
proc.StartInfo.FileName = "php\php.exe"
Dim B As New System.Text.StringBuilder
B.Append("-B ""$_")
B.Append(requesttype & " = array(")
For i As Integer = 0 To argnames.Length - 1
B.Append("'" & argnames(i) & "' => '" & argvals(i) & "', ")
Next
B.Remove(B.Length - 2, 2)
B.Append(");"" -F script.php")
InputBox("", "", B.ToString)
proc.StartInfo.Arguments = B.ToString
proc.StartInfo.UseShellExecute = False
proc.StartInfo.RedirectStandardOutput = True
proc.StartInfo.CreateNoWindow = True
proc.Start()
Return proc.StandardOutput.ReadToEnd
End Function
which returns something like this:
-B "$_GET = array('name' => 'John', 'email' => 'john.doe#no.com');" -F script.php
and should be calling this test php script:
<html>
<body>
Welcome <?php echo $_GET["name"]; ?><br>
Your email address is: <?php echo $_GET["email"]; ?>
</body>
</html>
but it gets stuck trying to read the answer
With php you could read the args like this:
<?php
if (isset($argv)) {
echo $argv[1]." ".$argv[2];
}
?>
this will return
John john.doe#no.com
I don't really get it how do you send the command line params.
You should just run the php like
php.exe John john.doe#no.com
I've found a work around the issue. I'm still looking for a proper solution but I can work with this for now
The parameters of the call to the PHP CLI should be
-r "$arrayname = array('arraypar1' => 'arrayval1', 'arraypar2' => 'arrayval2', ); require_once('C:\fullroutetofile\script.php');"
It seems that you can't call -B and -f at the same time, but require_once lets you bypass that.

Can not execute CL Command (AS400 command) in PHP script

I login to AS400 and go to QSHELL(STRQSH). After that I pasted the following command and run it in QSHELL
system "IVIEW/PRTDISTL APPNAME(MYJOBLOG) STMF(TEST_89.PDF) HOLD(*NO)"
It works. But when I execute the above command using PHP script as the follow
$cmd = "IVIEW/PRTDISTL APPNAME(MYJOBLOG) STMF(TEST_89.PDF) HOLD(*NO)";
$cmd = 'system "' . $cmd . '"';
$output = array();
exec ($cmd, $output , $retVal);
echo "return value code: " . $retVal;
It returns error code of 255. Please help me how to fix this issue. Thanks
Try the PHP Toolkit for i5/OS. There is a older Redbook that describes it: http://www.redbooks.ibm.com/redbooks/pdfs/sg247327.pdf
An example from there:
<HTML>
<?php
/* Connect to server */
$conn = i5_connect("localhost", "PHPUSER", "MYPASSWORD");
if (!$conn)
die("<br>Connection using \"localhost\" with USERID and PASSWORD failed. Error
number =".i5_errno()." msg=".i5_errormsg())."<br>";
else
echo "<br>Connection using \"localhost\" with USERID and PASSWORD OK!<br>\n";
/* Call Retrieve Network Attributes command */
$ret = i5_command("rtvneta", array(), array("sysname" => "sysn", "lclnetid"=>"lclnet"));
if (!$ret) die("<br>rtvneta command failed. errno=".i5_errno()."
msg=".i5_errormsg());
print "<h1><b>Results of \"rtvneta\" command </b></h1><br>" ;
print "System Name : $sysn<br>" ;
print "Local Net ID : $lclnet<br>" ;
/* Close connection */
i5_close($conn);
?>
</HTML>
I see two pontential problems:
PHP runs in PASE, not in QShell. Try to manually run your call from QP2TERM.
User rights. Make sure QTMHHTTP (or whatever user runs PHP) has the apropriate rights to the program you try to call.
You can check for further information in stdout, which you should have in $output, and your PHP-server joblog as mentioned at IBM i information center (possibly needing the flag 'system -K').

How to provide default value for user input in PHP?

Is there a PHP functionallity same as read -i in BASH so that a script can prompt the user and provide a default answer like this:
Are you doing ok? (yes/no): yes
Where "yes" is the default answer provided by the script, which the user can erase and input another.
The readline function does not seem to have what it takes. Is there any other way to do this?
Using a stream does not seem to work either:
<?php
echo "Are you doing ok? (yes/no): ";
$in = fopen('php://stdin', 'rw+');
fputs($in, 'yes'); // should be the default?
$answer = fgets($in);
fclose($in);
echo "\nYou entered: {$answer}\n";
Whatever is in written by the fputs($in, 'yes'); line is ignored:
Are you doing ok? (yes/no): yes
You entered:
Am I using the stream incorrectly? Or maybe there is some other way to achive the default value?
EDIT:
Maybe I simlified the example to much. The real issue is not a simple yes/no prompt - this is just an example. Let me emphasize again: I'm aiming for providing exactly the same functionallity as the read -i BASH command. The $answer in my specific case holds an URL, so I would like for the user to be provided with the first part of the url (scheme, host, port), so he can add/edit the rest (path, query), fragment. Like this:
Enter url: http://www.example.com/foo/
now the user complement the path with bar/baz and we get:
You entered: http://www.example.com/foo/bar/baz
But on the other hand the user also should have the option to erase the first part of the url and provide completely different string:
Enter url: ftp://www.my-super-specific-domain.com/foo/bar
There's no built in way of doing this because writing some code that does it is quite straight forward:
function writeQuestion($question, $answers)
{
echo $question . ' (' . implode('/', $answers) . '): ' . PHP_EOL;
}
function readAnswer($possibleAnswers, $defaultAnswer)
{
$in = fopen('php://stdin', 'rw+');
$answer = trim(fgets($in));
if(!in_array($answer, $possibleAnswers))
{
return $defaultAnswer;
}
return $answer;
}
$question = 'Are you doing ok?';
$answers = array('yes', 'no');
$defaultAnswer = 'yes';
writeQuestion($question, $answers);
$answer = readAnswer($answers, $defaultAnswer);
You can wrap standard bash read for prefilled/populated edit and call it from you main php cli script
bash script named xreadline:
#! /bin/bash
IFS="";read -r -p "$1" -i "$2" -e STRING;echo "$STRING"
main php cli script:
#!/usr/bin/php
<?php
function xreadline ($prompt,$prefill)
{
$on = exec ('./xreadline "'.$prompt.'" "'.$prefill.'"');
return $on;
}
$answer = xreadline ('Your answer: ', 'xyz');
echo $answer;
.....
This approach fully supports UTF8 instead of native PHP readline.
Comment messed my code so here is standalone php cli file with function call to "read" command.
Little bit tricky, but hopefully will work as supposed to. :-)
#!/usr/bin/php
<?php
function xreadline ($prompt,$prefill)
{
return exec ('/bin/bash -c \'read -r -p "'.$prompt.'" -i "'.$prefill.'" -e STRING;echo "$STRING";\'');
}
echo "Prompt test :\n";
$output = xreadline ("edit this prefilled prompt: ","prefilled stuff");
echo "\n";
echo $output;

PHP never testing true for file_exists while evaluating array value

My problem is I set an array value to the name of a server as follow:
$appserver[$i]=`grep $ip[2] /etc/hosts |awk '{print $2}'`;
Later I do a test to see if the server is up or not (using a wget).
If the test fails I keep track of that server being down by creating a file with that
name using touch:
$touch=`touch /home/steve/data/$appserver[$i];
The file gets created successfully.
Later when I go to test whether or not the file exists it never evaluates to true.
if(file_exists('/home/steve/data/$appserver[$i])) {
I have tried several different things including creating a new variable for
$appserver[$i] and testing against it, which also does not work:
I am running php 5.1.6 on RHEL 5.
Here is the full code:
$appserver[$i]=`grep $ip[2] /etc/hosts |awk '{print $2}'`;
echo "appserver[i] = $appserver[$i]\n";
$get=`wget $key->url 2> /dev/null`;
if(file_exists('/home/user/Start')) {
$color[$i]="green";
$rm=`rm -rf /home/user/Start`;
}
else {
$color[$i]="red";
if($hostname=="xxxxx" ) {
**if(file_exists('/home/user/data/$appserver[$i]))** {**
echo "do nothing appserver file exists\n";
$touch=`touch /home/steve/data/notmailed`;
}
else {
echo "No app file mailed alert\n";
$touch=`touch /home/user/data/$appserver[$i]`;
}
}
}
Thank you.
It should be:
if(file_exists("/home/steve/data/$appserver[$i]")) {
if(file_exists('/home/steve/data/$appserver[$i]')) {
' quoted strings do not interpolate variable values, so you're looking for a file whose literal name is $appserver[$i]. Use " quotes instead:
if(file_exists("/home/steve/data/$appserver[$i]")) {
Try this:
$appserver[$i] = "grep $ip[2] /etc/hosts |awk '{print $2}'";
//...
if(file_exists("/home/steve/data/$appserver[$i]"))
{
//...
}
Ensure that you use double-qoutes (") whereever you want the content of variables parsed into the declared string!

Categories