metasploit-framework/lib/rex/parser/winscp.rb

109 lines
2.8 KiB
Ruby

require 'rex/parser/ini'
module Rex
module Parser
module WinSCP
PWDALG_SIMPLE_MAGIC = 0xA3
PWDALG_SIMPLE_FLAG = 0xFF
def read_and_parse_ini(filename)
file = File.read(filename)
return if file.to_s.empty?
parse_ini(file)
end
def parse_protocol(fsprotocol)
return 'Unknown' if fsprotocol.nil?
case fsprotocol
when 5 then 'FTP'
when 0 then 'SSH'
else
'Unknown'
end
end
def parse_ini(file)
results = []
raise RuntimeError, 'No data to parse' if file.nil? || file.empty?
ini = Rex::Parser::Ini.from_s(file)
if ini['Configuration\\Security']
# if a Master Password is in use we give up
if ini['Configuration\\Security']['UseMasterPassword'].to_i == 1
raise RuntimeError, 'Master Password Set, unable to recover saved passwords!'
end
end
# Runs through each group in the ini file looking for all of the Sessions
ini.each_key do |group|
if group.include?('Sessions') && ini[group].has_key?('Password')
# Decrypt our password, and report on results
encrypted_password = ini[group]['Password']
user = ini[group]['UserName']
host = ini[group]['HostName']
sname = parse_protocol(ini[group]['FSProtocol'].to_i)
plaintext = decrypt_password(encrypted_password, "#{user}#{host}")
results << {
hostname: host,
password: plaintext,
portnumber: ini[group]['PortNumber'] || 22,
username: user,
protocol: sname
}
end
end
results
end
# Decrypts the next character in the password sequence
def decrypt_next_char(pwd)
if pwd.nil? || pwd.length <= 0
return 0, pwd
end
# Takes the first char from the encrypted password and then left shifts the returned index by 4 bits
a = pwd[0].hex << 4
# Takes the second char from the encrypted password
b = pwd[1].hex
# Adds the two results, XORs against 0xA3, NOTs it and then ANDs it with 0xFF
result = ~((a + b) ^ PWDALG_SIMPLE_MAGIC) & PWDALG_SIMPLE_FLAG
# Strips the first two chars off and returns our result
return result, pwd[2..-1]
end
def decrypt_password(pwd, key)
flag, pwd = decrypt_next_char(pwd)
if flag == PWDALG_SIMPLE_FLAG
_, pwd = decrypt_next_char(pwd)
length, pwd = decrypt_next_char(pwd)
else
length = flag
end
del, pwd = decrypt_next_char(pwd)
pwd = pwd[del*2..-1]
result = ""
length.times do
r, pwd = decrypt_next_char(pwd)
result << r.chr
end
if flag == PWDALG_SIMPLE_FLAG
result = result[key.length..-1]
end
result
end
end
end
end