Files
metasploit-gs/lib/rex/parser/winscp.rb
T

109 lines
2.8 KiB
Ruby
Raw Normal View History

2015-08-01 20:44:14 +01:00
require 'rex/parser/ini'
module Rex
module Parser
module WinSCP
2015-09-01 22:05:47 +01:00
PWDALG_SIMPLE_MAGIC = 0xA3
PWDALG_SIMPLE_FLAG = 0xFF
2015-08-01 20:44:14 +01:00
def read_and_parse_ini(filename)
file = File.read(filename)
return if file.to_s.empty?
parse_ini(file)
end
def parse_protocol(fsprotocol)
2015-09-01 22:05:47 +01:00
return 'Unknown' if fsprotocol.nil?
case fsprotocol
2015-08-01 20:44:14 +01:00
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
2015-09-01 22:05:47 +01:00
if ini['Configuration\\Security']['UseMasterPassword'].to_i == 1
2015-08-01 20:44:14 +01:00
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']
2015-09-01 22:05:47 +01:00
sname = parse_protocol(ini[group]['FSProtocol'].to_i)
2015-08-01 20:44:14 +01:00
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
2015-09-01 22:05:47 +01:00
# Decrypts the next character in the password sequence
def decrypt_next_char(pwd)
if pwd.nil? || pwd.length <= 0
return 0, pwd
2015-08-01 20:44:14 +01:00
end
2015-09-01 22:05:47 +01:00
# 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]
2015-08-01 20:44:14 +01:00
end
def decrypt_password(pwd, key)
2015-09-01 22:05:47 +01:00
flag, pwd = decrypt_next_char(pwd)
2015-08-01 20:44:14 +01:00
2015-09-01 22:05:47 +01:00
if flag == PWDALG_SIMPLE_FLAG
_, pwd = decrypt_next_char(pwd)
length, pwd = decrypt_next_char(pwd)
2015-08-01 20:44:14 +01:00
else
length = flag
end
2015-09-01 22:05:47 +01:00
del, pwd = decrypt_next_char(pwd)
pwd = pwd[del*2..-1]
2015-08-01 20:44:14 +01:00
result = ""
length.times do
2015-09-01 22:05:47 +01:00
r, pwd = decrypt_next_char(pwd)
result << r.chr
2015-08-01 20:44:14 +01:00
end
2015-09-01 22:05:47 +01:00
if flag == PWDALG_SIMPLE_FLAG
result = result[key.length..-1]
2015-08-01 20:44:14 +01:00
end
result
end
end
end
end