WEB2PY反序列化安全问题:CVE-2016-3957

web2py

前言

在一次渗透测试的过程中,我们遇到了用 web2py 框架建构的应用程式。为了成功渗透目标,我们研究了web2py,发现该框架范例应用程式中存在三个资讯泄漏问题,这些泄漏都会导致远程命令执行 (RCE)。由于范例应用程式默认是开启的,若没有手动关闭,攻击者可以直接利用泄漏资讯取得系统执行权限。这些问题编号分别为:CVE-2016-3952、CVE-2016-3953、CVE-2016-3954、CVE-2016-3957。

背景—老生常谈的Pickle Code Execution

在进一步说明前必须要先认识什么是反序列化安全问题?反序列化安全问题在本质上其实是物件注入,它的严重性取决于所注入的物件本身是否会造成危险行为,例如读写档。一般来说要透过反序列化建构一个成功的攻击有两个要点:

  1. 是否可控制目标所要反序列化的字串。
  2. 危险行为在反序列化后是否会被执行。这在实务上大概有下面两种情形:
  • 危险行为是写在魔法方法 (Magic Method) 里面,例如 PHP 的 __construct 在物件生成时一定会执行。
  • 反序列化后覆蓋既有物件,导致正常程式流程出现危险结果。

反序列化的问题在每个程式语言都会发生,但通常需要搭配看程式码拼凑出可以用的攻击流程,比较难利用。不过,某些实作序列化的函式库会将程式逻辑也序列化成字串,因此攻击者可以自定义物件直接使用,不再需要拼凑,例如今天要提的 Python Pickle。

直接举个 Pickle 的例子如下,我们制造了一个会执行系统指令 echo success 的物件 Malicious,并且序列化成字串 “cposix\nsystem\np1\n(S’echo success’\np2\ntp3\nRp4\n.”。当受害者反序列化这个字串,即触发执行该系统指令,因此打印出 success。

>>> import os
>>> import cPickle
>>> class Malicious(object):
... def __reduce__(self):
... return (os.system,("echo success",))
...
>>> serialize = cPickle.dumps(Malicious())
>>> serialize
"cposix\nsystem\np1\n(S'echo success'\np2\ntp3\nRp4\n."
>>> cPickle.loads(serialize)
success
0

这就是 Pickle 误用反序列化所造成的命令执行风险。攻击者很容易可以产生一个含有任意命令执行的序列化字串,进而使受害者在进行反序列化的过程中触发执行恶意命令。

反序列化 + 序列化字串可控

本次发现的问题主要来自web2py 本身的 session cookie 使用 Pickle 处理序列化需求 (CVE-2016-3957),而且因为 session cookie 的加密字串固定 (CVE-2016-3953),攻击者可任意伪造恶意的序列化字串造成前面所介绍的命令执行风险。细节如下。

CVE-2016-3957

web2py 的应用程式如果使用 cookie 来储存 session 资讯,那么在每次接到使用者请求时会将 session cookie 用一个 secure_loads 函式将 cookie 内容读入。globals.py

# gluon/globals.py#L846

        if response.session_storage_type == 'cookie':
            # check if there is session data in cookies
            if response.session_data_name in cookies:
                session_cookie_data = cookies[response.session_data_name].value
            else:
                session_cookie_data = None
            if session_cookie_data:
                data = secure_loads(session_cookie_data, cookie_key,
                                    compression_level=compression_level)
                if data:
                    self.update(data)
            response.session_id = True

secure_loads 函式内容如下,在一连串解密后会用 pickle.loads 方法将解密内容反序列化,在这里确定 cookie 内容会使用 Pickle 处理。utils.py

# gluon/utils.py#L200

def secure_loads(data, encryption_key, hash_key=None, compression_level=None):
    if ':' not in data:
        return None
    if not hash_key:
        hash_key = sha1(encryption_key).hexdigest()
    signature, encrypted_data = data.split(':', 1)
    actual_signature = hmac.new(hash_key, encrypted_data).hexdigest()
    if not compare(signature, actual_signature):
        return None
    key = pad(encryption_key[:32])
    encrypted_data = base64.urlsafe_b64decode(encrypted_data)
    IV, encrypted_data = encrypted_data[:16], encrypted_data[16:]
    cipher, _ = AES_new(key, IV=IV)
    try:
        data = cipher.decrypt(encrypted_data)
        data = data.rstrip(' ')
        if compression_level:
            data = zlib.decompress(data)
        return pickle.loads(data)  # <-- Bingo!!!
    except Exception, e:
        return None

因此,如果知道连线中用以加密 cookie 内容的 encryption_key,攻击者就可以伪造 session cookie,进而利用 pickle.loads 进行远端命令执行。

CVE-2016-3953

很幸运的,我们发现 web2py 默认开启的范例应用程式是使用 session cookie,并且有一个写死的密钥:yoursecret。

# applications/examples/models/session.py
session.connect(request,response,cookie_key='yoursecret')

因此,web2py 的使用者如果没有手动关闭范例应用程式,攻击者就可以直接在 http://[target]/examples/ 页面发动攻击取得主机操作权。

PoC

我们尝试用 yoursecret 作为 encryption_key 伪造一个合法的 session cookie,并将一个会执行系统指令 sleep 的物件塞入其中。带着此 session cookie 连入 web2py 官网范例应用程式(http://www.web2py.com/examples),情形如下:

当插入的物件会执行指令 sleep 3 时,网站回应时间为 6.8 秒

POC1

当插入的物件会执行指令 sleep 5 时,网站回应时间为 10.8 秒

POC2

确实会因为塞入的 session cookie 值不同而有所延迟,证明网站的确执行了(两次)我们伪造的物件内容。

其他泄漏导致 RCE

此外,在 web2py 范例应用程式为了示范框架的特性,因此泄漏了许多环境变量。其中有两个变量较为敏感,间接也会导致端命令执行,分别如下。

CVE-2016-3954

在 http://[target]/examples/simple_examples/status 页面中,response 分页内容泄漏了 session_cookie_key 值。这个值就是用来加密前面所介绍的 session cookie,搭配 CVE-2016-3957 Pickle 的问题可直接远端命令执行。

CVE-2016-3954

无论使用者是否自行更改 session_cookie_key,或是该值是系统随机产生。此接口仍然可以取得机敏资讯藉以造成危害。

CVE-2016-3952

http://[target]/examples/template_examples/beautify 页面泄漏了系统环境变量,当使用者是使用 standalone 版本时,管理者的密码就会在环境变量里出现。这个密码可登入 http://[target]/admin 管理接口,管理接口内提供方便的功能得以执行任意指令。

CVE-2016-3952

官方修复

Version 2.14.1 移除泄漏的环境变量。gluon/globals.py

Version 2.14.2 使用不固定字串作为 session_cookie_key,并移除泄漏页面。

# applications/examples/models/session.py
from gluon.utils import web2py_uuid
cookie_key = cache.ram('cookie_key',lambda: web2py_uuid(),None)
session.connect(request,response,cookie_key=cookie_key)

总结

web2py 框架默认会开启一个范例应用程式,路径为 http://[target]/examples/。
由于这个应用程式使用 Pickle 来处理序列化的 session cookie,且因为加密字串为写死的 yoursecret,任何人可窜改 session cookie 的内容,借此进行 Pickle 命令执行攻击。

该范例程式接口中也存在 session_cookie_key、管理者密码泄漏问题,两个都会导致任意命令执行。除此之外,在这个应用程式中泄漏许多系统配置、路径等资讯,有机会被拿来做进阶攻击。

在 2.14.2 版本后已经修复所有泄漏问题,当然最好的解决办法就是关闭这个范例应用程式。

最后,来整理从开发者的角度在这个案例中该注意的要点:

  1. 小心处理序列化字串,使用者若有机会改变该字串值,有机会被插入未预期的恶意物件,造成恶意的结果。
  2. 正式产品中切记要移除任何跟开发相关的配置。

 

*参考来源:Shaolin,转载请注明来自MottoIN

原创文章,作者:Sam,如若转载,请注明出处:http://www.mottoin.com/article/web/94962.html

发表评论

登录后才能评论

联系我们

021-62666911

在线咨询:点击这里给我发消息

邮件:root@mottoin.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code