CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/proto/nuuo/client.rb
Views: 11704
1
# -*- coding: binary -*-
2
3
require 'rex/socket'
4
5
module Rex
6
module Proto
7
module Nuuo
8
# This class is a representation of a nuuo client
9
class Client
10
# @!attribute host
11
# @return [String] The nuuo server host
12
attr_accessor :host
13
# @!attribute port
14
# @return [Integer] The nuuo server port
15
attr_accessor :port
16
# @!attribute timeout
17
# @return [Integer] The connect/read timeout
18
attr_accessor :timeout
19
# @!attribute connection
20
# @return [IO] The connection established through Rex sockets
21
attr_accessor :connection
22
# @!attribute context
23
# @return [Hash] The Msf context where the connection belongs to
24
attr_accessor :context
25
# @!attribute ncs_version
26
# @return [String] NCS version used in session
27
attr_accessor :ncs_version
28
# @!attribute username
29
# @return [String] Username for NCS
30
attr_accessor :username
31
# @!attribute password
32
# @return [String] Password for NCS user
33
attr_accessor :password
34
# @!attribute user_session
35
# @return [String] ID for the user session
36
attr_accessor :user_session
37
# @!attribute config
38
# @return [Hash] ClientRequest configuration options
39
attr_accessor :config
40
41
def initialize(opts = {})
42
self.host = opts[:host]
43
self.port = opts[:port] || 5180
44
self.timeout = opts[:timeout] || 10
45
self.context = opts[:context] || {}
46
self.username = opts[:username]
47
self.password = opts[:password]
48
self.user_session = opts[:user_session]
49
50
self.config = Nuuo::ClientRequest::DefaultConfig
51
end
52
53
# Creates a connection through a Rex socket
54
#
55
# @return [Rex::Socket::Tcp]
56
def connect(temp: false)
57
return connection if connection && !temp
58
return create_tcp_connection(temp: temp)
59
end
60
61
# Closes the connection
62
def close
63
if connection
64
connection.shutdown
65
connection.close unless connection.closed?
66
end
67
68
self.connection = nil
69
end
70
71
def send_recv(req, conn=nil, t=-1)
72
send_request(req, conn)
73
read_response(conn, t)
74
end
75
76
def send_request(req, conn=nil)
77
conn ? conn.put(req.to_s) : connect.put(req.to_s)
78
end
79
80
def read_response(conn=nil, t=-1)
81
res = Response.new
82
conn = connection unless conn
83
84
return res if not t
85
Timeout.timeout((t < 0) ? nil : t) do
86
parse_status = nil
87
while (!conn.closed? &&
88
parse_status != Response::ParseCode::Completed &&
89
parse_status != Response::ParseCode::Error
90
)
91
begin
92
buff = conn.get_once
93
parse_status = res.parse(buff || '')
94
rescue ::Errno::EPIPE, ::EOFError, ::IOError
95
case res.state
96
when Response::ParseState::ProcessingHeader
97
res = nil
98
when Response::ParseState::ProcessingBody
99
res.error = :truncated
100
end
101
break
102
end
103
end
104
end
105
106
res
107
end
108
109
def user_session_header(opts)
110
val = nil
111
if opts['user_session']
112
val = opts['user_session']
113
elsif self.user_session
114
val = self.user_session
115
end
116
end
117
118
def request_ping(opts={})
119
opts = self.config.merge(opts)
120
opts['headers'] ||= {}
121
opts['method'] = 'PING'
122
session = user_session_header(opts)
123
opts['headers']['User-Session-No'] = session if session
124
125
ClientRequest.new(opts)
126
end
127
128
def request_sendlicfile(opts={})
129
opts = self.config.merge(opts)
130
opts['headers'] ||= {}
131
opts['method'] = 'SENDLICFILE'
132
133
session = user_session_header(opts)
134
opts['headers']['User-Session-No'] = session if session
135
opts['data'] = '' unless opts['data']
136
137
opts['headers']['FileName'] = opts['file_name']
138
opts['headers']['Content-Length'] = opts['data'].length
139
140
ClientRequest.new(opts)
141
end
142
143
# GETCONFIG
144
# FileName:
145
# FileType: 1
146
# User-Session-No: <session-no>
147
# @return [ClientRequest]
148
def request_getconfig(opts={})
149
opts = self.config.merge(opts)
150
opts['headers'] ||= {}
151
opts['method'] = 'GETCONFIG'
152
153
opts['headers']['FileName'] = opts['file_name']
154
opts['headers']['FileType'] = opts['file_type'] || 1
155
session = user_session_header(opts)
156
opts['headers']['User-Session-No'] = session if session
157
158
ClientRequest.new(opts)
159
end
160
161
# COMMITCONFIG
162
# FileName:
163
# FileType: 1
164
# Content-Length
165
# User-Session-No: <session-no>
166
#
167
# <data> filedata
168
# @return [ClientRequest]
169
def request_commitconfig(opts={})
170
opts = self.config.merge(opts)
171
opts['headers'] ||= {}
172
opts['method'] = 'COMMITCONFIG'
173
174
opts['headers']['FileName'] = opts['file_name']
175
opts['headers']['FileType'] = opts['file_type'] || 1
176
177
session = user_session_header(opts)
178
opts['headers']['User-Session-No'] = session if session
179
180
opts['data'] = '' unless opts['data']
181
opts['headers']['Content-Length'] = opts['data'].length
182
183
ClientRequest.new(opts)
184
end
185
186
# USERLOGIN
187
# Version:
188
# Username:
189
# Password-Length:
190
# TimeZone-Length: 0
191
#
192
# <data> password
193
# @return [ClientRequest]
194
def request_userlogin(opts={})
195
opts = self.config.merge(opts)
196
opts['headers'] ||= {}
197
opts['method'] = 'USERLOGIN'
198
199
# Account for version...
200
opts['headers']['Version'] = opts['server_version']
201
202
username = nil
203
if opts['username'] && opts['username'] != ''
204
username = opts['username']
205
elsif self.username && self.username != ''
206
username = self.username
207
end
208
209
opts['headers']['Username'] = username
210
211
password = ''
212
if opts['password'] && opts['password'] != ''
213
password = opts['password']
214
elsif self.password && self.password != ''
215
password = self.password
216
end
217
opts['data'] = password
218
opts['headers']['Password-Length'] = password.length
219
220
# Need to verify if this is needed
221
opts['headers']['TimeZone-Length'] = '0'
222
223
ClientRequest.new(opts)
224
end
225
226
# GETOPENALARM NUCM/1.0
227
# DeviceID: <number>
228
# SourceServer: <server-id>
229
# LastOne: <number>
230
# @return [ClientRequest]
231
def request_getopenalarm(opts={})
232
opts = self.config.merge(opts)
233
opts['headers'] ||= {}
234
opts['method'] = 'GETOPENALARM'
235
236
opts['headers']['DeviceID'] = opts['device_id'] || 1
237
opts['headers']['SourceServer'] = opts['source_server'] || 1
238
opts['headers']['LastOne'] = opts['last_one'] || 1
239
240
ClientRequest.new(opts)
241
end
242
243
244
private
245
246
# Creates a TCP connection using Rex::Socket::Tcp
247
#
248
# @return [Rex::Socket::Tcp]
249
def create_tcp_connection(temp: false)
250
tcp_connection = Rex::Socket::Tcp.create(
251
'PeerHost' => host,
252
'PeerPort' => port.to_i,
253
'Context' => context,
254
'Timeout' => timeout
255
)
256
self.connection = tcp_connection unless temp
257
tcp_connection
258
end
259
260
end
261
end
262
end
263
end
264
265