Metasploit Module: Linux eBPF ALU32 32-bit Invalid Bounds Tracking LPE
Type: exploit
Path: modules/exploits/linux/local/cve_2021_3490_ebpf_alu32_bounds_check_lpe.rb
Disclosure date: 2021-05-11
References: CVE-2021-3490, URL-https://www.openwall.com/lists/oss-security/2021/05/11/11, URL-https://github.com/chompie1337/Linux_LPE_eBPF_CVE-2021-3490, URL-https://www.zerodayinitiative.com/blog/2020/4/8/cve-2020-8835-linux-kernel-privilege-escalation-via-improper-ebpf-program-verification, URL-https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git/commit/?id=049c4e13714ecbca567b4d5f6d563f05d431c80e, URL-https://www.graplsecurity.com/post/kernel-pwning-with-ebpf-a-love-story, URL-https://www.zerodayinitiative.com/advisories/ZDI-21-606/, URL-https://ubuntu.com/security/notices/USN-4950-1, URL-https://ubuntu.com/security/notices/USN-4949-1

Description:
Linux kernels from 5.7-rc1 prior to 5.13-rc4, 5.12.4, 5.11.21, and
          5.10.37 are vulnerable to a bug in the eBPF verifier's verification
          of ALU32 operations in the scalar32_min_max_and function when performing
          AND operations, whereby under certain conditions the bounds of a
          32 bit register would not be properly updated.

          This can be abused by attackers to conduct an out of bounds read
          and write in the Linux kernel and therefore achieve arbitrary
          code execution as the root user.

          The target system must be compiled with eBPF support and not have
          kernel.unprivileged_bpf_disabled set, which prevents unprivileged
          users from loading eBPF programs into the kernel. Note that if
          kernel.unprivileged_bpf_disabled is enabled this module can still be
          utilized to bypass protections such as SELinux, however the user
          must already be logged as a privileged user such as root.

Check method (fingerprinting):
arch = kernel_hardware

    # Could we potentially support x86? Yes, potentially. Will we? Well considering the 5.7 kernel was released
    # in 2020 and official support for x64 kernels ended in 2012 with
    # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=743aa456c1834f76982af44e8b71d1a0b2a82e2
    # combined with the fact that those distros that do have older x86 versions mostly have 4.x or older kernels,
    # and 90% of them have dropped support for x86 kernels a while back, we'll just assume that if its x86, its probably not
    # running an affected Linux kernel.
    unless arch.include?('x86_64')
      return CheckCode::Safe("System architecture #{arch} is not supported")
    end

    if unprivileged_bpf_disabled?
      return CheckCode::Safe('Unprivileged BPF loading is not permitted')
    end

    vprint_good('Unprivileged BPF loading is permitted')

    release = kernel_release
    version = kernel_version

    # If the target is Ubuntu...
    if version =~ /[uU]buntu/
      version_array = release.split('-')
      if version_array.length < 2
        fail_with(Failure::UnexpectedReply, 'The target Ubuntu server does not have the expected kernel version format!')
      end
      major_version = version_array[0]
      minor_version = version_array[1]

      # First check if we are past the 5.11.x kernel releases and into at the time of
      # writing beta versions of Ubuntu. If so,the target isn't vuln.
      if Rex::Version.new(major