librex 0.0.1 → 0.0.3

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