CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/ui/web/comm.rb
Views: 1904
1
# -*- coding: binary -*-
2
module Msf
3
module Ui
4
module Web
5
6
module Comm
7
8
class Channel
9
def initialize
10
@id = Comm.next_channel_id
11
end
12
13
def read
14
nil
15
end
16
17
attr_accessor :id
18
end
19
20
class SessionChannel < Channel
21
def initialize(session_id, pipe)
22
super()
23
24
@sid = session_id
25
@pipe = pipe
26
27
@pipe.create_subscriber(channel.id)
28
end
29
30
def close
31
@pipe.remove_subscriber(channel.id)
32
end
33
34
def write_input(msg)
35
@pipe.write_input(msg)
36
end
37
38
def read
39
@pipe.read_subscriber(channel.id)
40
end
41
end
42
43
class SessionEventSubscriber
44
include Msf::SessionEvent
45
46
def on_session_open(session)
47
pipe = Comm.create_session_pipe(session)
48
49
session.init_ui(pipe, pipe)
50
end
51
end
52
53
@@framework = nil
54
@@channels = {}
55
@@channel_id = 0
56
@@read_event = Rex::Sync::Event.new(false, false)
57
@@session_pipes = {}
58
59
def self.setup(framework)
60
@framework = framework
61
62
framework.events.add_session_subscriber(SessionEventSubscriber.new)
63
end
64
65
def self.wakeup
66
@read_event.set
67
end
68
69
def self.next_channel_id
70
@channel_id += 1
71
end
72
73
def self.create_channel(client, request)
74
create_session_channel(client.qstring['sid'].to_i)
75
end
76
77
def self.create_session_channel(session_id)
78
channel = SessionChannel.new(session_id, @session_pipes[session_id])
79
80
@channels[channel.id] = channel
81
82
channel
83
end
84
85
def self.create_session_pipe(session)
86
pipe = Rex::Ui::BidirectionalPipe.new
87
88
@session_pipes[session.id] = pipe
89
90
pipe
91
end
92
93
def self.write_channel(client, request)
94
channel_id = request.qstring['channel_id']
95
data = request.qstring['data']
96
channel = @channels[channel_id]
97
98
if channel.nil? == false
99
channel.write_input(data)
100
end
101
end
102
103
def self.read_channels(client, request)
104
dlog("read_channels: waiting for event")
105
106
# Wait to see if there's any data available on channels. If there
107
# isn't, then we send a response immediately. Otherwise, we check
108
# to see if any of the requested channels were ones that we're
109
# interested in.
110
begin
111
@@read_event.wait(15)
112
rescue Timeout::Error
113
client.send_response(Rex::Proto::Http::Response::OK.new)
114
return
115
end
116
117
@@read_event.reset
118
119
channels = request.qstring['channels']
120
121
if channels.kind_of?(Array) == false
122
channels = [channels]
123
end
124
125
# Walk each channel, checking to see if there is any read data. If
126
# there is, then we'll include it in the response body.
127
body = '<channeldatum>'
128
129
channels.each { |cid|
130
channel = @channels[cid]
131
132
next if channel.nil?
133
134
buf = channel.read
135
136
next if buf.nil?
137
138
body += "<channeldata id=\"#{channel.id}\">#{Base64.encode64(buf)}</channeldata>"
139
}
140
141
body = '</channeldatum>'
142
143
# Create and send the response
144
response = Rex::Proto::Http::Response::OK.new
145
response.body = body
146
147
client.send_response(response)
148
end
149
150
end
151
152
end
153
end
154
end
155
156
157