librex 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. data/README.md +1 -1
  2. data/Rakefile +13 -0
  3. data/lib/rex.rb +4 -1
  4. data/lib/rex/assembly/nasm.rb +4 -0
  5. data/lib/rex/compat.rb +31 -1
  6. data/lib/rex/encoder/alpha2/generic.rb +11 -10
  7. data/lib/rex/exceptions.rb +1 -1
  8. data/lib/rex/exploitation/egghunter.rb +27 -0
  9. data/lib/rex/file.rb +13 -0
  10. data/lib/rex/io/stream.rb +9 -1
  11. data/lib/rex/io/stream_abstraction.rb +18 -7
  12. data/lib/rex/io/stream_server.rb +2 -2
  13. data/lib/rex/job_container.rb +1 -1
  14. data/lib/rex/mime/message.rb +5 -4
  15. data/lib/rex/ole.rb +83 -6
  16. data/lib/rex/ole/propset.rb +144 -0
  17. data/lib/rex/parser/ip360_aspl_xml.rb +102 -0
  18. data/lib/rex/parser/ip360_xml.rb +93 -0
  19. data/lib/rex/parser/nessus_xml.rb +118 -0
  20. data/lib/rex/parser/netsparker_xml.rb +94 -0
  21. data/lib/rex/parser/retina_xml.rb +109 -0
  22. data/lib/rex/post/meterpreter/channel.rb +15 -8
  23. data/lib/rex/post/meterpreter/client.rb +32 -3
  24. data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +1 -1
  25. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +14 -5
  26. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +1 -1
  27. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +3 -3
  28. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +1 -1
  29. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +1 -1
  30. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +5 -0
  31. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +16 -8
  32. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -7
  33. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +1 -1
  34. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +15 -4
  35. data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +13 -7
  36. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +20 -0
  37. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +63 -0
  38. data/lib/rex/post/meterpreter/packet_dispatcher.rb +18 -7
  39. data/lib/rex/post/meterpreter/packet_response_waiter.rb +10 -17
  40. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +1 -1
  41. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +16 -6
  42. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +4 -5
  43. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +2 -0
  44. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +4 -2
  45. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +157 -0
  46. data/lib/rex/proto/dhcp/server.rb +8 -4
  47. data/lib/rex/proto/http/client.rb +19 -45
  48. data/lib/rex/proto/http/packet.rb +8 -5
  49. data/lib/rex/proto/http/response.rb +8 -3
  50. data/lib/rex/proto/http/server.rb +1 -1
  51. data/lib/rex/proto/proxy/socks4a.rb +4 -4
  52. data/lib/rex/proto/rfb.rb +19 -0
  53. data/lib/rex/proto/rfb.rb.ut.rb +37 -0
  54. data/lib/rex/proto/rfb/cipher.rb +78 -0
  55. data/lib/rex/proto/rfb/client.rb +207 -0
  56. data/lib/rex/proto/rfb/constants.rb +52 -0
  57. data/lib/rex/proto/tftp/server.rb +20 -17
  58. data/lib/rex/services/local_relay.rb +1 -1
  59. data/lib/rex/socket.rb +69 -10
  60. data/lib/rex/socket/comm/local.rb +7 -4
  61. data/lib/rex/socket/range_walker.rb +14 -1
  62. data/lib/rex/text.rb +28 -3
  63. data/lib/rex/text.rb.ut.rb +14 -0
  64. data/lib/rex/thread_factory.rb +42 -0
  65. data/lib/rex/ui/text/input/buffer.rb +1 -1
  66. data/lib/rex/zip/archive.rb +74 -9
  67. data/lib/rex/zip/entry.rb +6 -1
  68. metadata +22 -7
@@ -56,16 +56,15 @@ class Console::CommandDispatcher::Sniffer
56
56
  end
57
57
 
58
58
  def cmd_sniffer_start(*args)
59
- intf = args[0].to_i
59
+ intf = args.shift.to_i
60
60
  if (intf == 0)
61
61
  print_error("Usage: sniffer_start [interface-id] [packet-buffer (1-200000)] [bpf filter (posix meterpreter only)]")
62
62
  return
63
63
  end
64
- maxp = args[1].to_i
65
- maxp = 50000 if maxp == 0
66
- filter = args[2..-1].join(" ")
64
+ maxp = (args.shift || 50000).to_i
65
+ bpf = args.join(" ")
67
66
 
68
- client.sniffer.capture_start(intf, maxp, filter)
67
+ client.sniffer.capture_start(intf, maxp, bpf)
69
68
  print_status("Capture started on interface #{intf} (#{maxp} packet buffer)")
70
69
  return true
71
70
  end
@@ -16,6 +16,7 @@ class Console::CommandDispatcher::Stdapi
16
16
  require 'rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net'
17
17
  require 'rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys'
18
18
  require 'rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui'
19
+ require 'rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam'
19
20
 
20
21
  Klass = Console::CommandDispatcher::Stdapi
21
22
 
@@ -25,6 +26,7 @@ class Console::CommandDispatcher::Stdapi
25
26
  Klass::Net,
26
27
  Klass::Sys,
27
28
  Klass::Ui,
29
+ Klass::Webcam,
28
30
  ]
29
31
 
30
32
  include Console::CommandDispatcher
@@ -223,7 +223,7 @@ class Console::CommandDispatcher::Stdapi::Fs
223
223
  stat = client.fs.file.stat(src)
224
224
 
225
225
  if (stat.directory?)
226
- client.fs.dir.download(dest, src, recursive) { |step, src, dst|
226
+ client.fs.dir.download(dest, src, recursive, true) { |step, src, dst|
227
227
  print_status("#{step.ljust(11)}: #{src} -> #{dst}")
228
228
  }
229
229
  elsif (stat.file?)
@@ -247,7 +247,9 @@ class Console::CommandDispatcher::Stdapi::Fs
247
247
  end
248
248
 
249
249
  # Get a temporary file path
250
- temp_path = Tempfile.new('meterp').path
250
+ meterp_temp = Tempfile.new('meterp')
251
+ meterp_temp.binmode
252
+ temp_path = meterp_temp.path
251
253
 
252
254
  begin
253
255
  # Download the remote file to the temporary file
@@ -0,0 +1,157 @@
1
+ require 'rex/post/meterpreter'
2
+
3
+ module Rex
4
+ module Post
5
+ module Meterpreter
6
+ module Ui
7
+
8
+ ###
9
+ #
10
+ # Webcam - Capture video from the remote system
11
+ #
12
+ ###
13
+ class Console::CommandDispatcher::Stdapi::Webcam
14
+
15
+ Klass = Console::CommandDispatcher::Stdapi::Webcam
16
+
17
+ include Console::CommandDispatcher
18
+
19
+ #
20
+ # List of supported commands.
21
+ #
22
+ def commands
23
+ {
24
+ "webcam_list" => "List webcams",
25
+ "webcam_snap" => "Take a snapshot from the specified webcam",
26
+ "record_mic" => "Record audio from the default microphone for X seconds"
27
+ }
28
+ end
29
+
30
+ #
31
+ # Name for this dispatcher
32
+ #
33
+ def name
34
+ "Stdapi: Webcam"
35
+ end
36
+
37
+ def cmd_webcam_list
38
+ begin
39
+ client.webcam.webcam_list.each_with_index { |name, indx|
40
+ print_line("#{indx + 1}: #{name}")
41
+ }
42
+ return true
43
+ rescue
44
+ print_error("No webcams were found")
45
+ return false
46
+ end
47
+ end
48
+
49
+ def cmd_webcam_snap(*args)
50
+ path = Rex::Text.rand_text_alpha(8) + ".jpeg"
51
+ quality = 50
52
+ view = true
53
+ index = 1
54
+ wc_list = []
55
+
56
+ webcam_snap_opts = Rex::Parser::Arguments.new(
57
+ "-h" => [ false, "Help Banner" ],
58
+ "-i" => [ true, "The index of the webcam to use (Default: 1)" ],
59
+ "-q" => [ true, "The JPEG image quality (Default: '#{quality}')" ],
60
+ "-p" => [ true, "The JPEG image path (Default: '#{path}')" ],
61
+ "-v" => [ true, "Automatically view the JPEG image (Default: '#{view}')" ]
62
+ )
63
+
64
+ webcam_snap_opts.parse( args ) { | opt, idx, val |
65
+ case opt
66
+ when "-h"
67
+ print_line( "Usage: webcam_snap [options]\n" )
68
+ print_line( "Grab a frame from the specified webcam." )
69
+ print_line( webcam_snap_opts.usage )
70
+ return
71
+ when "-i"
72
+ index = val.to_i
73
+ when "-q"
74
+ quality = val.to_i
75
+ when "-p"
76
+ path = val
77
+ when "-v"
78
+ view = false if ( val =~ /^(f|n|0)/i )
79
+ end
80
+ }
81
+ begin
82
+ wc_list << client.webcam.webcam_list
83
+ rescue
84
+ end
85
+ if wc_list.length > 0
86
+ print_status("Starting...")
87
+ client.webcam.webcam_start(index)
88
+ data = client.webcam.webcam_get_frame(quality)
89
+ print_good("Got frame")
90
+ client.webcam.webcam_stop
91
+ print_status("Stopped")
92
+
93
+ if( data )
94
+ ::File.open( path, 'wb' ) do |fd|
95
+ fd.write( data )
96
+ end
97
+ path = ::File.expand_path( path )
98
+ print_line( "Webcam shot saved to: #{path}" )
99
+ Rex::Compat.open_file( path ) if view
100
+ end
101
+ return true
102
+ else
103
+ print_error("No webcams where found")
104
+ return false
105
+ end
106
+ end
107
+
108
+ def cmd_record_mic(*args)
109
+ path = Rex::Text.rand_text_alpha(8) + ".wav"
110
+ play = true
111
+ duration = 1
112
+
113
+ record_mic_opts = Rex::Parser::Arguments.new(
114
+ "-h" => [ false, "Help Banner" ],
115
+ "-d" => [ true, "Number of seconds to record (Default: 1)" ],
116
+ "-f" => [ true, "The wav file path (Default: '#{::File.expand_path( "[randomname].wav" )}')" ],
117
+ "-p" => [ true, "Automatically play the captured audio (Default: '#{play}')" ]
118
+ )
119
+
120
+ record_mic_opts.parse( args ) { | opt, idx, val |
121
+ case opt
122
+ when "-h"
123
+ print_line( "Usage: record_mic [options]\n" )
124
+ print_line( "Records audio from the default microphone." )
125
+ print_line( record_mic_opts.usage )
126
+ return
127
+ when "-d"
128
+ duration = val.to_i
129
+ when "-f"
130
+ path = val
131
+ when "-p"
132
+ play = false if ( val =~ /^(f|n|0)/i )
133
+ end
134
+ }
135
+
136
+ print_status("Starting...")
137
+ data = client.webcam.record_mic(duration)
138
+ print_status("Stopped")
139
+
140
+ if( data )
141
+ ::File.open( path, 'wb' ) do |fd|
142
+ fd.write( data )
143
+ end
144
+ path = ::File.expand_path( path )
145
+ print_line( "Audio saved to: #{path}" )
146
+ Rex::Compat.play_sound( path ) if play
147
+ end
148
+ return true
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+ end
155
+ end
156
+ end
157
+
@@ -1,4 +1,4 @@
1
- # $Id: server.rb 10261 2010-09-08 17:06:31Z jduck $
1
+ # $Id: server.rb 11003 2010-11-12 06:19:49Z hdm $
2
2
 
3
3
  require 'rex/socket'
4
4
  require 'rex/proto/dhcp'
@@ -36,7 +36,9 @@ class Server
36
36
  if ipstart
37
37
  self.start_ip = Rex::Socket.addr_atoi(ipstart)
38
38
  else
39
- self.start_ip = "#{self.ipstring[0..2]}\x20" #default range x.x.x.32-254
39
+ # Use the first 3 octects of the server's IP to construct the
40
+ # default range of x.x.x.32-254
41
+ self.start_ip = "#{self.ipstring[0..2]}\x20".unpack("N").first
40
42
  end
41
43
  self.current_ip = start_ip
42
44
 
@@ -44,7 +46,9 @@ class Server
44
46
  if ipend
45
47
  self.end_ip = Rex::Socket.addr_atoi(ipend)
46
48
  else
47
- self.end_ip = "#{self.ipstring[0..2]}\xfe"
49
+ # Use the first 3 octects of the server's IP to construct the
50
+ # default range of x.x.x.32-254
51
+ self.end_ip = "#{self.ipstring[0..2]}\xfe".unpack("N").first
48
52
  end
49
53
 
50
54
  # netmask
@@ -95,7 +99,7 @@ class Server
95
99
  'Context' => context
96
100
  )
97
101
 
98
- self.thread = Thread.new {
102
+ self.thread = Rex::ThreadFactory.spawn("DHCPServerMonitor", false) {
99
103
  monitor_socket
100
104
  }
101
105
  end
@@ -328,7 +328,9 @@ class Client
328
328
  def send_recv(req, t = -1, persist=false)
329
329
  @pipeline = persist
330
330
  send_request(req)
331
- read_response(t)
331
+ res = read_response(t)
332
+ res.request = req.to_s if res
333
+ res
332
334
  end
333
335
 
334
336
  #
@@ -361,10 +363,12 @@ class Client
361
363
  rv != Packet::ParseCode::Completed and
362
364
  rv != Packet::ParseCode::Error
363
365
  )
366
+
364
367
  begin
365
- buff = conn.get_once(-1, 1)
366
- rv = resp.parse( buff || '')
367
368
 
369
+ buff = conn.get_once(-1, 1)
370
+ rv = resp.parse( buff || '' )
371
+
368
372
  ##########################################################################
369
373
  # XXX: NOTE: BUG: get_once currently (as of r10042) rescues "Exception"
370
374
  # As such, the following rescue block will ever be reached. -jjd
@@ -390,7 +394,7 @@ class Client
390
394
  rblob = rbody.to_s + rbufq.to_s
391
395
  tries = 0
392
396
  begin
393
- # XXX This doesn't deal with chunked encoding or "Content-type: text/html; charset=..."
397
+ # XXX: This doesn't deal with chunked encoding or "Content-type: text/html; charset=..."
394
398
  while tries < 1000 and resp.headers["Content-Type"]== "text/html" and rblob !~ /<\/html>/i
395
399
  buff = conn.get_once(-1, 0.05)
396
400
  break if not buff
@@ -405,50 +409,20 @@ class Client
405
409
  end
406
410
  end
407
411
  end
408
- resp
409
- end
410
-
411
- #
412
- # Read a response from the server (starting with existing data)
413
- #
414
- def reread_response(resp, t = -1)
415
-
416
- resp.max_data = config['read_max_data']
417
- resp.reset_except_queue
418
- resp.parse('')
419
-
420
- # Wait at most t seconds for the full response to be read in. We only
421
- # do this if t was specified as a negative value indicating an infinite
422
- # wait cycle. If t were specified as nil it would indicate that no
423
- # response parsing is required.
424
-
425
- return resp if not t
426
-
427
- Timeout.timeout((t < 0) ? nil : t) do
428
412
 
429
- rv = resp.state
413
+ return resp if not resp
430
414
 
431
- while (
432
- rv != Packet::ParseCode::Completed and
433
- rv != Packet::ParseCode::Error
434
- )
435
- begin
436
- buff = conn.get
437
- rv = resp.parse( buff || '')
438
-
439
- # Handle unexpected disconnects
440
- rescue ::Errno::EPIPE, ::EOFError, ::IOError
441
- case resp.state
442
- when Packet::ParseState::ProcessingHeader
443
- resp = nil
444
- when Packet::ParseState::ProcessingBody
445
- # truncated request, good enough
446
- resp.error = :truncated
447
- end
448
- break
449
- end
450
- end
415
+ # As a last minute hack, we check to see if we're dealing with a 100 Continue here.
416
+ if resp.proto == '1.1' and resp.code == 100
417
+ # If so, our real response becaome the body, so we re-parse it.
418
+ body = resp.body
419
+ resp = Response.new
420
+ resp.max_data = config['read_max_data']
421
+ rv = resp.parse(body)
422
+ # XXX: At some point, this may benefit from processing post-completion code
423
+ # as seen above.
451
424
  end
425
+
452
426
  resp
453
427
  end
454
428
 
@@ -85,7 +85,8 @@ class Packet
85
85
 
86
86
  # Continue on to the body if the header was processed
87
87
  if(self.state == ParseState::ProcessingBody)
88
- if (self.body_bytes_left == 0)
88
+ # Chunked encoding sets the parsing state on its own
89
+ if (self.body_bytes_left == 0 and not self.transfer_chunked)
89
90
  self.state = ParseState::Completed
90
91
  else
91
92
  parse_body
@@ -165,7 +166,9 @@ class Packet
165
166
  # Converts the packet to a string.
166
167
  #
167
168
  def to_s
168
- content = self.body.dup
169
+ # Duplicate and make sure this is 8BIT safe for Ruby 1.9
170
+ content = self.body.unpack("C*").pack("C*")
171
+
169
172
  # Update the content length field in the header with the body length.
170
173
  if (content)
171
174
  if !self.compress.nil?
@@ -264,6 +267,7 @@ protected
264
267
  def parse_header
265
268
 
266
269
  head,data = self.bufq.split(/\r?\n\r?\n/, 2)
270
+
267
271
  return if not data
268
272
 
269
273
  self.headers.from_s(head)
@@ -346,7 +350,7 @@ protected
346
350
  clen = self.bufq.slice!(/^[a-fA-F0-9]+\r?\n/)
347
351
 
348
352
  clen.rstrip! if (clen)
349
-
353
+
350
354
  # if we happen to fall upon the end of the buffer for the next chunk len and have no data left, go get some more...
351
355
  if clen.nil? and self.bufq.length == 0
352
356
  return
@@ -358,7 +362,7 @@ protected
358
362
  return
359
363
  end
360
364
 
361
- self.body_bytes_left = clen.hex
365
+ self.body_bytes_left = clen.to_i(16)
362
366
 
363
367
  if (self.body_bytes_left == 0)
364
368
  self.bufq.sub!(/^\r?\n/s,'')
@@ -373,7 +377,6 @@ protected
373
377
  # to our body state.
374
378
  if (self.body_bytes_left > 0)
375
379
  part = self.bufq.slice!(0, self.body_bytes_left)
376
-
377
380
  self.body += part
378
381
  self.body_bytes_left -= part.length
379
382
  # Otherwise, just read it all.
@@ -74,12 +74,17 @@ class Response < Packet
74
74
  "HTTP\/#{proto} #{code}#{(message and message.length > 0) ? ' ' + message : ''}\r\n"
75
75
  end
76
76
 
77
- attr_accessor :code
77
+ #
78
+ # Used to store a copy of the original request
79
+ #
80
+ attr_accessor :request
81
+
82
+
83
+ attr_accessor :code
78
84
  attr_accessor :message
79
85
  attr_accessor :proto
80
-
81
86
  end
82
87
 
83
88
  end
84
89
  end
85
- end
90
+ end
@@ -342,7 +342,7 @@ protected
342
342
  # If we found the resource handler for this resource, call its
343
343
  # procedure.
344
344
  if (p[1] == true)
345
- Thread.new {
345
+ Rex::ThreadFactory.spawn("HTTPServerRequestHandler", false) {
346
346
  handler.on_request(cli, request)
347
347
  }
348
348
  else
@@ -165,7 +165,7 @@ class Socks4a
165
165
  @relay_client = relay_client
166
166
  @relay_sock = relay_sock
167
167
  # start the relay thread (modified from Rex::IO::StreamAbstraction)
168
- @relay_thread = ::Thread.new do
168
+ @relay_thread = Rex::ThreadFactory.spawn("SOCKS4AProxyServerRelay", false) do
169
169
  loop do
170
170
  closed = false
171
171
  buf = nil
@@ -234,7 +234,7 @@ class Socks4a
234
234
  #
235
235
  def start
236
236
  # create a thread to handle this client request so as to not block the socks4a server
237
- @client_thread = ::Thread.new do
237
+ @client_thread = Rex::ThreadFactory.spawn("SOCKS4AProxyClient", false) do
238
238
  begin
239
239
  @server.add_client( self )
240
240
  # get the initial client request packet
@@ -378,7 +378,7 @@ class Socks4a
378
378
  # signal we are now running
379
379
  @running = true
380
380
  # start the servers main thread to pick up new clients
381
- @server_thread = ::Thread.new do
381
+ @server_thread = Rex::ThreadFactory.spawn("SOCKS4AProxyServer", false) do
382
382
  while( @running ) do
383
383
  begin
384
384
  # accept the client connection
@@ -437,4 +437,4 @@ class Socks4a
437
437
 
438
438
  end
439
439
 
440
- end; end; end
440
+ end; end; end