Class: Msf::Exploit::Git::Lfs::Response

Inherits:
Rex::Proto::Http::Response show all
Includes:
Msf::Exploit::Git::Lfs
Defined in:
lib/msf/core/exploit/git/lfs/response.rb

Constant Summary collapse

STATUS_CODES =
{
  200 => 'OK',
  401 => 'Auth required, but creds were not sent',
  403 => 'User does not have write access',
  404 => 'The object does not exist on the server',
  406 => 'The Accept header needs to be application/vnd.git-lfs+json',
  410 => 'The object was removed by owner of repository',
  413 => 'The batch API request contained too many objects',
  422 => 'Requested object(s) invalid',
  429 => 'Server rate limit reached',
  501 => 'The server has not implemented the current method',
  507 => 'The server has insufficient storage capacity to complete the request',
  509 => 'The bandwidth limit for the user or repository has been exceeded'
}

Instance Attribute Summary collapse

Attributes inherited from Rex::Proto::Http::Response

#code, #count_100, #message, #peerinfo, #proto, #request

Attributes inherited from Rex::Proto::Http::Packet

#auto_cl, #body, #body_bytes_left, #bufq, #chunk_max_size, #chunk_min_size, #compress, #error, #headers, #incomplete, #inside_chunk, #keepalive, #max_data, #state, #transfer_chunked

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Msf::Exploit::Git::Lfs

#generate_pointer_file, #get_batch_response, #get_requested_obj_response

Methods inherited from Rex::Proto::Http::Response

#check_100, #cmd_string, #get_cookies, #get_cookies_parsed, #get_hidden_inputs, #get_html_document, #get_html_meta_elements, #get_html_scripts, #get_json_document, #get_xml_document, #redirect?, #redirection, #update_cmd_parts

Methods inherited from Rex::Proto::Http::Packet

#[], #[]=, #check_100, #chunk, #cmd_string, #completed?, #from_s, #output_packet, #parse, #parse_body, #parse_header, #reset, #reset_except_queue, #to_s, #to_terminal_output, #update_cmd_parts

Constructor Details

#initialize(opts = {}) ⇒ Response

Returns a new instance of Response.


27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 27

def initialize(opts = {})
  @uri = opts[:uri] || '/'
  @base_addr = opts[:base_addr] || ''
  @code = opts[:code] || 200
  @message = opts[:message] || STATUS_CODES[@code]
  @operation = opts[:operation] || 'download'
  @requested_oids = opts[:requested_oids] || []
  @valid_objs = opts[:valid_objs] || []
  @transfers = opts[:transfers] || [ 'basic' ]

  super(@code, @message)
  set_headers
end

Instance Attribute Details

#base_addrObject (readonly)

Returns the value of attribute base_addr.


9
10
11
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 9

def base_addr
  @base_addr
end

#operationObject (readonly)

Returns the value of attribute operation.


9
10
11
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 9

def operation
  @operation
end

#requested_oidsObject (readonly)

Returns the value of attribute requested_oids.


9
10
11
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 9

def requested_oids
  @requested_oids
end

#transfersObject (readonly)

Returns the value of attribute transfers.


9
10
11
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 9

def transfers
  @transfers
end

#valid_objsObject (readonly)

Returns the value of attribute valid_objs.


9
10
11
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 9

def valid_objs
  @valid_objs
end

Class Method Details

.from_http_request(request, git_addr = '') ⇒ Object


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 82

def self.from_http_request(request, git_addr = '')
  return nil unless request && request.body

  opts = {}
  opts[:uri] = request.uri
  case request.method
  when 'GET'
    uri_parts = opts[:uri].split('/')
    requested_oid = uri_parts.last
    unless requested_oid
      opts[:code] = 422
      return Response.new(opts)
    end

    opts[:requested_oids] = [ requested_oid ]
    Response.new(opts)
  when 'POST'
    unless request.uri.include?('info/lfs/objects/batch')
      opts[:code] = 404
      opts[:message] = 'Not Found'
      return Response.new(opts)
    end

    git_addr = git_addr.to_s
    if git_addr.empty?
      raise ArgumentError, 'The URL for the Git repository was not supplied'
    end

    git_addr = git_addr.gsub(/\/\w+\.git/, '')
    opts[:base_addr] = git_addr
    parsed_options = parse_request_data(request.body)
    opts.merge!(parsed_options)
    Response.new(opts)
  end
end

.obj_sha256(content) ⇒ Object


78
79
80
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 78

def self.obj_sha256(content)
  Digest::SHA256.hexdigest(content)
end

.parse_request_data(body) ⇒ Object


118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 118

def self.parse_request_data(body)
  json_data = JSON.parse(body)

  oids = []
  req_opts = {}
  req_opts[:operation] = json_data['operation'] || 'download'
  objects = json_data['objects'].nil? ? [] : json_data['objects']
  objects.each { |obj| oids << obj['oid'] }
  req_opts[:requested_oids] = oids
  req_opts[:transfers] = json_data['transfers']

  req_opts
end

Instance Method Details

#set_headersObject


41
42
43
44
45
46
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 41

def set_headers
  required_header = 'application/vnd.git-lfs+json'

  @headers['Accept'] = required_header
  @headers['Content-Type'] = required_header
end

#valid_objects?(repo_objects) ⇒ Boolean

Checks that the instance's requested oids are valid Git objects in the repo

Parameters:

  • list (Array)

    of objects in repo

Returns:

  • (Boolean)

54
55
56
57
58
59
60
61
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 54

def valid_objects?(repo_objects)
  repo_objects = [ repo_objects ] unless repo_objects.kind_of?(Array)

  return false if repo_objects.empty?

  validate_requested_objects(repo_objects)
  @valid_objs.all? { |obj| @requested_oids.include?(self.class.obj_sha256(obj.content)) } 
end

#validate_requested_objects(repo_objects) ⇒ Object

Populates the valid objects list based on oids requested by the client

Parameters:

  • list (Array)

    of objects in repo


68
69
70
71
72
73
74
75
76
# File 'lib/msf/core/exploit/git/lfs/response.rb', line 68

def validate_requested_objects(repo_objects)
  repo_objects.each do |obj|
    @requested_oids.each do |oid|
      @valid_objs << obj if self.class.obj_sha256(obj.content) == oid
    end
  end

  @valid_objs.uniq!
end