Внедрение произвольного кода в сервер 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
украшения, чтобы определить, что должно быть видно.