librex 0.0.6 → 0.0.7

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 (51) hide show
  1. data/README.md +3 -5
  2. data/Rakefile +26 -0
  3. data/lib/rex/compat.rb +1 -1
  4. data/lib/rex/exploitation/javascriptosdetect.rb +125 -62
  5. data/lib/rex/file.rb +15 -0
  6. data/lib/rex/io/stream.rb +1 -1
  7. data/lib/rex/parser/nmap_xml.rb +6 -0
  8. data/lib/rex/poly/block.rb +9 -0
  9. data/lib/rex/post/meterpreter/client.rb +0 -8
  10. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +6 -0
  11. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +1 -1
  12. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +49 -35
  13. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +26 -0
  14. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +9 -2
  15. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +630 -0
  16. data/lib/rex/post/meterpreter/packet.rb +3 -1
  17. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +143 -57
  18. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +6 -0
  19. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +9 -3
  20. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +6 -4
  21. data/lib/rex/proto.rb +1 -0
  22. data/lib/rex/proto/dhcp/server.rb +4 -2
  23. data/lib/rex/proto/http/packet.rb +5 -6
  24. data/lib/rex/proto/ntlm.rb +7 -0
  25. data/lib/rex/proto/ntlm.rb.ut.rb +177 -0
  26. data/lib/rex/proto/ntlm/base.rb +326 -0
  27. data/lib/rex/proto/ntlm/constants.rb +74 -0
  28. data/lib/rex/proto/ntlm/crypt.rb +340 -0
  29. data/lib/rex/proto/ntlm/exceptions.rb +9 -0
  30. data/lib/rex/proto/ntlm/message.rb +533 -0
  31. data/lib/rex/proto/ntlm/utils.rb +358 -0
  32. data/lib/rex/proto/smb/client.rb +548 -86
  33. data/lib/rex/proto/smb/client.rb.ut.rb +4 -4
  34. data/lib/rex/proto/smb/constants.rb +7 -24
  35. data/lib/rex/proto/smb/crypt.rb +12 -71
  36. data/lib/rex/proto/smb/exceptions.rb +12 -0
  37. data/lib/rex/proto/smb/simpleclient.rb +17 -5
  38. data/lib/rex/proto/smb/utils.rb +3 -460
  39. data/lib/rex/proto/tftp/server.rb +2 -2
  40. data/lib/rex/script/base.rb +2 -2
  41. data/lib/rex/socket.rb +12 -0
  42. data/lib/rex/socket.rb.ut.rb +31 -10
  43. data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +15 -5
  44. data/lib/rex/text.rb +55 -4
  45. data/lib/rex/ui/output.rb +0 -2
  46. data/lib/rex/ui/text/dispatcher_shell.rb +95 -10
  47. data/lib/rex/ui/text/output/buffer.rb +0 -4
  48. data/lib/rex/ui/text/shell.rb +8 -0
  49. data/lib/rex/ui/text/table.rb +21 -1
  50. metadata +15 -19
  51. data/lib/rex/proto/smb/crypt.rb.ut.rb +0 -20
@@ -1,4 +1,4 @@
1
- # $Id: server.rb 11454 2010-12-30 16:37:58Z hdm $
1
+ # $Id: server.rb 11636 2011-01-25 02:24:37Z hdm $
2
2
  require 'rex/socket'
3
3
  require 'rex/proto/tftp'
4
4
 
@@ -194,7 +194,7 @@ protected
194
194
  if @output_dir
195
195
  fn = tr[:file][:name].split(File::SEPARATOR)[-1]
196
196
  if fn
197
- fn = ::File.join(@output_dir, fn)
197
+ fn = ::File.join(@output_dir, Rex::FileUtils.clean_path(fn))
198
198
  ::File.open(fn, "wb") { |fd|
199
199
  fd.write(tr[:file][:data])
200
200
  }
@@ -35,8 +35,8 @@ class Base
35
35
  raise Rex::Script::Completed
36
36
  end
37
37
 
38
- def run(args)
39
- self.args = args
38
+ def run(args=[])
39
+ self.args = args = args.flatten
40
40
  begin
41
41
  eval(::File.read(self.path, ::File.size(self.path)), binding )
42
42
  rescue ::Interrupt
@@ -131,6 +131,18 @@ module Socket
131
131
  (addr =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))$/) ? true : false
132
132
  end
133
133
 
134
+ #
135
+ # Return true if +addr+ is within the ranges specified in RFC1918, or
136
+ # RFC5735/RFC3927
137
+ #
138
+ def self.is_internal?(addr)
139
+ if self.dotted_ip?(addr)
140
+ addr =~ /^(?:10\.|192\.168|172.(?:1[6-9]|2[0-9]|3[01])\.|169\.254)/
141
+ else
142
+ false
143
+ end
144
+ end
145
+
134
146
  #
135
147
  # Wrapper for Resolv.getaddress that takes special care to see if the
136
148
  # supplied address is already a dotted quad, for instance. This is
@@ -42,25 +42,35 @@ class Rex::Socket::UnitTest < Test::Unit::TestCase
42
42
  end
43
43
 
44
44
  def test_to_sockaddr
45
- assert_equal("\x00" * 16, Rex::Socket.to_sockaddr(nil, 0, 0), "null sockaddr")
46
- assert_equal([2].pack('s') + "\x00\x16" + "\x00" * 12, Rex::Socket.to_sockaddr(nil, 22), "default addr, port 22 sockaddr")
47
- assert_equal([2].pack('s') + "\x00\x16\x01\x02\x03\x04" + "\x00" * 8, Rex::Socket.to_sockaddr("1.2.3.4", 22), "1.2.3.4 addr, port 22 sockaddr")
45
+ assert_equal(([2] + [0]*14).pack("sC*"), Rex::Socket.to_sockaddr(0, 0), "null sockaddr")
46
+ =begin
47
+ # This is platform dependent, pain to test
48
+ if (Rex::Socket.support_ipv6?)
49
+ # Use the constant for AF_INET6 since it is different per platform
50
+ # (10 on linux and 28 on BSD)
51
+ inaddr_any_sockaddr = ([::Socket::AF_INET6, 22] + [0]*24).pack('sSC*')
52
+ else
53
+ inaddr_any_sockaddr = ([2, 22] + [0]*12).pack('snC*')
54
+ end
55
+ =end
56
+ assert_equal(([2, 0x16, 1, 2, 3, 4] + [0]*8).pack('snC*'), Rex::Socket.to_sockaddr("1.2.3.4", 22), "1.2.3.4 addr, port 22 sockaddr")
48
57
  end
49
58
 
50
59
  def test_from_sockaddr
51
- af, host, port = Rex::Socket.from_sockaddr("\x00" * 16)
52
- assert_equal(0, af, "zero af")
60
+ # 1.9.1 raises ArgumentError if we don't have an af == AF_INET or AF_INET6
61
+ af, host, port = Rex::Socket.from_sockaddr(([2, 0] + [0]*12).pack('snC*'))
62
+ assert_equal(2, af, "af = 2")
53
63
  assert_equal('0.0.0.0', host, "zero host")
54
64
  assert_equal(0, port, "zero port")
55
65
 
56
- af, host, port = Rex::Socket.from_sockaddr([2].pack('s') + "\x00\x16" + "\x00" * 12)
66
+ af, host, port = Rex::Socket.from_sockaddr(([2, 22]+[0]*12).pack('snC*'))
57
67
  assert_equal(2, af, "af = 2")
58
- assert_equal('0.0.0.0', host, "zero host")
59
68
  assert_equal(22, port, "port = 22")
69
+ assert_equal('0.0.0.0', host, "zero host")
60
70
 
61
- af, host, port = Rex::Socket.from_sockaddr([2].pack('s') + "\x00\x16\x01\x02\x03\x04" + "\x00" * 8)
71
+ af, host, port = Rex::Socket.from_sockaddr(([2, 22, 1, 2, 3, 4] + [0]*8).pack('snC*') )
62
72
  assert_equal(2, af, "af = 2")
63
- assert_equal('1.2.3.4', host, "zero host")
73
+ assert_equal('1.2.3.4', host, "host = '1.2.3.4'")
64
74
  assert_equal(22, port, "port = 22")
65
75
  end
66
76
 
@@ -83,4 +93,15 @@ class Rex::Socket::UnitTest < Test::Unit::TestCase
83
93
  assert_equal("255.255.0.0", Rex::Socket.bit2netmask(16))
84
94
  end
85
95
 
86
- end
96
+ def test_is_internal
97
+ assert( ! Rex::Socket.is_internal?("1.2.3.4"))
98
+ assert( ! Rex::Socket.is_internal?("172.15.3.4"))
99
+ assert( ! Rex::Socket.is_internal?("172.32.3.4"))
100
+ assert(Rex::Socket.is_internal?("10.2.3.4"))
101
+ assert(Rex::Socket.is_internal?("192.168.3.4"))
102
+ 16.upto(31) do |octet|
103
+ assert(Rex::Socket.is_internal?("172.#{octet}.3.4"))
104
+ end
105
+ end
106
+
107
+ end
@@ -5,17 +5,23 @@ $:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
5
5
  require 'test/unit'
6
6
  require 'rex/socket/ssl_tcp_server'
7
7
  require 'rex/socket/ssl_tcp'
8
+ require 'rex/text'
8
9
 
9
10
  class Rex::Socket::SslTcpServer::UnitTest < Test::Unit::TestCase
10
11
 
11
12
  # XXX. The client data is sent & decrypted just fine. The server data is not. the client thread just spins. BAH.
13
+ #
14
+ # As of 2011-03-04, works fine on 1.8.6-p399, 1.8.7-p330, 1.9.1-p378
15
+ #
12
16
  def test_tcp_server
13
- return;
17
+ #return;
14
18
 
15
19
  serv_port = 65433
16
20
  c = nil
17
21
 
18
22
  threads = []
23
+
24
+ # Server thread
19
25
  threads << Thread.new() {
20
26
  serv = Rex::Socket.create_tcp_server('LocalPort' => serv_port, 'SSL' => true)
21
27
  assert_kind_of(Rex::Socket::SslTcpServer, serv, "type => ssl")
@@ -24,12 +30,16 @@ class Rex::Socket::SslTcpServer::UnitTest < Test::Unit::TestCase
24
30
  s = serv.accept
25
31
  assert_equal("client_data\n", s.get_once(), "s: get_once")
26
32
  assert_equal(3, s.write("Yo\n"), "s: put Yo")
27
- assert(s.methods.include?('<<'))
28
- assert(s.methods.include?('>>'))
29
- assert(s.methods.include?('has_read_data?'))
33
+ # Make sure methods are Strings for 1.9 compat (which returns
34
+ # symbols)
35
+ meths = s.methods.map {|m| m.to_s}
36
+ assert(meths.include?("<<"), "Has <<")
37
+ assert(meths.include?(">>"), "Has >>")
38
+ assert(meths.include?("has_read_data?"), "Has has_read_data?")
30
39
  serv.close
31
40
  }
32
41
 
42
+ # Client thread
33
43
  threads << Thread.new() {
34
44
  sleep(2)
35
45
  assert_nothing_raised {
@@ -48,4 +58,4 @@ class Rex::Socket::SslTcpServer::UnitTest < Test::Unit::TestCase
48
58
  threads.each { |aThread| aThread.join }
49
59
  end
50
60
 
51
- end
61
+ end
@@ -237,7 +237,7 @@ module Text
237
237
  #
238
238
  def self.to_hex_ascii(str, prefix = "\\x", count = 1, suffix=nil)
239
239
  raise ::RuntimeError, "unable to chunk into #{count} byte chunks" if ((str.length % count) > 0)
240
- return str.unpack('H*')[0].gsub(Regexp.new(".{#{count * 2}}", nil, 'n')) { |s|
240
+ return str.unpack('H*')[0].gsub(Regexp.new(".{#{count * 2}}", nil, 'n')) { |s|
241
241
  (0x20..0x7e) === s.to_i(16) ? s.to_i(16).chr : prefix + s + suffix.to_s
242
242
  }
243
243
  end
@@ -414,6 +414,33 @@ module Text
414
414
  end
415
415
  end
416
416
 
417
+ #
418
+ # Converts a unicode string to standard ASCII text.
419
+ #
420
+ def self.to_ascii(str='', type = 'utf-16le', mode = '', size = '')
421
+ return '' if not str
422
+ case type
423
+ when 'utf-16le'
424
+ return str.unpack('v*').pack('C*')
425
+ when 'utf-16be'
426
+ return str.unpack('n*').pack('C*')
427
+ when 'utf-32le'
428
+ return str.unpack('V*').pack('C*')
429
+ when 'utf-32be'
430
+ return str.unpack('N*').pack('C*')
431
+ when 'utf-7'
432
+ raise TypeError, 'invalid utf type, not yet implemented'
433
+ when 'utf-8'
434
+ raise TypeError, 'invalid utf type, not yet implemented'
435
+ when 'uhwtfms' # suggested name from HD :P
436
+ raise TypeError, 'invalid utf type, not yet implemented'
437
+ when 'uhwtfms-half' # suggested name from HD :P
438
+ raise TypeError, 'invalid utf type, not yet implemented'
439
+ else
440
+ raise TypeError, 'invalid utf type'
441
+ end
442
+ end
443
+
417
444
  #
418
445
  # Encode a string in a manor useful for HTTP URIs and URI Parameters.
419
446
  #
@@ -795,7 +822,7 @@ module Text
795
822
  sets.size.times { counter << 0}
796
823
  0.upto(len-1) do |i|
797
824
  setnum = i % sets.size
798
-
825
+
799
826
  puts counter.inspect
800
827
  end
801
828
 
@@ -891,7 +918,8 @@ module Text
891
918
  raise RuntimeError, "Invalid gzip compression level" if (level < 1 or level > 9)
892
919
 
893
920
  s = ""
894
- gz = Zlib::GzipWriter.new(StringIO.new(s), level)
921
+ s.force_encoding('ASCII-8BIT') if s.respond_to?(:encoding)
922
+ gz = Zlib::GzipWriter.new(StringIO.new(s, 'wb'), level)
895
923
  gz << str
896
924
  gz.close
897
925
  return s
@@ -904,7 +932,8 @@ module Text
904
932
  raise RuntimeError, "Gzip support is not present." if (!zlib_present?)
905
933
 
906
934
  s = ""
907
- gz = Zlib::GzipReader.new(StringIO.new(str))
935
+ s.force_encoding('ASCII-8BIT') if s.respond_to?(:encoding)
936
+ gz = Zlib::GzipReader.new(StringIO.new(str, 'rb'))
908
937
  s << gz.read
909
938
  gz.close
910
939
  return s
@@ -1034,6 +1063,28 @@ module Text
1034
1063
  [bits.join].pack("B32").unpack("N")[0]
1035
1064
  end
1036
1065
 
1066
+ #
1067
+ # Split a string by n charachter into an array
1068
+ #
1069
+ def self.split_to_a(str, n)
1070
+ if n > 0
1071
+ s = str.dup
1072
+ until s.empty?
1073
+ (ret ||= []).push s.slice!(0, n)
1074
+ end
1075
+ else
1076
+ ret = str
1077
+ end
1078
+ ret
1079
+ end
1080
+
1081
+ #
1082
+ #Pack a value as 64 bit litle endian; does not exist for Array.pack
1083
+ #
1084
+ def self.pack_int64le(val)
1085
+ [val & 0x00000000ffffffff, val >> 32].pack("V2")
1086
+ end
1087
+
1037
1088
 
1038
1089
  protected
1039
1090
 
@@ -17,8 +17,6 @@ class Output
17
17
  # Text-based output
18
18
  require 'rex/ui/text/output'
19
19
 
20
- attr_accessor :on_print_proc
21
-
22
20
  #
23
21
  # Prints an error message.
24
22
  #
@@ -1,4 +1,5 @@
1
1
  require 'rex/ui'
2
+ require 'pp'
2
3
 
3
4
  module Rex
4
5
  module Ui
@@ -79,11 +80,75 @@ module DispatcherShell
79
80
  shell.update_prompt(prompt)
80
81
  end
81
82
 
83
+ #
84
+ # Displays the help banner. With no arguments, this is just a list of
85
+ # all commands grouped by dispatcher. Otherwise, tries to use a method
86
+ # named cmd_#{+cmd+}_help for the first dispatcher that has a command
87
+ # named +cmd+.
88
+ #
89
+ def cmd_help(cmd=nil, *ignored)
90
+ if cmd
91
+ help_found = false
92
+ cmd_found = false
93
+ shell.dispatcher_stack.each do |dispatcher|
94
+ next unless dispatcher.respond_to?(:commands)
95
+ next if (dispatcher.commands.nil?)
96
+ next if (dispatcher.commands.length == 0)
97
+
98
+ if dispatcher.respond_to?("cmd_#{cmd}")
99
+ cmd_found = true
100
+ break unless dispatcher.respond_to? "cmd_#{cmd}_help"
101
+ dispatcher.send("cmd_#{cmd}_help")
102
+ help_found = true
103
+ break
104
+ end
105
+ end
106
+ print_error("No help for #{cmd}, try -h") if cmd_found and not help_found
107
+ print_error("No such command") if not cmd_found
108
+ else
109
+ print(shell.help_to_s)
110
+ end
111
+ end
112
+
113
+ #
114
+ # Tab completion for the help command
115
+ #
116
+ # By default just returns a list of all commands in all dispatchers.
117
+ #
118
+ def cmd_help_tabs(str, words)
119
+ return [] if words.length > 1
120
+
121
+ tabs = []
122
+ shell.dispatcher_stack.each { |dispatcher|
123
+ tabs += dispatcher.commands.keys
124
+ }
125
+ return tabs
126
+ end
127
+
128
+ alias cmd_? cmd_help
129
+
130
+
82
131
  #
83
132
  # No tab completion items by default
84
133
  #
85
134
  attr_accessor :shell, :tab_complete_items
86
135
 
136
+ #
137
+ # Provide a generic tab completion for file names.
138
+ #
139
+ # If the only completion is a directory, this descends into that directory
140
+ # and continues completions with filenames contained within.
141
+ #
142
+ def tab_complete_filenames(str, words)
143
+ matches = ::Readline::FILENAME_COMPLETION_PROC.call(str)
144
+ if matches and matches.length == 1 and File.directory?(matches[0])
145
+ dir = matches[0]
146
+ dir += File::SEPARATOR if dir[-1,1] != File::SEPARATOR
147
+ matches = ::Readline::FILENAME_COMPLETION_PROC.call(dir)
148
+ end
149
+ matches
150
+ end
151
+
87
152
  end
88
153
 
89
154
  #
@@ -91,8 +156,6 @@ module DispatcherShell
91
156
  #
92
157
  include Shell
93
158
 
94
- attr_accessor :on_command_proc
95
-
96
159
  #
97
160
  # Initialize the dispatcher shell.
98
161
  #
@@ -148,20 +211,22 @@ module DispatcherShell
148
211
 
149
212
  # If no command is set and it supports commands, add them all
150
213
  if (tab_words.empty? and dispatcher.respond_to?('commands'))
151
- items.concat(dispatcher.commands.to_a.map { |x| x[0] })
214
+ items.concat(dispatcher.commands.keys)
152
215
  end
153
216
 
154
217
  # If the dispatcher exports a tab completion function, use it
155
218
  if(dispatcher.respond_to?('tab_complete_helper'))
156
219
  res = dispatcher.tab_complete_helper(str, tab_words)
220
+ else
221
+ res = tab_complete_helper(dispatcher, str, tab_words)
222
+ end
157
223
 
158
- if (res.nil?)
159
- # A nil response indicates no optional arguments
160
- return [''] if items.empty?
161
- else
162
- # Otherwise we add the completion items to the list
163
- items.concat(res)
164
- end
224
+ if (res.nil?)
225
+ # A nil response indicates no optional arguments
226
+ return [''] if items.empty?
227
+ else
228
+ # Otherwise we add the completion items to the list
229
+ items.concat(res)
165
230
  end
166
231
  }
167
232
 
@@ -184,6 +249,26 @@ module DispatcherShell
184
249
  }
185
250
  end
186
251
 
252
+ #
253
+ # Provide command-specific tab completion
254
+ #
255
+ def tab_complete_helper(dispatcher, str, words)
256
+ items = []
257
+
258
+ tabs_meth = "cmd_#{words[0]}_tabs"
259
+ # Is the user trying to tab complete one of our commands?
260
+ if (dispatcher.commands.include?(words[0]) and dispatcher.respond_to?(tabs_meth))
261
+ res = dispatcher.send(tabs_meth, str, words)
262
+ return [] if res.nil?
263
+ items.concat(res)
264
+ else
265
+ # Avoid the default completion list for known commands
266
+ return []
267
+ end
268
+
269
+ return items
270
+ end
271
+
187
272
  #
188
273
  # Run a single command line.
189
274
  #
@@ -28,10 +28,6 @@ class Output::Buffer < Rex::Ui::Text::Output
28
28
  def print_raw(msg = '')
29
29
  self.buf += msg || ''
30
30
 
31
- if self.on_print_proc
32
- self.on_print_proc.call(msg)
33
- end
34
-
35
31
  msg
36
32
  end
37
33
 
@@ -204,6 +204,7 @@ module Shell
204
204
  def print_error(msg='')
205
205
  return if (output.nil?)
206
206
 
207
+ self.on_print_proc.call(msg) if self.on_print_proc
207
208
  # Errors are not subject to disabled output
208
209
  log_output(output.print_error(msg))
209
210
  end
@@ -214,6 +215,7 @@ module Shell
214
215
  def print_status(msg='')
215
216
  return if (disable_output == true)
216
217
 
218
+ self.on_print_proc.call(msg) if self.on_print_proc
217
219
  log_output(output.print_status(msg))
218
220
  end
219
221
 
@@ -223,6 +225,7 @@ module Shell
223
225
  def print_good(msg='')
224
226
  return if (disable_output == true)
225
227
 
228
+ self.on_print_proc.call(msg) if self.on_print_proc
226
229
  log_output(output.print_good(msg))
227
230
  end
228
231
 
@@ -232,6 +235,7 @@ module Shell
232
235
  def print_line(msg='')
233
236
  return if (disable_output == true)
234
237
 
238
+ self.on_print_proc.call(msg) if self.on_print_proc
235
239
  log_output(output.print_line(msg))
236
240
  end
237
241
 
@@ -240,6 +244,7 @@ module Shell
240
244
  #
241
245
  def print(msg='')
242
246
  return if (disable_output == true)
247
+ self.on_print_proc.call(msg) if self.on_print_proc
243
248
  log_output(output.print(msg))
244
249
  end
245
250
 
@@ -256,6 +261,9 @@ module Shell
256
261
  #
257
262
  attr_reader :output
258
263
 
264
+ attr_accessor :on_command_proc
265
+ attr_accessor :on_print_proc
266
+
259
267
  protected
260
268
 
261
269
  #