librex 0.0.1 → 0.0.3

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 (53) hide show
  1. data/README +4 -0
  2. data/lib/rex/exploitation/cmdstager.rb +9 -133
  3. data/lib/rex/exploitation/cmdstager/base.rb +170 -0
  4. data/lib/rex/exploitation/cmdstager/debug_asm.rb +142 -0
  5. data/lib/rex/exploitation/cmdstager/debug_write.rb +136 -0
  6. data/lib/rex/exploitation/cmdstager/tftp.rb +63 -0
  7. data/lib/rex/exploitation/cmdstager/vbs.rb +128 -0
  8. data/lib/rex/io/stream.rb +2 -2
  9. data/lib/rex/io/stream_server.rb +1 -1
  10. data/lib/rex/job_container.rb +7 -6
  11. data/lib/rex/mime/header.rb +12 -10
  12. data/lib/rex/mime/message.rb +57 -26
  13. data/lib/rex/ole/directory.rb +5 -4
  14. data/lib/rex/ole/samples/create_ole.rb +0 -0
  15. data/lib/rex/ole/samples/dir.rb +0 -0
  16. data/lib/rex/ole/samples/dump_stream.rb +1 -1
  17. data/lib/rex/ole/samples/ole_info.rb +0 -0
  18. data/lib/rex/parser/nexpose_xml.rb +131 -0
  19. data/lib/rex/parser/nmap_xml.rb +1 -0
  20. data/lib/rex/peparsey/pe.rb +21 -3
  21. data/lib/rex/post/meterpreter/client.rb +6 -1
  22. data/lib/rex/post/meterpreter/client_core.rb +2 -2
  23. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +19 -18
  24. data/lib/rex/post/meterpreter/packet.rb +68 -0
  25. data/lib/rex/post/meterpreter/packet_dispatcher.rb +2 -2
  26. data/lib/rex/post/meterpreter/packet_response_waiter.rb +5 -5
  27. data/lib/rex/post/meterpreter/ui/console.rb +2 -0
  28. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +5 -2
  29. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +2 -2
  30. data/lib/rex/proto/dcerpc/client.rb.ut.rb +0 -0
  31. data/lib/rex/proto/http/client.rb +8 -3
  32. data/lib/rex/proto/http/packet.rb +11 -1
  33. data/lib/rex/proto/smb/client.rb +1 -1
  34. data/lib/rex/proto/smb/utils.rb +72 -24
  35. data/lib/rex/proto/tftp.rb +3 -0
  36. data/lib/rex/proto/tftp/constants.rb +37 -0
  37. data/lib/rex/proto/tftp/server.rb +249 -0
  38. data/lib/rex/proto/tftp/server.rb.ut.rb +28 -0
  39. data/lib/rex/script/meterpreter.rb +6 -0
  40. data/lib/rex/services/local_relay.rb +2 -2
  41. data/lib/rex/socket/ip.rb +9 -8
  42. data/lib/rex/socket/range_walker.rb +43 -5
  43. data/lib/rex/socket/udp.rb +11 -4
  44. data/lib/rex/text.rb +42 -19
  45. data/lib/rex/ui/interactive.rb +24 -22
  46. data/lib/rex/ui/text/irb_shell.rb +4 -2
  47. data/lib/rex/ui/text/output/file.rb +6 -0
  48. data/lib/rex/ui/text/shell.rb +14 -18
  49. data/lib/rex/zip/samples/comment.rb +0 -0
  50. data/lib/rex/zip/samples/mkwar.rb +0 -0
  51. data/lib/rex/zip/samples/mkzip.rb +0 -0
  52. data/lib/rex/zip/samples/recursive.rb +0 -0
  53. metadata +20 -5
@@ -4,47 +4,72 @@ class Message
4
4
 
5
5
  require 'rex/mime/header'
6
6
  require 'rex/mime/part'
7
- require 'rex/text'
7
+ require 'rex/text'
8
8
 
9
9
  attr_accessor :header, :parts, :bound, :content
10
10
 
11
- def initialize
11
+ def initialize(data=nil)
12
12
  self.header = Rex::MIME::Header.new
13
13
  self.parts = []
14
14
  self.bound = "_Part_#{rand(1024)}_#{rand(0xffffffff)}_#{rand(0xffffffff)}"
15
15
  self.content = ''
16
+ if data
17
+ head,body = data.split(/\r?\n\r?\n/, 2)
18
+
19
+ self.header.parse(head)
20
+ ctype = self.header.find('Content-Type')
21
+
22
+ if ctype and ctype[1] and ctype[1] =~ /multipart\/mixed;\s*boundary=([^\s]+)/
23
+ self.bound = $1
24
+
25
+ chunks = body.to_s.split(/--#{self.bound}(--)?\r?\n/)
26
+ self.content = chunks.shift.to_s.gsub(/\s+$/, '')
27
+ self.content << "\r\n" if not self.content.empty?
28
+
29
+ chunks.each do |chunk|
30
+ break if chunk == "--"
31
+ head,body = chunk.split(/\r?\n\r?\n/, 2)
32
+ part = Rex::MIME::Part.new
33
+ part.header.parse(head)
34
+ part.content = body.gsub(/\s+$/, '')
35
+ self.parts << part
36
+ end
37
+ else
38
+ self.content = body.to_s.gsub(/\s+$/, '') + "\r\n"
39
+ end
40
+ end
16
41
  end
17
42
 
18
43
  def to
19
44
  (self.header.find('To') || [nil, nil])[1]
20
45
  end
21
-
46
+
22
47
  def to=(val)
23
48
  self.header.set("To", val)
24
49
  end
25
-
50
+
26
51
  def from=(val)
27
- self.header.set("From", val)
52
+ self.header.set("From", val)
28
53
  end
29
-
54
+
30
55
  def from
31
56
  (self.header.find('From') || [nil, nil])[1]
32
57
  end
33
-
58
+
34
59
  def subject=(val)
35
- self.header.set("Subject", val)
60
+ self.header.set("Subject", val)
36
61
  end
37
-
62
+
38
63
  def subject
39
64
  (self.header.find('Subject') || [nil, nil])[1]
40
65
  end
41
-
66
+
42
67
  def mime_defaults
43
68
  self.header.set("MIME-Version", "1.0")
44
69
  self.header.set("Content-Type", "multipart/mixed; boundary=\"#{self.bound}\"")
45
70
  self.header.set("Subject", '') # placeholder
46
71
  self.header.set("Date", Time.now.strftime("%a,%e %b %Y %H:%M:%S %z"))
47
- self.header.set("Message-ID",
72
+ self.header.set("Message-ID",
48
73
  "<"+
49
74
  Rex::Text.rand_text_alphanumeric(rand(20)+40)+
50
75
  "@"+
@@ -55,24 +80,24 @@ class Message
55
80
  self.header.set("To", '') # placeholder
56
81
  end
57
82
 
58
-
83
+
59
84
  def add_part(data='', content_type='text/plain', transfer_encoding="8bit", content_disposition=nil)
60
85
  part = Rex::MIME::Part.new
61
86
  part.header.set("Content-Type", content_type)
62
-
87
+
63
88
  if (transfer_encoding)
64
89
  part.header.set("Content-Transfer-Encoding", transfer_encoding)
65
90
  end
66
-
91
+
67
92
  if (content_disposition)
68
93
  part.header.set("Content-Disposition", content_disposition)
69
94
  end
70
-
95
+
71
96
  part.content = data
72
97
  self.parts << part
73
98
  part
74
99
  end
75
-
100
+
76
101
  def add_part_attachment(data, name)
77
102
  self.add_part(
78
103
  Rex::Text.encode_base64(data, "\r\n"),
@@ -81,7 +106,7 @@ class Message
81
106
  "attachment; filename=\"#{name}\""
82
107
  )
83
108
  end
84
-
109
+
85
110
 
86
111
  def add_part_inline_attachment(data, name)
87
112
  self.add_part(
@@ -91,22 +116,28 @@ class Message
91
116
  "inline; filename=\"#{name}\""
92
117
  )
93
118
  end
94
-
119
+
95
120
  def to_s
96
121
  msg = self.header.to_s + "\r\n"
97
-
98
- msg << self.content + "\r\n"
99
-
122
+
123
+ if self.content and not self.content.empty?
124
+ msg << self.content + "\r\n"
125
+ end
126
+
100
127
  self.parts.each do |part|
101
128
  msg << "--" + self.bound + "\r\n"
102
- msg << part.to_s
129
+ msg << part.to_s + "\r\n"
130
+ end
131
+
132
+ if self.parts.length > 0
133
+ msg << "--" + self.bound + "--\r\n"
103
134
  end
104
135
 
105
- msg << "--" + self.bound + "--\r\n"
106
-
107
- msg
136
+ # Force CRLF for SMTP compatibility
137
+ msg.gsub("\r", '').gsub("\n", "\r\n")
108
138
  end
109
139
 
110
140
  end
111
141
  end
112
- end
142
+ end
143
+
@@ -1,6 +1,6 @@
1
1
  ##
2
- # $Id: directory.rb 8457 2010-02-11 18:36:38Z jduck $
3
- # Version: $Revision: 8457 $
2
+ # $Id: directory.rb 9287 2010-05-12 05:33:35Z jduck $
3
+ # Version: $Revision: 9287 $
4
4
  ##
5
5
 
6
6
  ##
@@ -51,7 +51,6 @@ class Directory < DirEntry
51
51
  child.sid = @num_entries
52
52
  @num_entries += 1
53
53
 
54
-
55
54
  # link item to siblings and/or parent
56
55
  if (parent._sidChild == DIR_NOSTREAM)
57
56
  parent._sidChild = child.sid
@@ -72,7 +71,9 @@ class Directory < DirEntry
72
71
  break
73
72
  end
74
73
  }
75
- raise RuntimeError, 'Unable to find a sibling to link to in the directory'
74
+ if (not sib)
75
+ raise RuntimeError, 'Unable to find a sibling to link to in the directory'
76
+ end
76
77
  end
77
78
  parent << child
78
79
  end
File without changes
File without changes
@@ -23,7 +23,7 @@ if (stg = Rex::OLE::Storage.new(document))
23
23
  data = stm.read(stm.length)
24
24
  data ||= ""
25
25
  $stderr.puts "Successfully opened the \"%s\" stream (%u bytes)" % [stream, data.length]
26
- $stdout.puts data
26
+ $stdout.print data
27
27
  stm.close
28
28
  else
29
29
  $stderr.puts "Unable to open stream: #{stream}"
File without changes
@@ -0,0 +1,131 @@
1
+ module Rex
2
+ module Parser
3
+
4
+ # XXX doesn't tie services to vulns
5
+ class NexposeXMLStreamParser
6
+
7
+ attr_accessor :callback
8
+
9
+ def initialize(callback = nil)
10
+ reset_state
11
+ self.callback = callback if callback
12
+ end
13
+
14
+ def reset_state
15
+ @state = :generic_state
16
+ @host = { "status" => nil, "endpoints" => [], "names" => [], "vulns" => {} }
17
+ @vuln = { "refs" => [] }
18
+ end
19
+
20
+ def tag_start(name, attributes)
21
+ case name
22
+ when "node"
23
+ @host["hardware-address"] = attributes["hardware-address"]
24
+ @host["addr"] = attributes["address"]
25
+ @host["status"] = attributes["status"]
26
+ when "os"
27
+ # Take only the highest certainty
28
+ if not @host["os_certainty"] or (@host["os_certainty"].to_f < attributes["certainty"].to_f)
29
+ @host["os_vendor"] = attributes["vendor"]
30
+ @host["os_family"] = attributes["family"]
31
+ @host["os_product"] = attributes["product"]
32
+ @host["arch"] = attributes["arch"]
33
+ @host["os_certainty"] = attributes["certainty"]
34
+ end
35
+ when "name"
36
+ #@host["names"].push attributes["name"]
37
+ @state = :in_name
38
+ when "endpoint"
39
+ # This is a port in NeXpose parlance
40
+ @host["endpoints"].push(attributes)
41
+ when "service"
42
+ @state = :in_service
43
+ # Store any service info with the associated port. There shouldn't
44
+ # be any collisions on attribute names here, so just merge them.
45
+ @host["endpoints"].last.merge!(attributes)
46
+ when "fingerprint"
47
+ if @state == :in_service
48
+ @host["endpoints"].last.merge!(attributes)
49
+ end
50
+ when "test"
51
+ if attributes["status"] == "vulnerable-exploited" or attributes["status"] == "vulnerable-version"
52
+ @host["vulns"][attributes["id"]] = attributes.dup
53
+ end
54
+ when "vulnerability"
55
+ @vuln.merge! attributes
56
+ when "reference"
57
+ @state = :in_reference
58
+ @vuln["refs"].push attributes
59
+ end
60
+ end
61
+
62
+ def text(str)
63
+ case @state
64
+ when :in_name
65
+ @host["names"].push str
66
+ when :in_reference
67
+ @vuln["refs"].last["value"] = str
68
+ end
69
+ end
70
+
71
+ def tag_end(name)
72
+ case name
73
+ when "node"
74
+ callback.call(:host, @host) if callback
75
+ reset_state
76
+ when "vulnerability"
77
+ callback.call(:vuln, @vuln) if callback
78
+ reset_state
79
+ when "service","reference"
80
+ @state = :generic_state
81
+ end
82
+ end
83
+
84
+ # We don't need these methods, but they're necessary to keep REXML happy
85
+ def xmldecl(version, encoding, standalone); end
86
+ def cdata; end
87
+ def comment(str); end
88
+ def instruction(name, instruction); end
89
+ def attlist; end
90
+ end
91
+ end
92
+ end
93
+
94
+ __END__
95
+
96
+ <node address="10.1.1.10" status="alive" hardware-address="0007371F3BE8">
97
+ <names>
98
+ <name>NETBIOSNAME</name>
99
+ <name>hostname.example.com</name>
100
+ </names>
101
+ <fingerprints>
102
+ <os certainty="1.00" device-class="Domain controller" vendor="Microsoft" family="Windows" product="Windows Server 2003, Standard Edition" version="SP2" arch="x86"/>
103
+ <os certainty="0.85" device-class="General" vendor="Microsoft" family="Windows" product="Windows Server 2003"/>
104
+ <os certainty="0.70" vendor="Microsoft" family="Windows" product="Windows Server 2003"/>
105
+ </fingerprints>
106
+ <software>
107
+ <fingerprint certainty="1.00" vendor="Acronis" product="Acronis&#160;True&#160;Image&#160;Echo&#160;Server" version="9.5.8163"/>
108
+ <fingerprint certainty="1.00" vendor="Acronis" product="Acronis&#160;Universal&#160;Restore for Acronis&#160;True&#160;Image&#160;Echo&#160;Server" version="9.5.8076"/>
109
+ <fingerprint certainty="1.00" software-class="Internet Client" vendor="Microsoft" family="Internet Explorer" product="Internet Explorer" version="7.0.5730.11"/>
110
+ <fingerprint certainty="1.00" software-class="Database Client" vendor="Microsoft" family="MDAC" product="MDAC" version="2.8"/>
111
+ <fingerprint certainty="1.00" software-class="Media Client" vendor="Microsoft" family="Windows Media Player" product="Windows Media Player" version="10.0.0.3997"/>
112
+ <fingerprint certainty="1.00" vendor="MySolutions NORDIC" product="NSClient++ (Win32)" version="0.3.4.0"/>
113
+ <fingerprint certainty="1.00" vendor="Symantec Corporation" product="LiveUpdate 3.1 (Symantec Corporation)" version="3.1.0.99"/>
114
+ <fingerprint certainty="1.00" vendor="Symantec Corporation" product="Symantec AntiVirus" version="10.1.5000.5"/>
115
+ </software>
116
+ <tests>
117
+ <test status="not-vulnerable" id="backdoor-ckb.cfaae1e6">
118
+
119
+ <endpoint protocol="tcp" port="139" status="open">
120
+ <services>
121
+ <service name="CIFS">
122
+ <fingerprints>
123
+ <fingerprint certainty="1.00" product="Windows Server 2003 R2 5.2"/>
124
+ </fingerprints>
125
+ <tests>
126
+ </tests>
127
+ </service>
128
+ </services>
129
+ </endpoint>
130
+ </node>
131
+
@@ -77,6 +77,7 @@ class NmapXMLStreamParser
77
77
  when "status"
78
78
  # <status> refers to the liveness of the host; values are "up" or "down"
79
79
  @host["status"] = attributes["state"]
80
+ @host["status_reason"] = attributes["reason"]
80
81
  when "port"
81
82
  @host["ports"].push(attributes)
82
83
  when "state"
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # $Id: pe.rb 7730 2009-12-07 12:56:54Z sf $
3
+ # $Id: pe.rb 9272 2010-05-10 16:18:19Z jduck $
4
4
 
5
5
  require 'rex/image_source'
6
6
  require 'rex/peparsey/exceptions'
@@ -143,7 +143,7 @@ class Pe < PeBase
143
143
  self.hdr.config = self._config_header
144
144
  self.hdr.tls = self._tls_header
145
145
  self.hdr.exceptions = self._exception_header
146
-
146
+
147
147
  # We load the exception directory last as it relies on hdr.file to be created above.
148
148
  self._exception_header = _load_exception_directory()
149
149
  end
@@ -184,5 +184,23 @@ class Pe < PeBase
184
184
  (ptr_32?) ? ("0x%.8x" % va) : ("0x%.16x" % va)
185
185
  end
186
186
 
187
- end end end
187
+ #
188
+ # Converts a file offset into a virtual address
189
+ #
190
+ def file_offset_to_va(offset)
191
+ image_base + file_offset_to_rva(offset)
192
+ end
193
+
194
+ #
195
+ # Read raw bytes from the specified offset in the underlying file
196
+ #
197
+ # NOTE: You should pass raw file offsets into this, not offsets from
198
+ # the beginning of the section. If you need to read from within a
199
+ # section, add section.file_offset prior to passing the offset in.
200
+ #
201
+ def read(offset, len)
202
+ _isource.read(offset, len)
203
+ end
204
+
188
205
 
206
+ end end end
@@ -81,13 +81,14 @@ class Client
81
81
  self.ext_aliases = ObjectAliases.new
82
82
  self.alive = true
83
83
  self.target_id = opts[:target_id]
84
+ self.capabilities= opts[:capabilities] || {}
84
85
 
85
86
  self.response_timeout = opts[:timeout] || self.class.default_timeout
86
87
  self.send_keepalives = true
87
88
 
88
89
 
89
90
  # Switch the socket to SSL mode and receive the hello if needed
90
- if not opts[:skip_ssl]
91
+ if capabilities[:ssl] and not opts[:skip_ssl]
91
92
  swap_sock_plain_to_ssl()
92
93
  end
93
94
 
@@ -325,6 +326,10 @@ class Client
325
326
  # The unique target identifier for this payload
326
327
  #
327
328
  attr_accessor :target_id
329
+ #
330
+ # The libraries available to this meterpreter server
331
+ #
332
+ attr_accessor :capabilities
328
333
 
329
334
  protected
330
335
  attr_accessor :parser, :ext_aliases # :nodoc:
@@ -89,7 +89,7 @@ class ClientCore < Extension
89
89
  }
90
90
 
91
91
  if (image != nil)
92
- request.add_tlv(TLV_TYPE_DATA, image, false, true)
92
+ request.add_tlv(TLV_TYPE_DATA, image, false, client.capabilities[:zlib])
93
93
  else
94
94
  raise RuntimeError, "Failed to serialize library #{library_path}.", caller
95
95
  end
@@ -222,7 +222,7 @@ class ClientCore < Extension
222
222
  request = Packet.create_request( 'core_migrate' )
223
223
  request.add_tlv( TLV_TYPE_MIGRATE_PID, pid )
224
224
  request.add_tlv( TLV_TYPE_MIGRATE_LEN, payload.length )
225
- request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, payload, false, true)
225
+ request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, payload, false, client.capabilities[:zlib])
226
226
  if( process['arch'] == ARCH_X86_64 )
227
227
  request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64
228
228
  else
@@ -24,10 +24,10 @@ class Priv < Extension
24
24
  #
25
25
  def initialize(client)
26
26
  super(client, 'priv')
27
-
27
+
28
28
  client.register_extension_aliases(
29
29
  [
30
- {
30
+ {
31
31
  'name' => 'priv',
32
32
  'ext' => self
33
33
  },
@@ -36,25 +36,25 @@ class Priv < Extension
36
36
  # Initialize sub-classes
37
37
  self.fs = Fs.new(client)
38
38
  end
39
-
39
+
40
40
  #
41
41
  # Attempt to elevate the meterpreter to Local SYSTEM
42
42
  #
43
43
  def getsystem( technique=0 )
44
44
  request = Packet.create_request( 'priv_elevate_getsystem' )
45
-
46
- elevator_name = Rex::Text.rand_text_alpha_lower( 6 )
47
-
45
+
46
+ elevator_name = Rex::Text.rand_text_alpha_lower( 6 )
47
+
48
48
  if( client.platform == 'x64/win64' )
49
49
  elevator_path = ::File.join( Msf::Config.install_root, "data", "meterpreter", "elevator.x64.dll" )
50
50
  else
51
51
  elevator_path = ::File.join( Msf::Config.install_root, "data", "meterpreter", "elevator.dll" )
52
52
  end
53
-
53
+
54
54
  elevator_path = ::File.expand_path( elevator_path )
55
-
55
+
56
56
  elevator_data = ""
57
-
57
+
58
58
  ::File.open( elevator_path, "rb" ) { |f|
59
59
  elevator_data += f.read( f.stat.size )
60
60
  }
@@ -63,29 +63,29 @@ class Priv < Extension
63
63
  request.add_tlv( TLV_TYPE_ELEVATE_SERVICE_NAME, elevator_name )
64
64
  request.add_tlv( TLV_TYPE_ELEVATE_SERVICE_DLL, elevator_data )
65
65
  request.add_tlv( TLV_TYPE_ELEVATE_SERVICE_LENGTH, elevator_data.length )
66
-
66
+
67
67
  # as some service routines can be slow we bump up the timeout to 90 seconds
68
68
  response = client.send_request( request, 90 )
69
-
69
+
70
70
  technique = response.get_tlv_value( TLV_TYPE_ELEVATE_TECHNIQUE )
71
-
71
+
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
75
  return [ true, technique ]
76
76
  end
77
-
77
+
78
78
  return [ false, 0 ]
79
79
  end
80
-
80
+
81
81
  #
82
82
  # Returns an array of SAM hashes from the remote machine.
83
83
  #
84
84
  def sam_hashes
85
- response = client.send_request(
86
- Packet.create_request('priv_passwd_get_sam_hashes'))
85
+ # This can take a long long time for large domain controls, bump the timeout to one hour
86
+ response = client.send_request(Packet.create_request('priv_passwd_get_sam_hashes'), 3600)
87
87
 
88
- response.get_tlv_value(TLV_TYPE_SAM_HASHES).split(/\n/).map { |hash|
88
+ response.get_tlv_value(TLV_TYPE_SAM_HASHES).split(/\n/).map { |hash|
89
89
  SamUser.new(hash)
90
90
  }
91
91
  end
@@ -101,4 +101,5 @@ protected
101
101
 
102
102
  end
103
103
 
104
- end; end; end; end; end
104
+ end; end; end; end; end
105
+