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