向Python SimpleXMLRPC服务器注入任意代码

3 投票
1 回答
869 浏览
提问于 2025-04-17 19:24

在Python的文档中,关于SimpleXMLRPC Server,提到了一些警告:

警告:开启allow_dotted_names选项会让不法分子有机会访问你模块中的全局变量,并可能让他们在你的机器上执行任意代码。这个选项只应该在安全的、封闭的网络中使用。

现在我有一个服务器,代码如下:

from xmlrpc.server import SimpleXMLRPCServer
from xmlrpc.server import SimpleXMLRPCRequestHandler


server = SimpleXMLRPCServer(("localhost", 8000),
                            requestHandler=RequestHandler)
server.register_introspection_functions()

server.register_function(pow)

def adder_function(x,y):
    return x + y
server.register_function(adder_function, 'add')

class MyFuncs:
    def mul(self, x, y):
        return x * y

server.register_instance(MyFuncs(), allow_dotted_names=True)

server.serve_forever()

请解释一下,这个漏洞是如何被利用来在服务器上注入任意代码的?如果我上面的代码没有漏洞,那请给一个可以被利用的例子,以及相应的客户端代码。

1 个回答

0

MyFuncs().mul 不仅仅是一个可以调用的函数,它和所有Python函数一样,都是一个一等对象,拥有自己的属性。

除了很多以 __xxx__ 开头的魔法方法(这些你无法访问,因为SimpleXMLRPCServer会阻止访问任何以 _ 开头的东西),还有一些内部方法成员,比如 im_class(指向类对象)、im_self(指向 MyFuncs() 的实例)和 im_func(指向 mul 的函数定义)。这个函数对象本身有很多可访问的属性,最重要的是 func_globals,它可以访问包含文件的变量作用域字典。

因此,通过调用 mul.im_func.func_globals.get,攻击者可以读取你在脚本中设置的任意全局变量,或者使用 update() 方法来修改这些变量。在上面的例子中,这并不可被利用,因为你的全局变量中没有敏感信息。但这并不是你想要一直依赖的事情。

完全“执行任意代码”的可能性不大,但你可以想象一个可写的全局变量 codeToExecute,它可能会在后面被 eval 执行,或者有人通过 register_instance 注册了整个模块,这样它导入的所有模块都可以被访问(典型的例子是 osos.system)。

在Python 3中,这种特定的攻击方式已经无法实现,因为函数/方法的内部属性被重命名为双下划线版本,这样就被阻止了。但总的来说,默认开放并允许外部访问实例的任何属性,单凭名称来看似乎是个坏主意——没有保证未来不会出现其他非下划线名称,或者不会有属性被添加到可访问的内置类型(如元组、字典)中,这些属性可能会以某种方式被利用。

如果你真的需要嵌套属性访问,似乎更安全的做法是设计一个版本的SimpleXMLRPCServer,要求使用类似 @rpc_accessible 的装饰器来定义哪些内容应该是可见的。

撰写回答