librex 0.0.29 → 0.0.30

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