并且命名要符合规范,符合骆驼式命名法,比如说属性名为abc,那么get方法为public Type getAbc(),set方法为public void setAbc(Type value)
那么这种class就被称为JavaBean,其实也就是规范写法的类,比如说举个例子:
public class a {
private String name = "c1oud";
private int age = 20;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
}
import org.apache.commons.beanutils.PropertyUtils;
public class CB {
public static void main(String[] args) throws Exception{
a c = new a();
System.out.println(PropertyUtils.getProperty(c, "name"));
System.out.println(PropertyUtils.getProperty(c,"age"));
}
}
Commons BeanUtils
前面我们认识了
java.util.PriorityQueue
,它在Java
中是一个优先队列,队列中每一个元素有自己的优先级。在反序列化这个对象时,为了保证队列顺序,会进行重排序的操作,而排序就涉及到大小比较,进而执行java.util.Comparator
接口的compare()
方法。那么,我们是否还能找到其他可以利用的
java.util.Comparator
对象呢?了解Apache Commons Beanutils
在这之前还是先了解一下什么是
Apache Commons Beanutils
,它是是Apache Commons工具集下的另一个项目,能提供对普通Java
类对象(JavaBean
)的一些操作方法。JavaBean
JavaBean是一种符合命名规范的class,具体要求如下:
那么这种class就被称为JavaBean,其实也就是规范写法的类,比如说举个例子:
这就是一个很简单的
JavaBean
而在
commons-beanutils
中就提供了一种静态方法,可以让使用者直接调用到任意JavaBean
对象中的getter
方法,这个方法其实是危险的,它就是PropertyUtils.getProperty
,用法也很简单,只有两个参数,前面是JavaBean
对象,后面是想要获取的方法名,比如说:PropertyUtils.getProperty(people,"name"),
看看完整的代码:这样就成功调用到了
c
对象的getName()
和getAge()
方法并且
PropertyUtils.getProperty
还支持递归获取属性,比如a
对象中有属性b
,b
对象中有属性c
,我们可以通过PropertyUtils.getProperty(a, "b.c");
的方式进行递归获取,这样就可以很方便的调用任意对象的getter
方法,适用于在不确定JavaBean
是哪个类对象时使用利用链的构造
之前在学习
利用TemplatesImpl加载字节码
的时候分析过利用链:在
cc3
里面用的是TrAXFilter
的构造方法来调用的newTransformer()
方法,不过其实还有一个方法可以调用到newTransformer()
方法,而且它也是public
类型,它就是getOutputProperties()
方法:值得注意的是,之前说过
getter
方法的定义就是get
后面跟属性名,明显这个是符合的,那就可以思考是否可以通过PropertyUtils.getProperty
方法调用这个getter
方法,最后加载字节码导致rce
呢?现在我们的目的就是找到一个方法里面调用了
PropertyUtils.getProperty
方法,恰好在org.apache.commons.beanutils.BeanComparator#compare
里面有个这个方法:BeanComparator
类是commons-beanutils
用来比较两个JavaBean
是否相等的类,它实现了java.util.Comparator
接口,自然就会有compare
方法;这个方法传入两个对象,如果
this.property
为空,则直接比较这两个对象;如果this.property
不为空,则用PropertyUtils.getProperty
分别取这两个对象的this.property
属性,比较属性的值,总之取this.property
属性的时候就可以调用到getter
方法了。构造利用链
因为
getOutputProperties()
方法是TemplatesImpl
类里面的,所以先构造TemplatesImpl
对象然后实例化
BeanComparator
,这里先不设置property
,防止报错,后面再用反射来操作,直接调用构造函数的话,property
默认就为空,现在要想办法调用BeanComparator
类里面的compare
方法想到优先队列
PriorityQueue
反序列化的时候可以一步步调用到compare
方法,把这个comparator
放进去,最后调用到comparator.compare()
的时候就可以让他连起来了这里还是先添加两个无害的对象
1
进去,防止出问题,因为我们还没有设置property
,当this.property
为空时,相当于就是直接比较这两个对象,对这两个1
进行排序,没有什么影响,在最后用反射将property
的值设置为outputProperties
,并将队列中的任意一个对象替换成恶意的TemplatesImpl
对象;跟进后发现
queue
这个属性本来就是数组,所以后面用Object
数组装的替换的对象,用Object
数组的原因也是因为Object
数组是根对象,里面放什么类型的对象都可以,更方便。所以替换成恶意的
TemplatesImpl
对象。最终写出完整poc:完整poc
利用CB链来攻击shiro
回顾一下之前用
TemplatesImpl
打shiro
时,用到了几个依赖:前4个依赖都和项目本身有关,少了他们这个
demo
会出错或功能缺失。但是第5个依赖,commonscollections
主要是为了演示漏洞。那么,实际场景下,目标可能并没有安装commons-collections
,这个时候shiro
反序列化漏洞是否仍然可以利用呢?这里我们将
pom.xml
中关于commons-collections
的这部分删除,重新加载Maven
此时观察
IDEA
中的依赖库,发现与cc
链相关的依赖确实被删除了,但是外部库里并没有导入CB
依赖,不过却加载了CB
依赖。也就是说,
Shiro
是依赖于commons-beanutils
的。那么,是否可以用到刚才分析的CB
链来进行攻击呢?构造poc
这里直接用上面的payload,加上shiro需要的加密代码
然后我就直接打出来了
不知道是不是mac的原因,但是按照p神的文章和其他师傅的文章,这里应该报一个这样的错
在java中如果两个不同版本的库使用了同一个类,而这两个类可能有一些方法和属性有了变化,此时在序列化通信的时候就可能因为不兼容导致出现隐患。
因此,
Java
在反序列化的时候提供了一个机制,序列化时会根据固定算法计算出一个当前类的
serialVersionUID
值,写入数据流中;反序列化时,如果发现对方的环境中这个类计算出的
serialVersionUID
不同,则反序列化就会异常退出,避免后续的未知隐患。当然,开发者也可以手工给类赋予一个
serialVersionUID
值,此时就能手工控制兼容性了。所以,出现错误的原因就是,本地使用的
commons-beanutils是1.9.2
版本,而Shiro中自带的commons-beanutils是1.8.3
版本,出现了serialVersionUID
对应不上的问题。解决方法也比较简单,将本地的
commons-beanutils也换成1.8.3版本
改了以后再打来看,我还是一打就出来了,这个先不研究,重点是学会原理
接着p神的看,这里按道理还会报一个这样的错
那首先要找到,看哪里用了
ComparableComparator
这个类,看到这里但我们实例化的时候是这样用的
用的是无参构造,实际上是因为
this(null)
这个语句 正在做的是调用另一个带有一个参数的类中的另一个构造函数,并将null值作为该参数传递。这是构造函数的特殊语法,也就是还是进入到了有参构造嘛。并且没有传
comparator
默认进入到第二个构造函数,也就会用到了ComparableComparator
这个类,然后因为也是this()
这个语句会进入到第三个构造函数,但我们不能用到他,也就是说我们需要找一个其他类来代替他。无依赖的shiro反序列化利用链
这里我们需要找的类还要满足这些条件:
通过IDEA的功能,我们找到一个 CaseInsensitiveComparator :
CaseInsensitiveComparator
类是java.lang.String
类下的一个内部私有类,其实现了Comparator
和Serializable
,且位于Java
的核心代码中,兼容性强,符合所有条件我们通过
String.CASE_INSENSITIVE_ORDER
,即可拿到上下文中的CaseInsensitiveComparator
对象,用它来代替ComparableComparator
生成
payload
的时候出错了这个简单,应该是类型的问题,我们后面添加的是两个整形对象,不能转换成字符串类型,直接将add(1)、add(2)改为add("1")、add("2")
最终poc