3
3
module Rex
4
4
module Parser
5
5
module WinSCP
6
+ PWDALG_SIMPLE_MAGIC = 0xA3
7
+ PWDALG_SIMPLE_FLAG = 0xFF
8
+
6
9
def read_and_parse_ini ( filename )
7
10
file = File . read ( filename )
8
11
return if file . to_s . empty?
9
12
parse_ini ( file )
10
13
end
11
14
12
15
def parse_protocol ( fsprotocol )
13
- case fsprotocol . to_i
16
+ return 'Unknown' if fsprotocol . nil?
17
+
18
+ case fsprotocol
14
19
when 5 then 'FTP'
15
20
when 0 then 'SSH'
16
21
else
@@ -26,7 +31,7 @@ def parse_ini(file)
26
31
27
32
if ini [ 'Configuration\\Security' ]
28
33
# if a Master Password is in use we give up
29
- if ini [ 'Configuration\\Security' ] [ 'MasterPassword ' ] . to_i == 1
34
+ if ini [ 'Configuration\\Security' ] [ 'UseMasterPassword ' ] . to_i == 1
30
35
raise RuntimeError , 'Master Password Set, unable to recover saved passwords!'
31
36
end
32
37
end
@@ -38,7 +43,7 @@ def parse_ini(file)
38
43
encrypted_password = ini [ group ] [ 'Password' ]
39
44
user = ini [ group ] [ 'UserName' ]
40
45
host = ini [ group ] [ 'HostName' ]
41
- sname = parse_protocol ( ini [ group ] [ 'FSProtocol' ] )
46
+ sname = parse_protocol ( ini [ group ] [ 'FSProtocol' ] . to_i )
42
47
plaintext = decrypt_password ( encrypted_password , "#{ user } #{ host } " )
43
48
44
49
results << {
@@ -54,49 +59,46 @@ def parse_ini(file)
54
59
results
55
60
end
56
61
57
- def decrypt_next_char
58
- pwalg_simple_magic = 0xA3
59
- pwalg_simple_string = "0123456789ABCDEF"
60
-
61
- # Decrypts the next character in the password sequence
62
- if @password . length > 0
63
- # Takes the first char from the encrypted password and finds its position in the
64
- # pre-defined string, then left shifts the returned index by 4 bits
65
- unpack1 = pwalg_simple_string . index ( @password [ 0 , 1 ] )
66
- unpack1 = unpack1 << 4
67
-
68
- # Takes the second char from the encrypted password and finds its position in the
69
- # pre-defined string
70
- unpack2 = pwalg_simple_string . index ( @password [ 1 , 1 ] )
71
- # Adds the two results, XORs against 0xA3, NOTs it and then ands it with 0xFF
72
- result = ~( ( unpack1 +unpack2 ) ^ pwalg_simple_magic ) & 0xff
73
- # Strips the first two chars off and returns our result
74
- @password = @password [ 2 , @password . length ]
75
- return result
62
+ # Decrypts the next character in the password sequence
63
+ def decrypt_next_char ( pwd )
64
+ if pwd . nil? || pwd . length <= 0
65
+ return 0 , pwd
76
66
end
67
+
68
+ # Takes the first char from the encrypted password and then left shifts the returned index by 4 bits
69
+ a = pwd [ 0 ] . hex << 4
70
+
71
+ # Takes the second char from the encrypted password
72
+ b = pwd [ 1 ] . hex
73
+
74
+ # Adds the two results, XORs against 0xA3, NOTs it and then ANDs it with 0xFF
75
+ result = ~( ( a + b ) ^ PWDALG_SIMPLE_MAGIC ) & PWDALG_SIMPLE_FLAG
76
+
77
+ # Strips the first two chars off and returns our result
78
+ return result , pwd [ 2 ..-1 ]
77
79
end
78
80
79
81
def decrypt_password ( pwd , key )
80
- pwalg_simple_flag = 0xFF
81
- @password = pwd
82
- flag = decrypt_next_char ( )
82
+ flag , pwd = decrypt_next_char ( pwd )
83
83
84
- if flag == pwalg_simple_flag
85
- decrypt_next_char ( )
86
- length = decrypt_next_char ( )
84
+ if flag == PWDALG_SIMPLE_FLAG
85
+ _ , pwd = decrypt_next_char ( pwd )
86
+ length , pwd = decrypt_next_char ( pwd )
87
87
else
88
88
length = flag
89
89
end
90
- ldel = ( decrypt_next_char ( ) ) *2
91
- @password = @password [ ldel , @password . length ]
90
+
91
+ del , pwd = decrypt_next_char ( pwd )
92
+ pwd = pwd [ del *2 ..-1 ]
92
93
93
94
result = ""
94
95
length . times do
95
- result << decrypt_next_char ( ) . chr
96
+ r , pwd = decrypt_next_char ( pwd )
97
+ result << r . chr
96
98
end
97
99
98
- if flag == pwalg_simple_flag
99
- result = result [ key . length , result . length ]
100
+ if flag == PWDALG_SIMPLE_FLAG
101
+ result = result [ key . length ..- 1 ]
100
102
end
101
103
102
104
result
0 commit comments