librex 0.0.6 → 0.0.7

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