【技术分享】看我如何进行Python对象注入利用

https://p3.ssl.qhimg.com/t013b408b5045e6d58c.png

译者:天鸽

预估稿费:130RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


简介

在今天的 Defencely Lab 中,我们将详细介绍和演示 Python 对象注入攻击(Python Object Injection)的细节。整个演示将使用我们专门编写的易受攻击的应用程序和漏洞,源码可以在这里找到 – Github – Python Object Injection

需要的基础知识

了解基本的 OOP 概念

Python 类和对象简介

什么是类?

类是一个模板,你可以在其中存储变量和方法。

什么是对象?

对象可以是任何东西,一个类的实例,一个变量或者一个类中的函数。

让我们来看一个实际的例子:

http://p0.qhimg.com/t01986ba5640dc07a42.jpg

在这里,你可以看到我们创建了一个名为 Test 的类实例,并将它分配给了一个名为 simpleapp 的变量,将变量 rony 的值传递给了该实例。

输出如下:

simpleapp = Test(rony)

当执行此代码时,python 会创建一个对象,然后将我们的值传递给第一个参数。每当 python 创建一个对象时,__init__ 函数就会被调用。__init__ 像 python 中的构造函数一样工作。

伴随着我们的输出,打印出了一个随机的数字,这是因为我们直接打印出了实例分配的变量,以显示 python 是如何对待一个对象的。

 

什么是对象注入?

对象注入是一种应用程序级的安全漏洞,它允许攻击者根据上下文执行严重的攻击

Python 专门将某原生模块命名为“Pickle”,它在特定情况下容易受到对象注入攻击。

危险发生在当用户控制的数据被传递时,Python 已经在其官方文档中指出 pickle 是一个存在风险的模块。

http://p1.qhimg.com/t01e1125c6724057f20.png

我们可以将“Pickle”模块与 PHP 中的 serialize/unserialize() 原生函数进行比较,当存在用户输入时该 PHP 函数也容易受到对象注入攻击。

在 Python 中,与 PHP 不同的是,我们不需要一个魔术方法作为注入到对象的条件。

在 python 中进行序列化和反序列化仅仅是对数据的 PicklingUnpickling

除非用户输入的数据被传递到 Unpickling 的过程中,否则,Python 中数据的 Unpickling 并不一定是危险的。

下面是 Python 中 Pickled 和 Unpickled 的数据的样子:

http://p1.qhimg.com/t01d8f3ea4df77c258e.png


检测对象注入攻击

要实现对象注入,你必须在应用程序上执行一个白盒 Pentest。因为每当你在复杂对象上 pickling 时,Python 中的序列化数据都会带有类名、变量和值。

Pickle 模块提供了四种简单和快速 pickling 和 unpickling 的方法。

dump()

dumps()

load()

loads()

您可以在 Python 官方文档中找到它们各自的功能。

正如我已经提到的,Unpickling 数据并不一定是危险的,但如果你是在后端处理,那么 pickling 和 unpickling 用户输入的数据就是危险的。永远不要相信用户的输入。

如果所提供的数据是由用户控制的,那么很明显会被篡改。

因此,如果你看到 pickled 的数据正在通过 HTTP 方法传输,则可能存在对象注入。

 

了解易受攻击应用程序的工作流

文件名:pickle.py

http://p0.qhimg.com/t018be613b0a80b12c2.png

我们将研究上述代码,并据此实现一个对象注入。

忽略上面代码上写的所有内容,让我们集中精力在三件事情上。

在这里,arg 变量是用户的输入。

类 simpleApp 中的 final_workout() 方法将运行一个 python 文件。

app.secureaApp() 方法用于 unpickling 输入的数据。

现在,让我们更深入地了解这些方法正在扮演的角色。

simpleApp() 类中的 secureApp() 方法:

我假设你已经阅读了 Python 的官方文档,并且知道了这篇文章使用的所有方法的输入输出。

方法:

dump()

dumps()

load()

loads()

secureApp() 方法所做的是将文件名作为参数。使用 pickle 模块的 load() 方法 Unpickling 文件中的数据,并将 unpickled 的数据赋予变量 workDone。之后该变量会作为 final_workout() 方法的参数。

我们看看 final_workout() 方法的内容。

simpleApp() 类中的 final_workout() 方法:

该方法创建一个名为 code.py 的 python 文件,将 unpickled 的数据写入文件并运行它。

我们来看看,当使用已经生成的序列化数据来运行易受攻击的应用程序 pickle.py 时,会发生什么。

http://p6.qhimg.com/t01bc42e3d7a923e887.png

正如我们看到的,它打印出了序列化数据的内容,并成功运行,打印出字符串。

下面我们将学习怎样构造自己的序列化数据,以在相同的应用程序上成功地进行对象注入。

编写漏洞利用

现在我们知道 pickle.py 正在使用序列化的数据,因此,我们将使用 dumps() 方法 pickle 我们构造的 payload。

文件名:exploit_pickle.py

http://p8.qhimg.com/t0123e4870e7ae60f48.png

我们将序列化一条包含了编码后系统命令的代码, 并在它工作时对其进行测试。

现在我们就成功地注入了自己精心构造的代码。

http://p1.qhimg.com/t0187bc51d665212ea5.png

(完)