文章目录
介绍
burpsuite官网上一套不安全的反序列化实验(免费)
地址在 https://portswigger.net/web-security/deserialization/exploiting
本文是在这个实验室学习的记录
有针对实验的解决,也有别的一些
1. 如何识别不安全的反序列化
测试不安全的反序列化之前,您肯定要能够识别出序列化对象,下面简略介绍两种语言的序列化格式
以便您能够在遇到它们的时候识别出它们
1.1. PHP序列化格式
PHP的序列化对象是可读的,可以用文本表示的(JAVA的则是二进制流,您无法用文本阅读器查看)
其中字母代表数据类型,数字代表每项的长度
若 User
具有以下属性的对象:
$user->name = "carlos";
$user->isLoggedIn = true;
序列化后,该对象可能看起来像这样:
O:4:"User":2:{
s:4:"name":s:6:"carlos"; s:10:"isLoggedIn":b:1;}
解释:
O:4:"User"
- 具有4个字符的类名称的对象 "User"
2
-对象具有2个属性
s:4:"name"
-第一个属性的键是4个字符的字符串 "name"
s:6:"carlos"
-第一个属性的值是6个字符的字符串 "carlos"
s:10:"isLoggedIn"
-第二个属性的键是10个字符的字符串 "isLoggedIn"
b:1
-第二个属性的值是布尔值 true
PHP 序列化的方法是serialize()
和unserialize()
1.2 Java序列化格式
JAVA(还有一些别的语言Ruby等) 使用二进制序列化格式
这使人难以阅读,但是序列化数据有一些固定的特征
例如,序列化的Java对象始终以相同的字节开头,它们是 ac ed
Base64下显示为显示rO0
。
如
rO0ABXNyACJkYXRhLnNlc3Npb24udG9rZW4uQWNjZXNzVG9rZW5Vc2Vyc1%2bhUBRJ0u8CAAJMAAthY2Nlc3NUb2tlbnQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACHVzZXJuYW1lcQB%2bAAF4cHQAIEhyUGQ1WVRiYThnb3VMbkZKNE5RSlVNUGFIM0h5ZkUxdAAGd2llbmVy
任何实现该接口的类java.io.Serializable
都可以序列化和反序列化
readObject()
方法 用于从中读取和反序列化数据InputStream
。
2. 操作序列化对象
不安全的反序列化就包括了用户可以对序列化对象进行修改
这可能导致一些越权,代码执行等漏洞
修改幅度有大有小,有的是仅仅修改序列化中的部分字符
有的则是重新生成一个序列化对象,传给网站进行反序列化
在处理序列化对象时可以采用两种方法:
可以直接以对象的字节流形式对其进行编辑,
也可以使用相应的语言编写简短的脚本来自己创建和序列化新对象。
使用二进制序列化格式时,后一种方法通常更容易
2.1. 修改对象属性
介绍
属于修改幅度较小的清空,仅仅修改属性不会使反序列化报错
也保留了原有对象的结构
举一个简单的例子,考虑一个使用序列化User
对象的网站,该网站将有关用户会话的数据存储在cookie中。
如果攻击者在HTTP请求中发现了序列化对象,则他们可能会对其进行解码以找到以下内容:
O:4:"User":2:{
s:8:"username":s:6:"carlos"; s:7:"isAdmin":b:0;}
注意到这里的isAdmin属性,
攻击者可以简单地将该属性的布尔值更改为1
(true),重新编码对象,然后使用此修改后的值覆盖其当前cookie
加入网站用如下代码检查当前用户是否有权访问某些管理功能:
$user = unserialize($_COOKIE);
if ($user->isAdmin === true) {
// allow access to admin interface
}
就可以越权访问某些页面
实验
一个购物网站页面
利用给我们的 wiener:peter
可以登录
登录后查看Cookie,base64解码后为
O:4:"User":2:{
s:8:"username";s:6:"wiener";s:5:"admin";b:0;}
尝试修改为(经过尝试需要每一次都修改,burpsuite直接修改cookie值)
O:4:"User":2:{
s:8:"username";s:6:"wiener";s:5:"admin";b:1;}
再base64加密,url加密得到
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjoxO30%3D
修改后出现了管理盘表
进入后有删除用户的操作
删除carlos用户即通过
2.2. 修改数据类型
介绍
我们已经看到了如何修改序列化对象中的属性值,修改数据类型有时候也会有意想不到的效果
这种效果可能基于PHP 的弱等于比较 ==
例如,如果在整数和字符串之间执行弱比较,PHP将尝试将字符串转换为整数,即结果5 == "5"
为true
。
这也适用于以数字开头的任何字母数字字符串。
在这种情况下,PHP将根据初始数字有效地将整个字符串转换为整数值。字符串的其余部分将被完全忽略。因此,5 == "5 of something"
在实践中被视为5 == 5
比较0 :
0 == "Example string" // true
因为没有数字,所以字符串中的数字为0。PHP将整个字符串视为整数0
考虑这种松散的比较运算符与反序列化对象中的用户可控制数据一起使用的情况。这可能会导致危险的逻辑缺陷。
$login = unserialize($_COOKIE)
if ($login['password'] == $password) {
// log in successfully
}
假设攻击者修改了password属性,使其包含整数0
而不是预期的字符串。只要存储的密码不是以数字开头,该条件将始终返回true
从而身份验证绕过。
请注意,以任何序列化的对象格式修改数据类型时,务必记住也要更新序列化数据中的任何类型标签和长度指示符,这一点很重要。否则,序列化的对象将被破坏并且不会被反序列化
实验
任务是: 编辑会话cookie中的序列化对象以访问administrator帐户。然后,删除Carlos。
我们登录后的cookie值:
O:4:"User":2:{
s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"XaUdeGmBn1wE6eB0QDcNSze28JC6JGhb";}
用户要修改为administrator,access_token应该是验证身份的
如果将access_token修改为整形,然后值修改为0/1/2/3/4/5/6/7 …
需要一次次尝试,因为如果与access_token比较的值前几位包含了数字就需要不停尝试,直到比较成功
修改administrator: s:8:"username";s:13:"administrator";
修改access_token : s:12:"access_token";i:0;}
拼接就是
O:4:"User":2:{
s:8:"username";s:13:"administrator";s:12:"access_token";i:0;}
处理后
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjEzOiJhZG1pbmlzdHJhdG9yIjtzOjEyOiJhY2Nlc3NfdG9rZW4iO2k6MDt9
burp抓包改cookie
我们成功以管理员身份访问该网站
成功删除Carlos,过关
3. 利用网站程序功能
除了简单地检查属性值外,网站的功能还可能会对反序列化对象中的数据执行危险的操作。
在这种情况下,您可以使用不安全的反序列化来传递意外数据,并利用相关功能造成损害
例如,作为网站“删除用户”功能的一部分,通过访问$user->image_location
属性中的文件路径来删除用户的个人资料图片。
如果这$user
是从序列化对象创建的,则攻击者可以通过将带有image_location
集合的已修改对象传递到任意文件路径来利用此漏洞。
删除他们自己的用户帐户也将删除任意文件。
实验:
一个BLOG网站
用户页面存在删除账号的选项,我们的任务是删除 Carlos 下的 morale.txt
cookie解码后
O:4:"User":3:{
s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"ycE1G0NQK93UD06osTkM7OzCOMfSVlT0";s:11:"avatar_link";s:19:"users/wiener/avatar";}
我们尝试通过更改avatar_link来完成任务
更改为s:23:"users/Carlos/morale.txt";
O:4:"User":3:{
s:8:"username";s:6:"wiener";s:12:"access_token";s