librex 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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