Skip to content

PHP

PHP is one of the most used languages for back-end web development and therefore it has become a target by hackers. PHP is a language which makes it painful to be secure for most instances, making it every hacker's dream target.

Overview

PHP is a C-like language which uses tags enclosed by <?php ... ?> (sometimes just <? ... ?>). It is inlined into HTML. A word of advice is to keep the php docs open because function names are strange due to the fact that the length of function name is used to be the key in PHP's internal dictionary, so function names were shortened/lengthened to make the lookup faster. Other things include:

  • Variables start with $: $name
  • Variable variables: $$name
  • Request-specific dictionaries: $_GET, $_POST, $_SERVER

Example

<?php
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['email']) && isset($_POST['password'])) {
        $db = new mysqli('127.0.0.1', 'cs3284', 'cs3284', 'logmein');
        $email = $_POST['email'];
        $password = sha1($_POST['password']);
        $res = $db->query("SELECT * FROM users WHERE email = '$email' AND password = '$password'");
        if ($row = $res->fetch_assoc()) {
            $_SESSION['id'] = $row['id'];
            header('Location: index.php');
            die();
        }
   }
?>
<html>...

This example PHP simply checks the POST data for an email and password. If the password is equal to the hashed password in the database, the use is logged in and redirected to the index page.

The line email = '$email' uses automatic string interpolation in order to convert $email into a string to compare with the database.

Type Juggling

PHP will do just about anything to match with a loose comparison (\=\=) which means things can be 'equal' (\=\=) or really equal (\=\=\=). The implicit integer parsing to strings is the root cause of a lot of issues in PHP.

Type Comparison Table

Comparisons of $x with PHP Functions

Expression gettype() empty() is_null() isset() boolean: if($x)
$x = ""; string TRUE FALSE TRUE FALSE
$x = null; NULL TRUE TRUE FALSE FALSE
var $x; NULL TRUE TRUE FALSE FALSE
$x is undefined NULL TRUE TRUE FALSE FALSE
$x = array(); array TRUE FALSE TRUE FALSE
$x = array('a', 'b'); array FALSE FALSE TRUE TRUE
$x = false; boolean TRUE FALSE TRUE FALSE
$x = true; boolean FALSE FALSE TRUE TRUE
$x = 1; integer FALSE FALSE TRUE TRUE
$x = 42; integer FALSE FALSE TRUE TRUE
$x = 0; integer TRUE FALSE TRUE FALSE
$x = -1; integer FALSE FALSE TRUE TRUE
$x = "1"; string FALSE FALSE TRUE TRUE
$x = "0"; string TRUE FALSE TRUE FALSE
$x = "-1"; string FALSE FALSE TRUE TRUE
$x = "php"; string FALSE FALSE TRUE TRUE
$x = "true"; string FALSE FALSE TRUE TRUE
$x = "false"; string FALSE FALSE TRUE TRUE

"==" Comparisons

TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "php" ""
TRUE ==TRUE== FALSE ==TRUE== FALSE ==TRUE== ==TRUE== FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE
FALSE FALSE ==TRUE== FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE ==TRUE== ==TRUE== FALSE ==TRUE==
1 ==TRUE== FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE
0 FALSE ==TRUE== FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE ==TRUE== FALSE ==TRUE== ==TRUE==
-1 ==TRUE== FALSE FALSE FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE
"1" ==TRUE== FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE
"0" FALSE ==TRUE== FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE
"-1" ==TRUE== FALSE FALSE FALSE ==TRUE== FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE
NULL FALSE ==TRUE== FALSE ==TRUE== FALSE FALSE FALSE FALSE ==TRUE== ==TRUE== FALSE ==TRUE==
array() FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE== ==TRUE== FALSE FALSE
"php" ==TRUE== FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE== FALSE
"" FALSE ==TRUE== FALSE ==TRUE== FALSE FALSE FALSE FALSE ==TRUE== FALSE FALSE ==TRUE==

"===" Comparisons

TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "php" ""
TRUE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
1 FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
0 FALSE FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
-1 FALSE FALSE FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE FALSE
"1" FALSE FALSE FALSE FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE FALSE
"0" FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE FALSE
"-1" FALSE FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE== FALSE FALSE FALSE FALSE
NULL FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE== FALSE FALSE FALSE
array() FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE== FALSE FALSE
"php" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE== FALSE
"" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ==TRUE==

File Inclusion

PHP has multiple ways to include other source files such as require, require_once and include. These can take a dynamic string such as require $_GET['page'] . ".php"; which is usually seen in templating.

PHP Stream Filters

PHP has its own URL scheme: php://... and its main purpose is to filter output automatically. It can automatically remove certain HTML tags and can base64 encode as well.

Example

$fp = fopen('php://output', 'w');
stream_filter_append(
       $fp,
       'string.strip_tags',
       STREAM_FILTER_WRITE,
       array('b','i','u'));
fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
/* <b>bolded text</b> enlarged to a level 1 heading */

Exploitation

These filters can also be used on input such as:

  • php://filter/convert.base64-encode/resource={file}
  • include, file_get_contents(), etc. support URLs including PHP stream filter URLs (php://)
  • include normally evaluates any PHP code (in tags) it finds, but if it’s base64 encoded it can be used to leak source