暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Python 代码审计的另外几个反序列化漏洞检查点

安全档案 2019-10-27
993

哔哔两句

最近刚做完某个白盒渗透项目,通读了整个项目代码后发现了几个比较明显的 Python 反序列化漏洞的问题。
代码中使用了 Pickle 这个 Python 反序列化模块,除此以外还发现了另外一个比较陌生的模块。
from sklearn.externals import joblib
因为在这个项目中 pickle 模块加载的都是扩展名为 .pkl
 的文件,我认为它是 PicK Le 的缩写,经过资料查询也证明了这个猜想。
同时除了 pickle 模块,还有一个 joblib 模块也用它的 load() 函数加载了 .pkl
 的文件,这让我很好奇,问了几个朋友也没有认识这个模块的,谷歌也没找出关于这个模块的漏洞文章,python 反序列化漏洞都是在讲 pickle、cPickle 和 PyYaml 的。
于是我尝试了一下用 joblib 这个模块是否能达到反序列化的效果

结论是当然可以,对比生成后的反序列化字节码和跟踪 joblib.load() 函数发现其实他就是封装了 pickle。

而这个 sklearn 其实是一个用于机器学习的库,一般在大型项目中或者有关机器学习的项目中能找到,所以大家以后在白盒审计 python 项目时除了 pickle 和 cPickle 以外还可以注意一下 sklearn 的 joblib 模块。

举一反三

学习一个东西就要举一反三,所以在看完 sklearn 后又查了一些相关的资料。sklearn 的反序列化问题是由于它要在机器学习的过程中加载模型,所以会有一些反序列化的操作。但是机器学习的库不止 sklearn 一个,还有很多知名的机器学习第三方库,那么它们是否也存在同样的问题?

NumPy (21,219 commits / 11,711 star)

NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

这个是被曝存在过漏洞的(CVE-2019-6446),如果 load 方法的 allow_pickle 参数被允许的话,或 loads 方法参数可控,则会引起安全问题

numpy 的 load 函数中判断如果 allow_pickle 为 True,则调用 pickle.load
 函数

if not allow_pickle:
raise ValueError("Cannot load file containing pickled data "
"when allow_pickle=False")
try:
return pickle.load(fid, **pickle_kwargs)
except Exception:
raise IOError(
"Failed to interpret file %s as a pickle" % repr(file))

numpy.loads() 则是直接调用了 pickle.loads()

Demo

#!/usr/bin/python
# -*- coding:utf-8 -*-
# @Author : b1u3r
# @Time : 2019/9/10 21:53


import numpy


numpy.load("blue.pkl",allow_pickle=True )
with open("blue.pkl","rb") as d:
numpy.loads(d.read())

Pandas (20,109 commits / 21,245 star)

Pandas是一个强大的分析结构化数据的工具集;它的使用基础是Numpy(提供高性能的矩阵运算);用于数据挖掘和数据分析,同时也提供数据清洗功能。

这个库的问题还没有被提出,在 pandas.read_pickle() 函数中,同样是由 pickle.load() 引起

Demo

#!/usr/bin/python
# -*- coding:utf-8 -*-
# @Author : b1u3r
# @Time : 2019/9/10 21:53
import pandas


pandas.read_pickle("blue.pkl")

PyTorch (20,565 commits / 31,489 star)

PyTorch是使用GPU和CPU优化的深度学习张量库。

pytorch 也存在相同的问题,它的 load 函数中,有一个值为 pickle 对象的 pickle_module 参数。

在后面的反序列化的过程直接调用的是 pickle_module.load() 函数,相当于是在调用 pickle.load()

Demo

#!/usr/bin/python
# -*- coding:utf-8 -*-
# @Author : b1u3r
# @Time : 2019/9/10 21:53
import torch


torch.load("blue.pkl")

CheckList

以上三个是我从 python 的机器学习最常用、Commits 次数多的几个库中挑选出来的库,经过测试均存在反序列化的问题。

以下例举几个在 python 代码审计时针对反序列化漏洞的检查点。

CheckPoint 1

import pickle


pickle.load(open("blue.pkl","rb"))
with open("blue.pkl","rb") as d:
pickle.loads(d.read())

CheckPoint 2

import cPickle


cPickle.load(open("blue.pkl","rb"))
with open("blue.pkl","rb") as d:
cPickle.loads(d.read())

CheckPoint 3

import _pickle


_pickle.load(open("blue.pkl","rb"))
with open("blue.pkl","rb") as d:
_pickle.loads(d.read())

CheckPoint 4

from sklearn.externals import joblib
joblib.load("blue.pkl")

CheckPoint 5

from pickle import Unpickler


Unpickler(open("blue.pkl","rb")).load()

CheckPoint 6

import numpy
numpy.load("blue.pkl",allow_pickle=True )
with open("blue.pkl","rb") as d:
numpy.loads(d.read())

CheckPoint 7

import pandas


pandas.read_pickle("blue.pkl")

CheckPoint 8

import torch


torch.load("blue.pkl")

如何防御

其实让被加载的文件用户不可控,就能解决大部分问题,但这样往往在某些场景中不太容易做到。如果系统中存在任意文件写入的漏洞,即使限制了文件可控问题,也可以配合其提升成为任意代码执行。
过滤关键词?虽然也是个办法,但黑名单的方式总归会被各种各样的骚操作 bypass。
如果要被反序列化的对象仅仅只需要里面的一些属性数据的话,可以使用 json 模块,这样就避免了不必要的不安全的反序列化操作。


文章转载自安全档案,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论