librex 0.0.29 → 0.0.30

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.
data/README.markdown CHANGED
@@ -3,7 +3,7 @@
3
3
  A non-official re-packaging of the Rex library as a gem for easy of usage of the Metasploit REX framework in a non Metasploit application. I received permission from HDM to create this package.
4
4
 
5
5
  Currently based on:
6
- SVN Revision: 12371
6
+ SVN Revision: 12516
7
7
 
8
8
  # Credits
9
9
  The Metasploit development team <http://www.metasploit.com>
@@ -54,7 +54,7 @@ class RingBuffer
54
54
  end
55
55
 
56
56
  #
57
- # The built-in monitor thread
57
+ # The built-in monitor thread (normally unused with Metasploit)
58
58
  #
59
59
  def monitor_thread
60
60
  Thread.new do
@@ -74,8 +74,8 @@ class RingBuffer
74
74
  # Push data back into the associated stream socket. Logging must occur
75
75
  # elsewhere, this function is simply a passthrough.
76
76
  #
77
- def put(data)
78
- self.fd.put(data)
77
+ def put(data, opts={})
78
+ self.fd.put(data, opts={})
79
79
  end
80
80
 
81
81
  #
data/lib/rex/io/stream.rb CHANGED
@@ -35,20 +35,20 @@ module Stream
35
35
  total_sent = 0
36
36
  total_length = buf.length
37
37
  block_size = 32768
38
+
38
39
  begin
39
40
  while( total_sent < total_length )
40
41
  s = Rex::ThreadSafe.select( nil, [ fd ], nil, 0.2 )
41
42
  if( s == nil || s[0] == nil )
42
43
  next
43
44
  end
44
- data = buf[0, block_size]
45
+ data = buf[total_sent, block_size]
45
46
  sent = fd.write_nonblock( data )
46
47
  if sent > 0
47
48
  total_sent += sent
48
- buf[0, sent] = ""
49
49
  end
50
50
  end
51
- rescue ::Errno::EAGAIN
51
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
52
52
  # Sleep for a half a second, or until we can write again
53
53
  Rex::ThreadSafe.select( nil, [ fd ], nil, 0.5 )
54
54
  # Decrement the block size to handle full sendQs better
@@ -57,8 +57,8 @@ module Stream
57
57
  retry
58
58
  rescue ::IOError, ::Errno::EPIPE
59
59
  return nil if (fd.abortive_close == true)
60
- raise $!
61
60
  end
61
+
62
62
  total_sent
63
63
  end
64
64
 
@@ -66,12 +66,16 @@ module Stream
66
66
  # This method reads data of the supplied length from the stream.
67
67
  #
68
68
  def read(length = nil, opts = {})
69
- # XXX handle length being nil
69
+
70
70
  begin
71
- fd.readpartial(length)
72
- rescue ::IOError, ::EOFError, ::Errno::EPIPE
71
+ return fd.read_nonblock( length )
72
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
73
+ # Sleep for a half a second, or until we can read again
74
+ Rex::ThreadSafe.select( [ fd ], nil, nil, 0.5 )
75
+ # Decrement the block size to handle full sendQs better
76
+ retry
77
+ rescue ::IOError, ::Errno::EPIPE
73
78
  return nil if (fd.abortive_close == true)
74
- raise $!
75
79
  end
76
80
  end
77
81
 
@@ -68,19 +68,19 @@ module StreamAbstraction
68
68
  end
69
69
 
70
70
  #
71
- # Writes to the local side.
71
+ # Low-level write to the local side.
72
72
  #
73
73
  def syswrite(buffer)
74
74
  lsock.syswrite(buffer)
75
75
  end
76
-
76
+
77
77
  #
78
- # Reads from the local side.
78
+ # Low-level read from the local side.
79
79
  #
80
80
  def sysread(length)
81
81
  lsock.sysread(length)
82
82
  end
83
-
83
+
84
84
  #
85
85
  # Shuts down the local side of the stream abstraction.
86
86
  #
@@ -160,15 +160,18 @@ protected
160
160
  total_length = buf.length
161
161
  while( total_sent < total_length )
162
162
  begin
163
- data = buf[0, buf.length]
163
+ data = buf[total_sent, buf.length]
164
+
165
+ # Note that this must be write() NOT syswrite() or put() or anything like it.
166
+ # Using syswrite() breaks SSL streams.
164
167
  sent = self.write( data )
165
- # sf: Only remove the data off the queue is syswrite was successfull.
168
+
169
+ # sf: Only remove the data off the queue is write was successfull.
166
170
  # This way we naturally perform a resend if a failure occured.
167
171
  # Catches an edge case with meterpreter TCP channels where remote send
168
172
  # failes gracefully and a resend is required.
169
173
  if( sent > 0 )
170
174
  total_sent += sent
171
- buf[0, sent] = ""
172
175
  end
173
176
  rescue ::IOError => e
174
177
  closed = true
@@ -177,6 +177,18 @@ class JobContainer < Hash
177
177
  self.delete(inst.jid.to_s)
178
178
  end
179
179
 
180
+ #
181
+ # Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
182
+ # "can't add a new key into hash during iteration"
183
+ #
184
+ def each(&block)
185
+ list = []
186
+ self.keys.sort.each do |sidx|
187
+ list << [sidx, self[sidx]]
188
+ end
189
+ list.each(&block)
190
+ end
191
+
180
192
  protected
181
193
 
182
194
  attr_accessor :job_id_pool # :nodoc:
@@ -0,0 +1,131 @@
1
+ #
2
+ # This is a Ruby port of the Python manifest parsing code posted to:
3
+ # http://stackoverflow.com/questions/3085153/how-to-parse-the-manifest-mbdb-file-in-an-ios-4-0-itunes-backup/3130860#3130860
4
+ #
5
+
6
+ module Rex
7
+ module Parser
8
+ class AppleBackupManifestDB
9
+
10
+ attr_accessor :entry_offsets
11
+ attr_accessor :entries
12
+ attr_accessor :mbdb, :mbdx
13
+ attr_accessor :mbdb_data, :mbdx_data
14
+ attr_accessor :mbdb_offset, :mbdx_offset
15
+
16
+ def initialize(mbdb_data, mbdx_data)
17
+ self.entries = {}
18
+ self.entry_offsets = {}
19
+ self.mbdb_data = mbdb_data
20
+ self.mbdx_data = mbdx_data
21
+ parse_mbdb
22
+ parse_mbdx
23
+ end
24
+
25
+ def self.from_files(mbdb_file, mbdx_file)
26
+ mbdb_data = ""
27
+ ::File.open(mbdb_file, "rb") {|fd| mbdb_data = fd.read(fd.stat.size) }
28
+ mbdx_data = ""
29
+ ::File.open(mbdx_file, "rb") {|fd| mbdx_data = fd.read(fd.stat.size) }
30
+
31
+ self.new(mbdb_data, mbdx_data)
32
+ end
33
+
34
+ def parse_mbdb
35
+ raise ArgumentError, "Not valid MBDB data" if self.mbdb_data[0,4] != "mbdb"
36
+ self.mbdb_offset = 4
37
+ self.mbdb_offset = self.mbdb_offset + 2 # Maps to \x05 \x00 (unknown)
38
+
39
+ while self.mbdb_offset < self.mbdb_data.length
40
+ info = {}
41
+ info[:start_offset] = self.mbdb_offset
42
+ info[:domain] = mbdb_read_string
43
+ info[:filename] = mbdb_read_string
44
+ info[:linktarget] = mbdb_read_string
45
+ info[:datahash] = mbdb_read_string
46
+ info[:unknown1] = mbdb_read_string
47
+ info[:mode] = mbdb_read_int(2)
48
+ info[:unknown2] = mbdb_read_int(4)
49
+ info[:unknown3] = mbdb_read_int(4)
50
+ info[:uid] = mbdb_read_int(4)
51
+ info[:gid] = mbdb_read_int(4)
52
+ info[:mtime] = Time.at(mbdb_read_int(4))
53
+ info[:atime] = Time.at(mbdb_read_int(4))
54
+ info[:ctime] = Time.at(mbdb_read_int(4))
55
+ info[:length] = mbdb_read_int(8)
56
+ info[:flag] = mbdb_read_int(1)
57
+ property_count = mbdb_read_int(1)
58
+ info[:properties] = {}
59
+ 1.upto(property_count) do |i|
60
+ k = mbdb_read_string
61
+ v = mbdb_read_string
62
+ info[:properties][k] = v
63
+ end
64
+ self.entry_offsets[ info[:start_offset] ] = info
65
+ end
66
+ self.mbdb_data = ""
67
+ end
68
+
69
+ def parse_mbdx
70
+ raise ArgumentError, "Not a valid MBDX file" if self.mbdx_data[0,4] != "mbdx"
71
+
72
+ self.mbdx_offset = 4
73
+ self.mbdx_offset = self.mbdx_offset + 2 # Maps to \x02 \x00 (unknown)
74
+
75
+ file_count = mbdx_read_int(4)
76
+
77
+ while self.mbdx_offset < self.mbdx_data.length
78
+ file_id = self.mbdx_data[self.mbdx_offset, 20].unpack("C*").map{|c| "%02x" % c}.join
79
+ self.mbdx_offset += 20
80
+ entry_offset = mbdx_read_int(4) + 6
81
+ mode = mbdx_read_int(2)
82
+ entry = entry_offsets[ entry_offset ]
83
+ # May be corrupted if there is no matching entry, but what to do about it?
84
+ next if not entry
85
+ self.entries[file_id] = entry.merge({:mbdx_mode => mode, :file_id => file_id})
86
+ end
87
+ self.mbdx_data = ""
88
+ end
89
+
90
+ def mbdb_read_string
91
+ raise RuntimeError, "Corrupted MBDB file" if self.mbdb_offset > self.mbdb_data.length
92
+ len = self.mbdb_data[self.mbdb_offset, 2].unpack("n")[0]
93
+ self.mbdb_offset += 2
94
+ return '' if len == 65535
95
+ val = self.mbdb_data[self.mbdb_offset, len]
96
+ self.mbdb_offset += len
97
+ return val
98
+ end
99
+
100
+ def mbdb_read_int(size)
101
+ val = 0
102
+ size.downto(1) do |i|
103
+ val = (val << 8) + self.mbdb_data[self.mbdb_offset, 1].unpack("C")[0]
104
+ self.mbdb_offset += 1
105
+ end
106
+ val
107
+ end
108
+
109
+ def mbdx_read_string
110
+ raise RuntimeError, "Corrupted MBDX file" if self.mbdx_offset > self.mbdx_data.length
111
+ len = self.mbdx_data[self.mbdx_offset, 2].unpack("n")[0]
112
+ self.mbdx_offset += 2
113
+ return '' if len == 65535
114
+ val = self.mbdx_data[self.mbdx_offset, len]
115
+ self.mbdx_offset += len
116
+ return val
117
+ end
118
+
119
+ def mbdx_read_int(size)
120
+ val = 0
121
+ size.downto(1) do |i|
122
+ val = (val << 8) + self.mbdx_data[self.mbdx_offset, 1].unpack("C")[0]
123
+ self.mbdx_offset += 1
124
+ end
125
+ val
126
+ end
127
+ end
128
+
129
+
130
+ end
131
+ end
@@ -51,6 +51,10 @@ class NexposeXMLStreamParser
51
51
  when "test"
52
52
  if attributes["status"] == "vulnerable-exploited" or attributes["status"] == "vulnerable-version"
53
53
  @host["vulns"][attributes["id"]] = attributes.dup
54
+ if attributes["key"]
55
+ @host["notes"] ||= []
56
+ @host["notes"] << [attributes["id"], attributes["key"]]
57
+ end
54
58
  end
55
59
  when "vulnerability"
56
60
  @vuln.merge! attributes
@@ -128,7 +128,32 @@ class Client
128
128
  ctx = generate_ssl_context()
129
129
  ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
130
130
 
131
- ssl.accept
131
+ if not ssl.respond_to?(:accept_nonblock)
132
+ ssl.accept
133
+ else
134
+ begin
135
+ ssl.accept_nonblock
136
+
137
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
138
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
139
+ IO::select(nil, nil, nil, 0.10)
140
+ retry
141
+
142
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
143
+ rescue ::Exception => e
144
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
145
+ IO::select( [ ssl ], nil, nil, 0.10 )
146
+ retry
147
+ end
148
+
149
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
150
+ IO::select( nil, [ ssl ], nil, 0.10 )
151
+ retry
152
+ end
153
+
154
+ raise e
155
+ end
156
+ end
132
157
 
133
158
  self.sock.extend(Rex::Socket::SslTcp)
134
159
  self.sock.sslsock = ssl
@@ -72,12 +72,14 @@ class Priv < Extension
72
72
  if( response.result == 0 and technique != nil )
73
73
  client.core.use( "stdapi" ) if not client.ext.aliases.include?( "stdapi" )
74
74
  client.sys.config.getprivs
75
- client.framework.db.report_note(
76
- :host => client.sock.peerhost,
77
- :workspace => client.framework.db.workspace,
78
- :type => "meterpreter.getsystem",
79
- :data => {:technique => technique}
80
- ) rescue nil
75
+ if client.framework.db and client.framework.db.active
76
+ client.framework.db.report_note(
77
+ :host => client.sock.peerhost,
78
+ :workspace => client.framework.db.workspace,
79
+ :type => "meterpreter.getsystem",
80
+ :data => {:technique => technique}
81
+ ) rescue nil
82
+ end
81
83
  return [ true, technique ]
82
84
  end
83
85
 
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..','..','..','..','..', 'lib'))
4
+
5
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/dll'
6
+ require 'test/unit'
7
+
8
+ module Rex
9
+ module Post
10
+ module Meterpreter
11
+ module Extensions
12
+ module Stdapi
13
+ module Railgun
14
+ class DLL::UnitTest < Test::Unit::TestCase
15
+
16
+ TLV_TYPE_NAMES = {
17
+ TLV_TYPE_RAILGUN_SIZE_OUT => "TLV_TYPE_RAILGUN_SIZE_OUT",
18
+ TLV_TYPE_RAILGUN_STACKBLOB => "TLV_TYPE_RAILGUN_STACKBLOB",
19
+ TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "TLV_TYPE_RAILGUN_BUFFERBLOB_IN",
20
+ TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT",
21
+ TLV_TYPE_RAILGUN_DLLNAME => "TLV_TYPE_RAILGUN_DLLNAME",
22
+ TLV_TYPE_RAILGUN_FUNCNAME => "TLV_TYPE_RAILGUN_FUNCNAME",
23
+ }
24
+
25
+ class MockRailgunClient
26
+ attr_reader :platform, :check_request, :response_tlvs
27
+
28
+ def initialize(platform, response_tlvs, check_request)
29
+ @check_request = check_request
30
+ @response_tlvs = response_tlvs
31
+ @platform = platform
32
+ end
33
+
34
+ def send_request(request)
35
+ check_request.call(request)
36
+
37
+ (Class.new do
38
+ def initialize(response_tlvs)
39
+ @response_tlvs = response_tlvs
40
+ end
41
+ def get_tlv_value(type)
42
+ return @response_tlvs[type]
43
+ end
44
+ end).new(@response_tlvs)
45
+ end
46
+ end
47
+
48
+ def make_mock_client(platform = "x86/win32", target_request_tlvs = [], response_tlvs = [])
49
+ check_request = lambda do |request|
50
+ target_request_tlvs.each_pair do |type, target_value|
51
+ assert_equal(target_value, request.get_tlv_value(type),
52
+ "process_function_call should send to client appropriate #{TLV_TYPE_NAMES[type]}")
53
+ end
54
+ end
55
+
56
+ return MockRailgunClient.new(platform, response_tlvs, check_request)
57
+ end
58
+
59
+ def test_add_function
60
+ function_descriptions.each do |func|
61
+ dll = DLL.new(func[:dll_name], make_mock_client(func[:platform]), nil)
62
+ dll.add_function(func[:name], func[:return_type], func[:params])
63
+
64
+ assert(dll.functions.has_key?(func[:name]),
65
+ "add_function should expand the list of available functions")
66
+ end
67
+ end
68
+
69
+ def test_method_missing
70
+ function_descriptions.each do |func|
71
+ client = make_mock_client(func[:platform], func[:request_to_client], func[:response_from_client])
72
+ dll = DLL.new(func[:dll_name], client, nil)
73
+
74
+ dll.add_function(func[:name], func[:return_type], func[:params])
75
+
76
+ actual_returned_hash = dll.send(:method_missing, func[:name].to_sym, *func[:ruby_args])
77
+
78
+ assert(func[:returned_hash].has_key?('GetLastError'),
79
+ "process_function_call should add the result of GetLastError to the key GetLastError")
80
+
81
+ assert_equal(func[:returned_hash], actual_returned_hash,
82
+ "process_function_call convert function result to a ruby hash")
83
+ end
84
+ end
85
+
86
+ # These are sample descriptions of functions to use for testing.
87
+ def function_descriptions
88
+ [
89
+ {
90
+ :platform => "x86/win32",
91
+ :name => "LookupAccountSidA",
92
+ :params => [
93
+ ["PCHAR","lpSystemName","in"],
94
+ ["LPVOID","Sid","in"],
95
+ ["PCHAR","Name","out"],
96
+ ["PDWORD","cchName","inout"],
97
+ ["PCHAR","ReferencedDomainName","out"],
98
+ ["PDWORD","cchReferencedDomainName","inout"],
99
+ ["PBLOB","peUse","out"],
100
+ ],
101
+ :return_type => "BOOL",
102
+ :dll_name => "advapi32",
103
+ :ruby_args => [nil, 1371864, 100, 100, 100, 100, 1],
104
+ :request_to_client => {
105
+ TLV_TYPE_RAILGUN_SIZE_OUT => 201,
106
+ TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD8\xEE\x14\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00d\x00\x00\x00\x03\x00\x00\x00\b\x00\x00\x00\x02\x00\x00\x00\xC8\x00\x00\x00",
107
+ TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "",
108
+ TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "d\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x00\x00\x00\x00",
109
+ TLV_TYPE_RAILGUN_DLLNAME => "advapi32",
110
+ TLV_TYPE_RAILGUN_FUNCNAME => "LookupAccountSidA"
111
+ },
112
+ :response_from_client => {
113
+ TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "\x06\x00\x00\x00\x00\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00",
114
+ TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "SYSTEM\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANT AUTHORITY\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x05",
115
+ TLV_TYPE_RAILGUN_BACK_RET => 1,
116
+ TLV_TYPE_RAILGUN_BACK_ERR => 997
117
+ },
118
+ :returned_hash => {
119
+ "GetLastError" => 997,
120
+ "return" => true,
121
+ "Name" => "SYSTEM",
122
+ "ReferencedDomainName" => "NT AUTHORITY",
123
+ "peUse" => "\x05",
124
+ "cchName" => 6,
125
+ "cchReferencedDomainName" => 12
126
+ },
127
+ },
128
+ {
129
+ :platform => 'x64/win64',
130
+ :name => 'LookupAccountSidA',
131
+ :params => [
132
+ ["PCHAR", "lpSystemName", "in"],
133
+ ["LPVOID", "Sid", "in"],
134
+ ["PCHAR", "Name", "out"],
135
+ ["PDWORD", "cchName", "inout"],
136
+ ["PCHAR", "ReferencedDomainName", "out"],
137
+ ["PDWORD", "cchReferencedDomainName", "inout"],
138
+ ["PBLOB", "peUse", "out"]
139
+ ],
140
+ :return_type => 'BOOL',
141
+ :dll_name => 'advapi32',
142
+ :ruby_args => [nil, 1631552, 100, 100, 100, 100, 1],
143
+ :request_to_client => {
144
+ TLV_TYPE_RAILGUN_SIZE_OUT => 201,
145
+ TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\xE5\x18\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x00\x00\x00",
146
+ TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "",
147
+ TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "d\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x00\x00\x00\x00",
148
+ TLV_TYPE_RAILGUN_DLLNAME => 'advapi32',
149
+ TLV_TYPE_RAILGUN_FUNCNAME => 'LookupAccountSidA',
150
+ },
151
+ :response_from_client => {
152
+ TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "\x06\x00\x00\x00\x00\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00",
153
+ TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "SYSTEM\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANT AUTHORITY\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x05",
154
+ TLV_TYPE_RAILGUN_BACK_RET => 1,
155
+ TLV_TYPE_RAILGUN_BACK_ERR => 0,
156
+ },
157
+ :returned_hash => {
158
+ "GetLastError"=>0,
159
+ "return"=>true,
160
+ "Name"=>"SYSTEM",
161
+ "ReferencedDomainName"=>"NT AUTHORITY",
162
+ "peUse"=>"\x05",
163
+ "cchName"=>6,
164
+ "cchReferencedDomainName"=>12
165
+ },
166
+ },
167
+ ]
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
@@ -555,7 +555,9 @@ class Console::CommandDispatcher::Core
555
555
  end
556
556
 
557
557
  if (mod)
558
- print_line ::Msf::Serializer::ReadableText.dump_module(mod)
558
+ print_line(::Msf::Serializer::ReadableText.dump_module(mod))
559
+ mod_opt = ::Msf::Serializer::ReadableText.dump_options(mod, ' ')
560
+ print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if (mod_opt and mod_opt.length > 0)
559
561
  end
560
562
  end
561
563
 
@@ -21,11 +21,13 @@ class Console::CommandDispatcher::Stdapi::Fs
21
21
  # Options for the download command.
22
22
  #
23
23
  @@download_opts = Rex::Parser::Arguments.new(
24
+ "-h" => [ false, "Help banner." ],
24
25
  "-r" => [ false, "Download recursively." ])
25
26
  #
26
27
  # Options for the upload command.
27
28
  #
28
29
  @@upload_opts = Rex::Parser::Arguments.new(
30
+ "-h" => [ false, "Help banner." ],
29
31
  "-r" => [ false, "Upload recursively." ])
30
32
 
31
33
  #
@@ -179,17 +181,21 @@ class Console::CommandDispatcher::Stdapi::Fs
179
181
  end
180
182
 
181
183
  alias :cmd_del :cmd_rm
184
+
185
+ def cmd_download_help
186
+ print_line "Usage: download [options] src1 src2 src3 ... destination"
187
+ print_line
188
+ print_line "Downloads remote files and directories to the local machine."
189
+ print_line @@download_opts.usage
190
+ end
182
191
 
183
192
  #
184
193
  # Downloads a file or directory from the remote machine to the local
185
194
  # machine.
186
195
  #
187
196
  def cmd_download(*args)
188
- if (args.empty?)
189
- print(
190
- "Usage: download [options] src1 src2 src3 ... destination\n\n" +
191
- "Downloads remote files and directories to the local machine.\n" +
192
- @@download_opts.usage)
197
+ if (args.empty? or args.include? "-h")
198
+ cmd_download_help
193
199
  return true
194
200
  end
195
201
 
@@ -361,7 +367,7 @@ class Console::CommandDispatcher::Stdapi::Fs
361
367
  # Removes one or more directory if it's empty.
362
368
  #
363
369
  def cmd_rmdir(*args)
364
- if (args.length == 0)
370
+ if (args.length == 0 or args.include?("-h"))
365
371
  print_line("Usage: rmdir dir1 dir2 dir3 ...")
366
372
  return true
367
373
  end
@@ -374,16 +380,20 @@ class Console::CommandDispatcher::Stdapi::Fs
374
380
  return true
375
381
  end
376
382
 
383
+ def cmd_upload_help
384
+ print_line "Usage: upload [options] src1 src2 src3 ... destination"
385
+ print_line
386
+ print_line "Uploads local files and directories to the remote machine."
387
+ print_line @@upload_opts.usage
388
+ end
389
+
377
390
  #
378
391
  # Uploads a file or directory to the remote machine from the local
379
392
  # machine.
380
393
  #
381
394
  def cmd_upload(*args)
382
- if (args.empty?)
383
- print(
384
- "Usage: upload [options] src1 src2 src3 ... destination\n\n" +
385
- "Uploads local files and directories to the remote machine.\n" +
386
- @@upload_opts.usage)
395
+ if (args.empty? or args.include?("-h"))
396
+ cmd_upload_help
387
397
  return true
388
398
  end
389
399
 
@@ -51,7 +51,7 @@ class Console::CommandDispatcher::Stdapi::Sys
51
51
  "execute" => "Execute a command",
52
52
  "getpid" => "Get the current process identifier",
53
53
  "getuid" => "Get the user that the server is running as",
54
- "getprivs" => "List all privileges available to the current process",
54
+ "getprivs" => "Attempt to enable all privileges available to the current process",
55
55
  "kill" => "Terminate a process",
56
56
  "ps" => "List running processes",
57
57
  "reboot" => "Reboots the remote computer",
@@ -421,10 +421,24 @@ class Console::CommandDispatcher::Stdapi::Sys
421
421
  client.sys.config.revert_to_self
422
422
  end
423
423
 
424
+ def cmd_getprivs_help
425
+ print_line "Usage: getprivs"
426
+ print_line
427
+ print_line "Attempt to enable all privileges, such as SeDebugPrivilege, available to the"
428
+ print_line "current process. Note that this only enables existing privs and does not change"
429
+ print_line "users or tokens."
430
+ print_line
431
+ print_line "See also: steal_token, getsystem"
432
+ print_line
433
+ end
434
+
424
435
  #
425
436
  # Obtains as many privileges as possible on the target machine.
426
437
  #
427
438
  def cmd_getprivs(*args)
439
+ if args.include? "-h"
440
+ cmd_getprivs_help
441
+ end
428
442
  print_line("=" * 60)
429
443
  print_line("Enabled Process Privileges")
430
444
  print_line("=" * 60)
@@ -1,4 +1,4 @@
1
- # $Id: constants.rb 12196 2011-04-01 00:51:33Z egypt $
1
+ # $Id: constants.rb 12375 2011-04-20 14:21:36Z jduck $
2
2
  require 'rex/proto/dhcp'
3
3
 
4
4
  module Rex
@@ -20,6 +20,7 @@ OpLeaseTime = 0x33
20
20
  OpSubnetMask = 1
21
21
  OpRouter = 3
22
22
  OpDns = 6
23
+ OpHostname = 0x0c
23
24
  OpEnd = 0xff
24
25
 
25
26
  PXEMagic = "\xF1\x00\x74\x7E"
@@ -1,4 +1,4 @@
1
- # $Id: server.rb 12196 2011-04-01 00:51:33Z egypt $
1
+ # $Id: server.rb 12471 2011-04-29 22:58:55Z scriptjunkie $
2
2
 
3
3
  require 'rex/socket'
4
4
  require 'rex/proto/dhcp'
@@ -12,6 +12,9 @@ module DHCP
12
12
  # DHCP Server class
13
13
  # not completely configurable - written specifically for a PXE server
14
14
  # - scriptjunkie
15
+ #
16
+ # extended to support testing/exploiting CVE-2011-0997
17
+ # - apconole@yahoo.com
15
18
  ##
16
19
 
17
20
  class Server
@@ -82,6 +85,17 @@ class Server
82
85
  else
83
86
  self.servePXE = false
84
87
  end
88
+
89
+ # Always assume we don't give out hostnames ...
90
+ self.give_hostname = false
91
+ self.served_over = 0
92
+ if (hash['HOSTNAME'])
93
+ self.give_hostname = true
94
+ self.served_hostname = hash['HOSTNAME']
95
+ if ( hash['HOSTSTART'] )
96
+ self.served_over = hash['HOSTSTART'].to_i
97
+ end
98
+ end
85
99
 
86
100
  self.leasetime = 600
87
101
  self.relayip = "\x00\x00\x00\x00" # relay ip - not currently suported
@@ -116,7 +130,8 @@ class Server
116
130
  def set_option(opts)
117
131
  allowed_options = [
118
132
  :serveOnce, :servePXE, :relayip, :leasetime, :dnsserv,
119
- :pxeconfigfile, :pxepathprefix, :pxereboottime, :router
133
+ :pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
134
+ :give_hostname, :served_hostname, :served_over
120
135
  ]
121
136
 
122
137
  opts.each_pair { |k,v|
@@ -144,6 +159,7 @@ class Server
144
159
  attr_accessor :sock, :thread, :myfilename, :ipstring, :served, :serveOnce
145
160
  attr_accessor :current_ip, :start_ip, :end_ip, :broadcasta, :netmaskn
146
161
  attr_accessor :servePXE, :pxeconfigfile, :pxepathprefix, :pxereboottime
162
+ attr_accessor :give_hostname, :served_hostname, :served_over
147
163
 
148
164
  protected
149
165
 
@@ -263,6 +279,12 @@ protected
263
279
  pkt << [DHCPAck].pack('C')
264
280
  # now we ignore their discovers (but we'll respond to requests in case a packet was lost)
265
281
  self.served.merge!( buf[28..43] => true )
282
+ if ( self.served_over != 0 )
283
+ # NOTE: this is sufficient for low-traffic net
284
+ # for high-traffic, this will probably lead to
285
+ # hostname collision
286
+ self.served_over += 1
287
+ end
266
288
  else
267
289
  #dlog("ignoring unknown DHCP request - type #{messageType}")
268
290
  return
@@ -278,6 +300,16 @@ protected
278
300
  pkt << dhcpoption(OpPXEConfigFile, self.pxeconfigfile)
279
301
  pkt << dhcpoption(OpPXEPathPrefix, self.pxepathprefix)
280
302
  pkt << dhcpoption(OpPXERebootTime, [self.pxereboottime].pack('N'))
303
+ if ( self.give_hostname == true )
304
+ send_hostname = self.served_hostname
305
+ if ( self.served_over != 0 )
306
+ # NOTE : see above comments for the 'uniqueness'
307
+ # of this value
308
+ send_hostname += self.served_over.to_s
309
+ end
310
+ pkt << dhcpoption(OpHostname, send_hostname)
311
+ end
312
+
281
313
  pkt << dhcpoption(OpEnd)
282
314
 
283
315
  pkt << ("\x00" * 32) #padding
@@ -141,6 +141,18 @@ class Packet::Header < Hash
141
141
  self.dcase_hash.clear
142
142
  end
143
143
 
144
+ #
145
+ # Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
146
+ # "can't add a new key into hash during iteration"
147
+ #
148
+ def each(&block)
149
+ list = []
150
+ self.keys.sort.each do |sidx|
151
+ list << [sidx, self[sidx]]
152
+ end
153
+ list.each(&block)
154
+ end
155
+
144
156
  #
145
157
  # The raw command string associated with the header which will vary between
146
158
  # requests and responses.
@@ -193,11 +193,10 @@ class Socks4a
193
193
  total_length = buf.length
194
194
  while( total_sent < total_length )
195
195
  begin
196
- data = buf[0, buf.length]
196
+ data = buf[total_sent, buf.length]
197
197
  sent = self.write( data )
198
198
  if( sent > 0 )
199
199
  total_sent += sent
200
- buf[0, sent] = ""
201
200
  end
202
201
  rescue
203
202
  closed = true
@@ -3,7 +3,6 @@ module Proto
3
3
  module SMB
4
4
  class Constants
5
5
 
6
- require 'rex/text'
7
6
  require 'rex/struct2'
8
7
 
9
8
  # SMB Commands
@@ -127,6 +127,18 @@ class ServiceManager < Hash
127
127
  return false
128
128
  end
129
129
 
130
+ #
131
+ # Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
132
+ # "can't add a new key into hash during iteration"
133
+ #
134
+ def each(&block)
135
+ list = []
136
+ self.keys.sort.each do |sidx|
137
+ list << [sidx, self[sidx]]
138
+ end
139
+ list.each(&block)
140
+ end
141
+
130
142
  protected
131
143
 
132
144
  #
@@ -138,4 +150,4 @@ protected
138
150
 
139
151
  end
140
152
 
141
- end
153
+ end
@@ -206,7 +206,7 @@ class Rex::Socket::Comm::Local
206
206
 
207
207
  # If a server TCP instance is being created...
208
208
  if (param.server?)
209
- sock.listen(128)
209
+ sock.listen(256)
210
210
 
211
211
  if (param.bare? == false)
212
212
  klass = Rex::Socket::TcpServer
@@ -14,9 +14,10 @@ begin
14
14
  begin
15
15
  require 'openssl'
16
16
  @@loaded_openssl = true
17
+ require 'openssl/nonblock'
17
18
  rescue ::Exception
18
19
  end
19
-
20
+
20
21
 
21
22
  include Rex::Socket::Tcp
22
23
 
@@ -55,12 +56,13 @@ begin
55
56
  def initsock(params = nil)
56
57
  super
57
58
 
58
-
59
59
  version = :SSLv3
60
60
  if(params)
61
61
  case params.ssl_version
62
62
  when 'SSL2'
63
63
  version = :SSLv2
64
+ when 'SSL23'
65
+ version = :SSLv23
64
66
  when 'TLS1'
65
67
  version = :TLSv1
66
68
  end
@@ -87,15 +89,40 @@ begin
87
89
 
88
90
  # Tie the context to a socket
89
91
  self.sslsock = OpenSSL::SSL::SSLSocket.new(self, self.sslctx)
90
-
92
+
91
93
  # XXX - enabling this causes infinite recursion, so disable for now
92
94
  # self.sslsock.sync_close = true
93
95
 
96
+
94
97
  # Force a negotiation timeout
95
98
  begin
96
99
  Timeout.timeout(params.timeout) do
97
- # Negotiate the connection
98
- self.sslsock.connect
100
+ if not self.sslsock.respond_to?(:connect_nonblock)
101
+ self.sslsock.connect
102
+ else
103
+ begin
104
+ self.sslsock.connect_nonblock
105
+
106
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
107
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
108
+ IO::select(nil, nil, nil, 0.10)
109
+ retry
110
+
111
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
112
+ rescue ::Exception => e
113
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
114
+ IO::select( [ self.sslsock ], nil, nil, 0.10 )
115
+ retry
116
+ end
117
+
118
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
119
+ IO::select( nil, [ self.sslsock ], nil, 0.10 )
120
+ retry
121
+ end
122
+
123
+ raise e
124
+ end
125
+ end
99
126
  end
100
127
 
101
128
  rescue ::Timeout::Error
@@ -113,22 +140,111 @@ begin
113
140
  # Writes data over the SSL socket.
114
141
  #
115
142
  def write(buf, opts = {})
116
- return sslsock.write(buf)
143
+ return sslsock.write(buf) if not self.sslsock.respond_to?(:write_nonblock)
144
+
145
+ total_sent = 0
146
+ total_length = buf.length
147
+ block_size = 32768
148
+
149
+ begin
150
+ while( total_sent < total_length )
151
+ s = Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, 0.25 )
152
+ if( s == nil || s[0] == nil )
153
+ next
154
+ end
155
+ data = buf[total_sent, block_size]
156
+ sent = sslsock.write_nonblock( data )
157
+ if sent > 0
158
+ total_sent += sent
159
+ end
160
+ end
161
+
162
+ rescue ::IOError, ::Errno::EPIPE
163
+ return nil if (fd.abortive_close == true)
164
+
165
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
166
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
167
+ # Sleep for a half a second, or until we can write again
168
+ Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, 0.5 )
169
+ # Decrement the block size to handle full sendQs better
170
+ block_size = 1024
171
+ # Try to write the data again
172
+ retry
173
+
174
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
175
+ rescue ::Exception => e
176
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
177
+ IO::select( [ self.sslsock ], nil, nil, 0.5 )
178
+ retry
179
+ end
180
+
181
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
182
+ IO::select( nil, [ self.sslsock ], nil, 0.5 )
183
+ retry
184
+ end
185
+
186
+ raise e
187
+ end
188
+
189
+ total_sent
117
190
  end
118
191
 
119
192
  #
120
193
  # Reads data from the SSL socket.
121
194
  #
122
- def read(length = nil, opts = {})
123
- length = 16384 unless length
195
+ def read(length = nil, opts = {})
196
+ if not self.sslsock.respond_to?(:read_nonblock)
197
+ length = 16384 unless length
198
+ begin
199
+ return sslsock.sysread(length)
200
+ rescue EOFError, ::Errno::EPIPE
201
+ raise EOFError
202
+ end
203
+ return
204
+ end
205
+
124
206
 
125
207
  begin
126
- return sslsock.sysread(length)
127
- rescue EOFError, ::Errno::EPIPE
128
- raise EOFError
208
+ while true
209
+ s = Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
210
+ if( s == nil || s[0] == nil )
211
+ next
212
+ end
213
+ buf = sslsock.read_nonblock( length )
214
+ return buf if buf
215
+ raise ::EOFError
216
+ end
217
+
218
+ rescue ::IOError, ::Errno::EPIPE
219
+ return nil if (fd.abortive_close == true)
220
+
221
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
222
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
223
+ # Sleep for a tenth a second, or until we can read again
224
+ Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
225
+ # Decrement the block size to handle full sendQs better
226
+ block_size = 1024
227
+ # Try to write the data again
228
+ retry
229
+
230
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
231
+ rescue ::Exception => e
232
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
233
+ IO::select( [ self.sslsock ], nil, nil, 0.5 )
234
+ retry
235
+ end
236
+
237
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
238
+ IO::select( nil, [ self.sslsock ], nil, 0.5 )
239
+ retry
240
+ end
241
+
242
+ raise e
129
243
  end
244
+
130
245
  end
131
246
 
247
+
132
248
  #
133
249
  # Closes the SSL socket.
134
250
  #
@@ -166,14 +282,14 @@ begin
166
282
  sslsock.cipher if sslsock
167
283
  end
168
284
 
169
-
170
-
171
285
  attr_reader :peer_verified # :nodoc:
172
286
  attr_accessor :sslsock, :sslctx # :nodoc:
287
+
173
288
  protected
174
289
 
175
290
  attr_writer :peer_verified # :nodoc:
176
291
 
292
+
177
293
  rescue LoadError
178
294
  end
179
295
 
@@ -15,10 +15,10 @@ module Rex::Socket::SslTcpServer
15
15
  begin
16
16
  require 'openssl'
17
17
  @@loaded_openssl = true
18
+ require 'openssl/nonblock'
18
19
  rescue ::Exception
19
20
  end
20
21
 
21
-
22
22
  include Rex::Socket::TcpServer
23
23
 
24
24
  ##
@@ -57,10 +57,39 @@ module Rex::Socket::SslTcpServer
57
57
 
58
58
  begin
59
59
  ssl = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)
60
- ssl.accept
60
+
61
+
62
+ if not ssl.respond_to?(:accept_nonblock)
63
+ ssl.accept
64
+ else
65
+ begin
66
+ ssl.accept_nonblock
67
+
68
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
69
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
70
+ IO::select(nil, nil, nil, 0.10)
71
+ retry
72
+
73
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
74
+ rescue ::Exception => e
75
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
76
+ IO::select( [ ssl ], nil, nil, 0.10 )
77
+ retry
78
+ end
79
+
80
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
81
+ IO::select( nil, [ ssl ], nil, 0.10 )
82
+ retry
83
+ end
84
+
85
+ raise e
86
+ end
87
+ end
88
+
61
89
  sock.extend(Rex::Socket::SslTcp)
62
90
  sock.sslsock = ssl
63
91
  sock.sslctx = self.sslctx
92
+
64
93
  return sock
65
94
 
66
95
  rescue ::OpenSSL::SSL::SSLError
@@ -190,6 +190,12 @@ class SwitchBoard
190
190
  def flush_routes
191
191
  _init
192
192
 
193
+ # Remove each of the individual routes so the comms don't think they're
194
+ # still routing after a flush.
195
+ self.routes.each { |r|
196
+ r.comm.routes.delete("#{r.subnet}/#{r.netmask}")
197
+ }
198
+ # Re-initialize to an empty array
193
199
  self.routes = Array.new
194
200
  end
195
201
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: librex
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.29
5
+ version: 0.0.30
6
6
  platform: ruby
7
7
  authors:
8
8
  - Metasploit Development Team
@@ -11,11 +11,11 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-04-19 00:00:00 -05:00
14
+ date: 2011-05-02 00:00:00 -05:00
15
15
  default_executable:
16
16
  dependencies: []
17
17
 
18
- description: Rex provides a variety of classes useful for security testing and exploit development. Based on SVN Revision 12371
18
+ description: Rex provides a variety of classes useful for security testing and exploit development. Based on SVN Revision 12516
19
19
  email:
20
20
  - hdm@metasploit.com
21
21
  - jacob.hammack@hammackj.com
@@ -149,6 +149,7 @@ files:
149
149
  - lib/rex/ole/substorage.rb
150
150
  - lib/rex/ole/util.rb
151
151
  - lib/rex/ole.rb
152
+ - lib/rex/parser/apple_backup_manifestdb.rb
152
153
  - lib/rex/parser/arguments.rb
153
154
  - lib/rex/parser/arguments.rb.ut.rb
154
155
  - lib/rex/parser/ini.rb
@@ -236,6 +237,7 @@ files:
236
237
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_user32.rb
237
238
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ws2_32.rb
238
239
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb
240
+ - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb.ut.rb
239
241
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb
240
242
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb
241
243
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb