Внедрение произвольного кода в сервер Python SimpleXMLRPC

В документации по 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 ответ

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разрешить доступ ко всем импортированным модулям (типичный пример: os а также os.system).

В Python 3 эта конкретная атака более недоступна, поскольку внутренние свойства функции / метода были переименованы в версии с двойным подчеркиванием, где они блокируются. Но в целом кажется плохой идеей "открывать по умолчанию" и разрешать внешний доступ к любому свойству в экземпляре, основанном только на имени, - нет гарантии, что в будущем не будут существовать другие не подчеркнутые имена или что свойства не будут добавлены к доступным встроенным типам (tuple, dict) тех свойств, которые могут быть использованы каким-либо образом.

Если вам действительно нужен доступ к вложенным свойствам, было бы безопаснее создать версию SimpleXMLRPCServer, для которой требуется что-то вроде @rpc_accessible украшения, чтобы определить, что должно быть видно.

Другие вопросы по тегам