PHP addslashes() Command Injection Bypass

PHP contains a method addSlashes() that many new programmers use (incorrectly) to sanitize their input. I will show you how to bypass this method when it's used to sanitize input to protect against a command injection.

Vulnerable code Patter

Code is vulnerable to this bypass if it followes the below pattern. Since this is PHP I'm going to assume we also are interacting with a website so query params are used.

public function vulnerableFunc($tainted) {
    $sanitized = addslashes($tainted);
    ...
    eval(...$sanitized...);
}

Why doesn't this work?

addslashes adds a backslahes in from of the following characters:

  • single quote (')
  • double quote (")
  • backslash ()
  • NUL (the NUL byte)

This list leaves open the values for variable replacement ${}. This allows us to write an input that will not be touched by addSlashes and then later when it is evaluated it will be replaced with a dangerous command injection input.

The Bypass

For this example I'll use a basic GET call:

GET /index.php?input=

Where Command is being passed to addslashes() and later into an eval() block. We will try to run the command ls ./ using this input.

To run a system command inside eval we will want to get the following string into the Eval block: ${system("ls /")}.

Step 1

First we'll make our "safe" string to get past addslashes().

${system($_GET[1])}

When evaluated this will call the system method with the value of the query param "1".

Step 2

Now we'll need to set the value of that query param.

1=ls+/

This is simply our command url encoded. Since we used a 'space' character we'd need to replace that with a '+'.

Final Query

So our final full query will be:

GET /index.php?input=${system($_GET[1])}&1=ls+/

So our code block will end up resolving in the following manner:

eval("${system($_GET[1])}");

eval("$system("ls /");

Now we can run any command as the PHP server on the underlying CLI.


Sources and Further Reading

PHP addslashes manual