Class: Msf::Modules::External::Bridge
- Inherits:
-
Object
- Object
- Msf::Modules::External::Bridge
- Defined in:
- lib/msf/core/modules/external/bridge.rb,
lib/msf/core/modules/external/bridge.rb
Constant Summary collapse
- LOADERS =
[ Msf::Modules::External::PyBridge, Msf::Modules::External::RbBridge, Msf::Modules::External::GoBridge, Msf::Modules::External::Bridge ]
Instance Attribute Summary collapse
-
#buf ⇒ Object
protected
Returns the value of attribute buf.
-
#cmd ⇒ Object
protected
Returns the value of attribute cmd.
-
#env ⇒ Object
protected
Returns the value of attribute env.
-
#exit_status ⇒ Object
Returns the value of attribute exit_status.
-
#framework ⇒ Object
protected
Returns the value of attribute framework.
-
#ios ⇒ Object
protected
Returns the value of attribute ios.
-
#messages ⇒ Object
Returns the value of attribute messages.
-
#path ⇒ Object
Returns the value of attribute path.
-
#read_thread ⇒ Object
protected
Returns the value of attribute read_thread.
-
#running ⇒ Object
Returns the value of attribute running.
-
#wait_thread ⇒ Object
protected
Returns the value of attribute wait_thread.
Class Method Summary collapse
Instance Method Summary collapse
- #cleanup ⇒ Object protected
- #close ⇒ Object
- #exec(req) ⇒ Object
- #handle_exception(e) ⇒ Object protected
- #harvest_process ⇒ Object protected
-
#initialize(module_path, framework: nil) ⇒ Bridge
constructor
A new instance of Bridge.
- #next_message(timeout = 600) ⇒ Object protected
-
#send(message) ⇒ Object
protected
XXX TODO non-blocking writes, check write lengths.
- #success? ⇒ Boolean
- #threadme(&block) ⇒ Object protected
- #write_message(fd, json) ⇒ Object protected
Constructor Details
#initialize(module_path, framework: nil) ⇒ Bridge
Returns a new instance of Bridge.
44 45 46 47 48 49 50 51 52 |
# File 'lib/msf/core/modules/external/bridge.rb', line 44 def initialize(module_path, framework: nil) self.env = {} self.running = false self.path = module_path self.cmd = [[self.path, self.path]] self. = Queue.new self.buf = '' self.framework = framework end |
Instance Attribute Details
#buf ⇒ Object (protected)
Returns the value of attribute buf.
57 58 59 |
# File 'lib/msf/core/modules/external/bridge.rb', line 57 def buf @buf end |
#cmd ⇒ Object (protected)
Returns the value of attribute cmd.
57 58 59 |
# File 'lib/msf/core/modules/external/bridge.rb', line 57 def cmd @cmd end |
#env ⇒ Object (protected)
Returns the value of attribute env.
57 58 59 |
# File 'lib/msf/core/modules/external/bridge.rb', line 57 def env @env end |
#exit_status ⇒ Object
Returns the value of attribute exit_status.
9 10 11 |
# File 'lib/msf/core/modules/external/bridge.rb', line 9 def exit_status @exit_status end |
#framework ⇒ Object (protected)
Returns the value of attribute framework.
57 58 59 |
# File 'lib/msf/core/modules/external/bridge.rb', line 57 def framework @framework end |
#ios ⇒ Object (protected)
Returns the value of attribute ios.
57 58 59 |
# File 'lib/msf/core/modules/external/bridge.rb', line 57 def ios @ios end |
#messages ⇒ Object
Returns the value of attribute messages.
9 10 11 |
# File 'lib/msf/core/modules/external/bridge.rb', line 9 def @messages end |
#path ⇒ Object
Returns the value of attribute path.
9 10 11 |
# File 'lib/msf/core/modules/external/bridge.rb', line 9 def path @path end |
#read_thread ⇒ Object (protected)
Returns the value of attribute read_thread.
57 58 59 |
# File 'lib/msf/core/modules/external/bridge.rb', line 57 def read_thread @read_thread end |
#running ⇒ Object
Returns the value of attribute running.
9 10 11 |
# File 'lib/msf/core/modules/external/bridge.rb', line 9 def running @running end |
#wait_thread ⇒ Object (protected)
Returns the value of attribute wait_thread.
57 58 59 |
# File 'lib/msf/core/modules/external/bridge.rb', line 57 def wait_thread @wait_thread end |
Class Method Details
.applies?(module_name) ⇒ Boolean
11 12 13 |
# File 'lib/msf/core/modules/external/bridge.rb', line 11 def self.applies?(module_name) File::executable? module_name end |
.open(module_path, framework: nil) ⇒ Object
255 256 257 258 259 260 261 |
# File 'lib/msf/core/modules/external/bridge.rb', line 255 def self.open(module_path, framework: nil) LOADERS.each do |klass| return klass.new module_path, framework: framework if klass.applies? module_path end nil end |
Instance Method Details
#cleanup ⇒ Object (protected)
156 157 158 159 160 161 |
# File 'lib/msf/core/modules/external/bridge.rb', line 156 def cleanup self.running = false self..close harvest_process self.ios.each {|fd| fd.close rescue nil} # Yeah, yeah. I know. end |
#close ⇒ Object
33 34 35 36 37 38 |
# File 'lib/msf/core/modules/external/bridge.rb', line 33 def close self.running = false self.read_thread.join self end |
#exec(req) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/msf/core/modules/external/bridge.rb', line 15 def exec(req) unless self.running self.running = true send(req) self.read_thread = threadme do begin while self.running && m = self..push m end ensure cleanup end end self end end |
#handle_exception(e) ⇒ Object (protected)
79 80 81 |
# File 'lib/msf/core/modules/external/bridge.rb', line 79 def handle_exception(e) e end |
#harvest_process ⇒ Object (protected)
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/msf/core/modules/external/bridge.rb', line 145 def harvest_process if self.wait_thread.join(10) self.exit_status = self.wait_thread.value elsif Process.kill('TERM', self.wait_thread.pid) && self.wait_thread.join(10) self.exit_status = self.wait_thread.value else Process.kill('KILL', self.wait_thread.pid) self.exit_status = self.wait_thread.value end end |
#next_message(timeout = 600) ⇒ Object (protected)
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/msf/core/modules/external/bridge.rb', line 87 def (timeout=600) _, out, err = self.ios = '' # Multiple messages can come over the wire all at once, and since yajl # doesn't play nice with windows, we have to emulate a state machine to # read just enough off the wire to get one request at a time. Since # Windows cannot do a nonblocking read on a pipe, we are forced to do a # whole lot of `select` syscalls and keep a buffer ourselves :( begin loop do # This is so we don't end up calling JSON.parse on every char and # catch an exception. Windows can't do nonblock on pipes, so we # still have to do the select if we are not at the end of object # and don't have any buffer left parts = self.buf.split '}', 2 if parts.length == 2 # [part, rest] << parts[0] << '}' self.buf = parts[1] break elsif parts.length == 1 # [part] << parts[0] self.buf = '' end # We would call Rex::Threadsafe directly, but that would require Rex for standalone use res = select([out, err], nil, nil, timeout) if res == nil # This is what we would have gotten without Rex and what `readpartial` can also raise raise EOFError.new else fds = res[0] # Preferentially drain and log stderr, EOF counts as activity, but # stdout might have some buffered data left, so carry on if fds.include?(err) && !err.eof? errbuf = err.readpartial(4096) if self.framework elog "Unexpected output running #{self.path}:\n#{errbuf}" else $stderr.puts errbuf end end if fds.include? out self.buf << out.readpartial(4096) end end end Message.from_module(JSON.parse()) rescue JSON::ParserError # Probably an incomplete response, but no way to really tell. Keep trying # until EOF retry rescue EOFError => e self.running = false end end |
#send(message) ⇒ Object (protected)
XXX TODO non-blocking writes, check write lengths
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/msf/core/modules/external/bridge.rb', line 61 def send() input, output, err, status = ::Open3.popen3(self.env, *self.cmd) self.ios = [input, output, err] self.wait_thread = status # We would call Rex::Threadsafe directly, but that would require rex for standalone use case select(nil, [input], nil, 0.1) when nil raise "Cannot run module #{self.path}" when [[], [input], []] m = .to_json (input, m) else raise "Error running module #{self.path}" end rescue => e raise handle_exception(e) end |
#success? ⇒ Boolean
40 41 42 |
# File 'lib/msf/core/modules/external/bridge.rb', line 40 def success? self.exit_status && self.exit_status.success? end |
#threadme(&block) ⇒ Object (protected)
163 164 165 166 167 168 169 170 |
# File 'lib/msf/core/modules/external/bridge.rb', line 163 def threadme(&block) if self.framework # Leak as few connections as possible self.framework.threads.spawn("External Module #{self.path}", false, &block) else ::Thread.new &block end end |
#write_message(fd, json) ⇒ Object (protected)
83 84 85 |
# File 'lib/msf/core/modules/external/bridge.rb', line 83 def (fd, json) fd.write(json) end |