Files
metasploit-gs/lib/msf/core/exploit/git/lfs.rb
T
2021-09-03 16:17:30 -05:00

120 lines
3.9 KiB
Ruby

module Msf
# This mixin adds functionality to enable modules to send and receive git LFS objects
module Exploit::Git::Lfs
include Msf::Exploit::Git
def generate_pointer_file(obj_data)
return '' if obj_data.empty?
<<~PTR_FILE
version https://git-lfs.github.com/spec/v1
oid sha256:#{Digest::SHA256.hexdigest(obj_data)}
size #{obj_data.length}
PTR_FILE
end
# Generates a Git LFS response to a batch request
#
# @param [Rex::Proto::Http::Request] the Git LFS request
# @param [String] the URL of the Git server
# @param [Array] list of objects in Git repo
#
# @return [Msf::Exploit::Git::Lfs::Response]
def get_batch_response(request, server_addr, repo_objects)
server_addr = server_addr.to_s unless server_addr.is_a?(String)
server_addr = server_addr.gsub(%r{/\w+\.git}, '')
repo_objects = [ repo_objects ] unless repo_objects.is_a?(Array)
response = Msf::Exploit::Git::Lfs::Response.from_http_request(request, server_addr)
return nil unless response
unless response.valid_objects?(repo_objects) || response.code != 200
print_error('Client requested objects not in repository')
return response
end
obj_data_arr = []
response.valid_objs.each do |obj|
sha = Msf::Exploit::Git::Lfs::Response.obj_sha256(obj.content)
time = Time.now + 3600
obj_data_arr <<
{
'oid' => sha,
'size' => obj.content.size,
'actions' =>
{
'download' =>
{
'href' => "#{response.base_addr}/#{sha}",
'expires_at' => time.strftime('%FT%TZ'),
'expires_in' => 3600
}
}
}
end
response.body = { 'objects' => obj_data_arr }.to_json
response
end
# Generates a response to a Git LFS object request
#
# @param [Rex::Proto::Http::Request] Git client request
# @param [Array] list of objects in Git repository
#
# @return [Msf::Exploit::Git::Lfs::Response]
def get_requested_obj_response(request, repo_objects)
repo_objects = [ repo_objects ] unless repo_objects.is_a?(Array)
response = Msf::Exploit::Git::Lfs::Response.from_http_request(request)
return nil unless response
unless response.valid_objects?(repo_objects) || response.code != 200
print_error('Client requested an object that is not in the repository')
return response
end
response.body = response.valid_objs.first.content
response
end
def handle_lfs_objects(req, hook_payload, git_addr)
git_hook_obj = Msf::Exploit::Git::Lfs::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
end
end