1

Good day guys. The issue I am having is specifically with handling this specific input case.

A part of my project I need to do is to take argument though command line into a PHP script. for eg ./do_op_2.php "`rm -rf ~/`;" .

I have tried using escapeshellarg($argv[1]), escapesellcmd($argv[1]); but to no avail it still executes the command. I have tried iterating through the string looking for ` and ; before anything happens, it is still executed.

If there are any more specific questions please do ask, I am willing to give more information.

Code for those who are curious.

#!/usr/bin/php
<?php
unset($argv[0]);
$argv[1] = escapeshellarg($argv[1]);
$argv[1] = escapeshellcmd($argv[1]);
function    add($a, $b)
{
    if (is_numeric($a) && is_numeric($b))
        return ($a + $b);
    else    
        return (0);
}

function    minus($a, $b)
{
    if (is_numeric($a) && is_numeric($b))
        return ($a - $b);
    else    
        return (0);
}

function    mult($a, $b)
{
    if (is_numeric($a) && is_numeric($b))
        return ($a * $b);
    else    
        return (0);
}

function    divide($a, $b)
{
    if (is_numeric($a) && is_numeric($b))
        return ($a / $b);
    else    
        return (0);
}

function    mod($a, $b)
{
    if (is_numeric($a) && is_numeric($b))
        return ($a % $b);
    else    
        return (0);
}

function ft_split($str)
{
    $ret = array_filter(preg_split('/\s+/', $str));
    return ($ret);
}

if ($argc == 2)
{
    $split = ft_split(trim($argv[1], " \t"));
    if (is_numeric($split[0]) && is_numeric($split[2]))
    {
        if ($split[1] == "+")
            echo add(trim($split[0], " \t"), trim($split[2], " \t")) . "\n";
        else if ($split[1] == "-")
            echo minus(trim($split[0], " \t"), trim($split[2], " \t")) . "\n";
        else if ($split[1] == "*")
            echo mult(trim($argv[0], " \t"), trim($split[2], " \t")) . "\n";
        else if ($split[1] == "/")
            echo divide(trim($split[0], " \t"), trim($split[2], " \t")) . "\n";
        else if ($split[1] == "%")
            echo mod(trim($split[0], " \t"), trim($split[2], " \t")) . "\n";
        else
            echo "Syntax Error\n";
    }
    else
        echo "Syntax Error\n";
}else
    echo "Incorrect Parameters\n";
?>
7
  • Quoting myslef -> I have tried using escapeshellarg($argv[1]), escapesellcmd($argv[1]); but to no avail it still executes the command.
    – Julian Wolf
    Oct 2, 2018 at 10:49
  • I am not arguing, All I said was quoting myself, where I stated its still being executed. The command is stated in my eg.
    – Julian Wolf
    Oct 2, 2018 at 10:56
  • What does rm -rf ~/ have to do with your code? Specifically add() / minus() / mult() / divide() / mod()... I don't understand.
    – Attie
    Oct 2, 2018 at 10:57
  • What is the output, what happens, and what did you expect to happen? Please show the text shown on the terminal from you running the command.
    – Attie
    Oct 2, 2018 at 10:58
  • @Attie Problem is when executed via command line, it will execute the command rm -rf ~/ even though it has nothing to do with my code. This where my question lies. The output is -> it removes all files from root. For eg. ./do_op_2.php "rm -rf test.doc;" will delete test.doc instead of ignoring the command.
    – Julian Wolf
    Oct 2, 2018 at 10:59

1 Answer 1

0

The only thing I can think of is command substitution (see also parameter substitution) - something which happens in bash and other shells. If this is what's going on, then your reporting of the situation is a little misleading (read on).

It's very unlikely that PHP will be doing this, it'll be done by the shell, and there is no way to modify your code to prevent this... It's a feature of the shell.


For example a variable, using ${...}:

$ FOO="test"
$ echo ${FOO}
test

It's also possible to run a command and use the output (stdout) as the value with $(...):

$ echo $(date)
Tue 2 Oct 12:02:59 BST 2018

Another variant of this is using backticks:

$ echo `date`
Tue 2 Oct 12:04:03 BST 2018

You've listed the following in your question:

./do_op_2.php '`rm -rf ~/`;'

The use of single quotes (') should prevent the shell from substituting the backticks:

$ echo '${FOO}'
${FOO}
$ echo '`date`'
`date`

But using double quotes (") will not prevent this:

$ echo "${FOO}"
test
$ echo "`date`"
Tue  2 Oct 12:05:17 BST 2018

I can only presume that you've reported single quotes, but actually used double quotes when you observed this behaviour. Your comment supports this theory.

For eg. ./do_op_2.php "`rm -rf test.doc`;" will delete test.doc instead of ignoring the command.

5
  • 1
    Part of my university we get marked by fellow mischievous students, so needs to prevent against it... which isn't proving successful. But thank you
    – Julian Wolf
    Oct 2, 2018 at 11:13
  • Unfortunately that's not possible if you give them shell access... Perhaps setup a webserver for them to poke at instead ;-)
    – Attie
    Oct 2, 2018 at 11:14
  • Yea I'm still new to the formatting of this thing. so it freaks out. That's my bad thank you for the help.
    – Julian Wolf
    Oct 2, 2018 at 11:20
  • That's designed behaviour as outlined in my answer... single quotes prevents substitution.
    – Attie
    Oct 2, 2018 at 11:21
  • You are aweome and valiant edition to the slack overflow community, thank you very much.
    – Julian Wolf
    Oct 2, 2018 at 11:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.