rex 2.0.5 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rex/exploitation/egghunter.rb +4 -6
- data/lib/rex/exploitation/powershell/psh_methods.rb +9 -0
- data/lib/rex/java/serialization.rb +2 -1
- data/lib/rex/java/serialization/builder.rb +94 -0
- data/lib/rex/java/serialization/model.rb +29 -18
- data/lib/rex/java/serialization/model/annotation.rb +2 -2
- data/lib/rex/java/serialization/model/field.rb +2 -2
- data/lib/rex/java/serialization/model/new_array.rb +8 -3
- data/lib/rex/java/serialization/model/new_class_desc.rb +3 -3
- data/lib/rex/java/serialization/model/new_enum.rb +4 -4
- data/lib/rex/java/serialization/model/new_object.rb +17 -10
- data/lib/rex/ole/direntry.rb +1 -1
- data/lib/rex/ole/samples/create_ole.rb +0 -0
- data/lib/rex/ole/samples/dir.rb +0 -0
- data/lib/rex/ole/samples/dump_stream.rb +0 -0
- data/lib/rex/ole/samples/ole_info.rb +0 -0
- data/lib/rex/parser/foundstone_nokogiri.rb +1 -1
- data/lib/rex/parser/fs/ntfs.rb +252 -0
- data/lib/rex/parser/openvas_nokogiri.rb +2 -0
- data/lib/rex/payloads/win32/kernel.rb +3 -3
- data/lib/rex/post/meterpreter/client_core.rb +172 -64
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +3 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +12 -10
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +64 -37
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +8 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +15 -3
- data/lib/rex/post/meterpreter/packet.rb +41 -38
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +7 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +17 -4
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +11 -4
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +1 -1
- data/lib/rex/proto.rb +2 -0
- data/lib/rex/proto/acpp.rb +17 -0
- data/lib/rex/proto/acpp/client.rb +29 -0
- data/lib/rex/proto/acpp/message.rb +183 -0
- data/lib/rex/proto/http/client.rb +1 -2
- data/lib/rex/proto/iax2/call.rb +22 -3
- data/lib/rex/proto/iax2/client.rb +1 -0
- data/lib/rex/proto/kerberos.rb +13 -0
- data/lib/rex/proto/kerberos/client.rb +213 -0
- data/lib/rex/proto/kerberos/credential_cache.rb +19 -0
- data/lib/rex/proto/kerberos/credential_cache/cache.rb +81 -0
- data/lib/rex/proto/kerberos/credential_cache/credential.rb +151 -0
- data/lib/rex/proto/kerberos/credential_cache/element.rb +49 -0
- data/lib/rex/proto/kerberos/credential_cache/key_block.rb +62 -0
- data/lib/rex/proto/kerberos/credential_cache/principal.rb +70 -0
- data/lib/rex/proto/kerberos/credential_cache/time.rb +69 -0
- data/lib/rex/proto/kerberos/crypto.rb +21 -0
- data/lib/rex/proto/kerberos/crypto/rc4_hmac.rb +65 -0
- data/lib/rex/proto/kerberos/crypto/rsa_md5.rb +15 -0
- data/lib/rex/proto/kerberos/model.rb +133 -0
- data/lib/rex/proto/kerberos/model/ap_req.rb +98 -0
- data/lib/rex/proto/kerberos/model/authenticator.rb +143 -0
- data/lib/rex/proto/kerberos/model/authorization_data.rb +85 -0
- data/lib/rex/proto/kerberos/model/checksum.rb +59 -0
- data/lib/rex/proto/kerberos/model/element.rb +67 -0
- data/lib/rex/proto/kerberos/model/enc_kdc_response.rb +215 -0
- data/lib/rex/proto/kerberos/model/encrypted_data.rb +171 -0
- data/lib/rex/proto/kerberos/model/encryption_key.rb +106 -0
- data/lib/rex/proto/kerberos/model/kdc_request.rb +166 -0
- data/lib/rex/proto/kerberos/model/kdc_request_body.rb +315 -0
- data/lib/rex/proto/kerberos/model/kdc_response.rb +141 -0
- data/lib/rex/proto/kerberos/model/krb_error.rb +219 -0
- data/lib/rex/proto/kerberos/model/last_request.rb +82 -0
- data/lib/rex/proto/kerberos/model/pre_auth_data.rb +104 -0
- data/lib/rex/proto/kerberos/model/pre_auth_enc_time_stamp.rb +126 -0
- data/lib/rex/proto/kerberos/model/pre_auth_pac_request.rb +81 -0
- data/lib/rex/proto/kerberos/model/principal_name.rb +116 -0
- data/lib/rex/proto/kerberos/model/ticket.rb +151 -0
- data/lib/rex/proto/kerberos/pac.rb +36 -0
- data/lib/rex/proto/kerberos/pac/client_info.rb +53 -0
- data/lib/rex/proto/kerberos/pac/element.rb +52 -0
- data/lib/rex/proto/kerberos/pac/logon_info.rb +566 -0
- data/lib/rex/proto/kerberos/pac/priv_svr_checksum.rb +29 -0
- data/lib/rex/proto/kerberos/pac/server_checksum.rb +30 -0
- data/lib/rex/proto/kerberos/pac/type.rb +121 -0
- data/lib/rex/proto/rmi.rb +7 -0
- data/lib/rex/proto/rmi/model.rb +31 -0
- data/lib/rex/proto/rmi/model/call.rb +60 -0
- data/lib/rex/proto/rmi/model/continuation.rb +76 -0
- data/lib/rex/proto/rmi/model/dgc_ack.rb +62 -0
- data/lib/rex/proto/rmi/model/element.rb +143 -0
- data/lib/rex/proto/rmi/model/output_header.rb +86 -0
- data/lib/rex/proto/rmi/model/ping.rb +41 -0
- data/lib/rex/proto/rmi/model/ping_ack.rb +41 -0
- data/lib/rex/proto/rmi/model/protocol_ack.rb +100 -0
- data/lib/rex/proto/rmi/model/return_data.rb +60 -0
- data/lib/rex/socket.rb +9 -1
- data/lib/rex/socket/tcp_server.rb +3 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +4 -4
- data/lib/rex/ui/text/output/tee.rb +2 -0
- data/lib/rex/zip/samples/comment.rb +0 -0
- data/lib/rex/zip/samples/mkwar.rb +0 -0
- data/lib/rex/zip/samples/mkzip.rb +0 -0
- data/lib/rex/zip/samples/recursive.rb +0 -0
- data/rex.gemspec +1 -1
- metadata +56 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cc2f7d9e9457482ffe5b8935f8b93c4e57560cc
|
4
|
+
data.tar.gz: b6e6ee56e59286b54a62d28540e92fa6363dd6ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17d81b1cda43811ec7acc076f4c903da5cb48316c399dd08abf2839df6e979b9de977f321e004ec1391fe86d472b450af2262f9be6a30aad8ddc30c2358a107e
|
7
|
+
data.tar.gz: f921d0e028d10c3b96eaaa65eff57a39d085dae29067d7e5b64addef567aff2043fc4079801a0cf11053abea603055a3d1ffcaeb9c3bf7788644bf44c0011d1c
|
@@ -65,12 +65,10 @@ class Egghunter
|
|
65
65
|
flippage = "\n\tor dx,0xfff"
|
66
66
|
edxdirection = "\n\tinc edx"
|
67
67
|
|
68
|
-
if searchforward
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
edxdirection = "\n\tdec edx"
|
73
|
-
end
|
68
|
+
if searchforward.to_s.downcase == 'false'
|
69
|
+
# go backwards
|
70
|
+
flippage = "\n\txor dl,dl"
|
71
|
+
edxdirection = "\n\tdec edx"
|
74
72
|
end
|
75
73
|
|
76
74
|
# other vars
|
@@ -64,6 +64,15 @@ module Powershell
|
|
64
64
|
def self.get_last_login(user)
|
65
65
|
%Q^ Get-QADComputer -ComputerRole DomainController | foreach { (Get-QADUser -Service $_.Name -SamAccountName "#{user}").LastLogon} | Measure-Latest^
|
66
66
|
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Disable SSL Certificate verification
|
70
|
+
#
|
71
|
+
# @return [String] Powershell code to disable SSL verification
|
72
|
+
# checks.
|
73
|
+
def self.ignore_ssl_certificate
|
74
|
+
'[System.Net.ServicePointManager]::ServerCertificateValidationCallback={$true};'
|
75
|
+
end
|
67
76
|
end
|
68
77
|
end
|
69
78
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
module Rex
|
4
|
+
module Java
|
5
|
+
module Serialization
|
6
|
+
# This class provides a builder to help in the construction of
|
7
|
+
# Java serialized contents.
|
8
|
+
class Builder
|
9
|
+
|
10
|
+
# Creates a Rex::Java::Serialization::Model::NewArray
|
11
|
+
#
|
12
|
+
# @param opts [Hash{Symbol => <Rex::Java::Serialization::Model::NewClassDesc, String, Array>}]
|
13
|
+
# @option opts [Rex::Java::Serialization::Model::NewClassDesc] :description
|
14
|
+
# @option opts [String] :values_type
|
15
|
+
# @option opts [Array] :values
|
16
|
+
# @return [Rex::Java::Serialization::Model::NewArray]
|
17
|
+
# @see #new_class
|
18
|
+
def new_array(opts = {})
|
19
|
+
class_desc = opts[:description] || new_class(opts)
|
20
|
+
type = opts[:values_type] || ''
|
21
|
+
values = opts[:values] || []
|
22
|
+
|
23
|
+
array = Rex::Java::Serialization::Model::NewArray.new
|
24
|
+
array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
25
|
+
array.array_description.description = class_desc
|
26
|
+
array.type = type
|
27
|
+
array.values = values
|
28
|
+
|
29
|
+
array
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates a Rex::Java::Serialization::Model::NewObject
|
33
|
+
#
|
34
|
+
# @param opts [Hash{Symbol => <Rex::Java::Serialization::Model::NewClassDesc, Array>}]
|
35
|
+
# @option opts [Rex::Java::Serialization::Model::NewClassDesc] :description
|
36
|
+
# @option opts [Array] :data
|
37
|
+
# @return [Rex::Java::Serialization::Model::NewObject]
|
38
|
+
# @see #new_class
|
39
|
+
def new_object(opts = {})
|
40
|
+
class_desc = opts[:description] || new_class(opts)
|
41
|
+
data = opts[:data] || []
|
42
|
+
|
43
|
+
object = Rex::Java::Serialization::Model::NewObject.new
|
44
|
+
object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
|
45
|
+
object.class_desc.description = class_desc
|
46
|
+
object.class_data = data
|
47
|
+
|
48
|
+
object
|
49
|
+
end
|
50
|
+
|
51
|
+
# Creates a Rex::Java::Serialization::Model::NewClassDesc
|
52
|
+
#
|
53
|
+
# @param opts [Hash{Symbol => <Rex::Java::Serialization::Model::NewClassDesc, Array>}]
|
54
|
+
# @option opts [String] :name
|
55
|
+
# @option opts [Fixnum] :serial
|
56
|
+
# @option opts [Fixnum] :flags
|
57
|
+
# @option opts [Array] :fields
|
58
|
+
# @option opts [Array] :annotations
|
59
|
+
# @option opts [Rex::Java::Serialization::Model::Element] :super_class
|
60
|
+
# @return [Rex::Java::Serialization::Model::NewClassDesc]
|
61
|
+
def new_class(opts = {})
|
62
|
+
class_name = opts[:name] || ''
|
63
|
+
serial_version = opts[:serial] || 0
|
64
|
+
flags = opts[:flags] || 2
|
65
|
+
fields = opts[:fields] || []
|
66
|
+
annotations = opts[:annotations] || [Rex::Java::Serialization::Model::NullReference.new,
|
67
|
+
Rex::Java::Serialization::Model::EndBlockData.new]
|
68
|
+
super_class = opts[:super_class] || Rex::Java::Serialization::Model::NullReference.new
|
69
|
+
|
70
|
+
class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
71
|
+
class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, class_name)
|
72
|
+
class_desc.serial_version = serial_version
|
73
|
+
class_desc.flags = flags
|
74
|
+
class_desc.fields = []
|
75
|
+
|
76
|
+
fields.each do |f|
|
77
|
+
field = Rex::Java::Serialization::Model::Field.new
|
78
|
+
field.type = f[0]
|
79
|
+
field.name = Rex::Java::Serialization::Model::Utf.new(nil, f[1])
|
80
|
+
field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, f[2]) if f[2]
|
81
|
+
class_desc.fields << field
|
82
|
+
end
|
83
|
+
|
84
|
+
class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
85
|
+
class_desc.class_annotation.contents = annotations
|
86
|
+
class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
87
|
+
class_desc.super_class.description = super_class
|
88
|
+
|
89
|
+
class_desc
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -1,20 +1,31 @@
|
|
1
1
|
# -*- coding: binary -*-
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
3
|
+
module Rex
|
4
|
+
module Java
|
5
|
+
module Serialization
|
6
|
+
module Model
|
7
|
+
|
8
|
+
autoload :Annotation, 'rex/java/serialization/model/annotation'
|
9
|
+
autoload :BlockDataLong, 'rex/java/serialization/model/block_data_long'
|
10
|
+
autoload :BlockData, 'rex/java/serialization/model/block_data'
|
11
|
+
autoload :ClassDesc, 'rex/java/serialization/model/class_desc'
|
12
|
+
autoload :Contents, 'rex/java/serialization/model/contents'
|
13
|
+
autoload :Element, 'rex/java/serialization/model/element'
|
14
|
+
autoload :EndBlockData, 'rex/java/serialization/model/end_block_data'
|
15
|
+
autoload :Field, 'rex/java/serialization/model/field'
|
16
|
+
autoload :LongUtf, 'rex/java/serialization/model/long_utf'
|
17
|
+
autoload :NewArray, 'rex/java/serialization/model/new_array'
|
18
|
+
autoload :NewClassDesc, 'rex/java/serialization/model/new_class_desc'
|
19
|
+
autoload :NewEnum, 'rex/java/serialization/model/new_enum'
|
20
|
+
autoload :NewObject, 'rex/java/serialization/model/new_object'
|
21
|
+
autoload :NullReference, 'rex/java/serialization/model/null_reference'
|
22
|
+
autoload :Reference, 'rex/java/serialization/model/reference'
|
23
|
+
autoload :Reset, 'rex/java/serialization/model/reset'
|
24
|
+
autoload :Stream, 'rex/java/serialization/model/stream'
|
25
|
+
autoload :Utf, 'rex/java/serialization/model/utf'
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -29,7 +29,7 @@ module Rex
|
|
29
29
|
loop do
|
30
30
|
content = decode_content(io, stream)
|
31
31
|
self.contents << content
|
32
|
-
return self if content.
|
32
|
+
return self if content.kind_of?(EndBlockData)
|
33
33
|
end
|
34
34
|
|
35
35
|
self
|
@@ -66,4 +66,4 @@ module Rex
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
-
end
|
69
|
+
end
|
@@ -55,7 +55,7 @@ module Rex
|
|
55
55
|
# @return [String] if serialization succeeds
|
56
56
|
# @raise [RuntimeError] if serialization doesn't succeed
|
57
57
|
def encode
|
58
|
-
unless name.
|
58
|
+
unless name.kind_of?(Rex::Java::Serialization::Model::Utf)
|
59
59
|
raise ::RuntimeError, 'Failed to serialize Field'
|
60
60
|
end
|
61
61
|
|
@@ -169,4 +169,4 @@ module Rex
|
|
169
169
|
end
|
170
170
|
end
|
171
171
|
end
|
172
|
-
end
|
172
|
+
end
|
@@ -52,7 +52,7 @@ module Rex
|
|
52
52
|
# @return [String] if serialization succeeds
|
53
53
|
# @raise [RuntimeError] if serialization doesn't succeed
|
54
54
|
def encode
|
55
|
-
unless array_description.
|
55
|
+
unless array_description.kind_of?(ClassDesc)
|
56
56
|
raise ::RuntimeError, 'Failed to serialize NewArray'
|
57
57
|
end
|
58
58
|
|
@@ -103,12 +103,17 @@ module Rex
|
|
103
103
|
raise ::RuntimeError, 'Empty NewArray description'
|
104
104
|
end
|
105
105
|
|
106
|
-
unless array_description.
|
106
|
+
unless array_description.kind_of?(ClassDesc)
|
107
107
|
raise ::RuntimeError, 'Unsupported NewArray description class'
|
108
108
|
end
|
109
109
|
|
110
110
|
desc = array_description.description
|
111
111
|
|
112
|
+
if desc.class == Reference
|
113
|
+
ref = desc.handle - BASE_WIRE_HANDLE
|
114
|
+
desc = stream.references[ref]
|
115
|
+
end
|
116
|
+
|
112
117
|
unless desc.class_name.contents[0] == '[' # Array
|
113
118
|
raise ::RuntimeError, 'Unsupported NewArray description'
|
114
119
|
end
|
@@ -222,4 +227,4 @@ module Rex
|
|
222
227
|
end
|
223
228
|
end
|
224
229
|
end
|
225
|
-
end
|
230
|
+
end
|
@@ -66,8 +66,8 @@ module Rex
|
|
66
66
|
# @return [String] if serialization succeeds
|
67
67
|
# @raise [RuntimeError] if serialization doesn't succeed
|
68
68
|
def encode
|
69
|
-
unless class_name.class == Rex::Java::Serialization::Model::Utf
|
70
|
-
class_annotation.class == Rex::Java::Serialization::Model::Annotation
|
69
|
+
unless class_name.class == Rex::Java::Serialization::Model::Utf ||
|
70
|
+
class_annotation.class == Rex::Java::Serialization::Model::Annotation ||
|
71
71
|
super_class.class == Rex::Java::Serialization::Model::ClassDesc
|
72
72
|
raise ::RuntimeError, 'Filed to serialize NewClassDesc'
|
73
73
|
end
|
@@ -152,4 +152,4 @@ module Rex
|
|
152
152
|
end
|
153
153
|
end
|
154
154
|
end
|
155
|
-
end
|
155
|
+
end
|
@@ -41,8 +41,8 @@ module Rex
|
|
41
41
|
# @return [String] if serialization succeeds
|
42
42
|
# @raise [RuntimeError] if serialization doesn't succeed
|
43
43
|
def encode
|
44
|
-
unless enum_description.
|
45
|
-
|
44
|
+
unless enum_description.kind_of?(ClassDesc) &&
|
45
|
+
constant_name.kind_of?(Utf)
|
46
46
|
raise ::RuntimeError, 'Failed to serialize EnumDescription'
|
47
47
|
end
|
48
48
|
|
@@ -68,7 +68,7 @@ module Rex
|
|
68
68
|
# @raise [RuntimeError] if deserialization doesn't succed
|
69
69
|
def decode_constant_name(io)
|
70
70
|
content = decode_content(io, stream)
|
71
|
-
raise ::RuntimeError, 'Failed to unserialize NewEnum' unless content.
|
71
|
+
raise ::RuntimeError, 'Failed to unserialize NewEnum' unless content.kind_of?(Rex::Java::Serialization::Model::Utf)
|
72
72
|
|
73
73
|
content
|
74
74
|
end
|
@@ -76,4 +76,4 @@ module Rex
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
79
|
-
end
|
79
|
+
end
|
@@ -32,9 +32,10 @@ module Rex
|
|
32
32
|
self.class_desc = ClassDesc.decode(io, stream)
|
33
33
|
stream.add_reference(self) unless stream.nil?
|
34
34
|
|
35
|
-
|
35
|
+
case class_desc.description
|
36
|
+
when NewClassDesc
|
36
37
|
self.class_data = decode_class_data(io, class_desc.description)
|
37
|
-
|
38
|
+
when Reference
|
38
39
|
ref = class_desc.description.handle - BASE_WIRE_HANDLE
|
39
40
|
self.class_data = decode_class_data(io, stream.references[ref])
|
40
41
|
end
|
@@ -47,7 +48,7 @@ module Rex
|
|
47
48
|
# @return [String] if serialization succeeds
|
48
49
|
# @raise [RuntimeError] if serialization doesn't succeed
|
49
50
|
def encode
|
50
|
-
unless class_desc.
|
51
|
+
unless class_desc.kind_of?(ClassDesc)
|
51
52
|
raise ::RuntimeError, 'Failed to serialize NewObject'
|
52
53
|
end
|
53
54
|
|
@@ -55,7 +56,7 @@ module Rex
|
|
55
56
|
encoded << class_desc.encode
|
56
57
|
|
57
58
|
class_data.each do |value|
|
58
|
-
if value.
|
59
|
+
if value.kind_of?(Array)
|
59
60
|
encoded << encode_value(value)
|
60
61
|
else
|
61
62
|
encoded << encode_content(value)
|
@@ -70,15 +71,16 @@ module Rex
|
|
70
71
|
# @return [String]
|
71
72
|
def to_s
|
72
73
|
str = ''
|
73
|
-
|
74
|
+
case class_desc.description
|
75
|
+
when NewClassDesc
|
74
76
|
str << class_desc.description.class_name.to_s
|
75
|
-
|
77
|
+
when Reference
|
76
78
|
str << (class_desc.description.handle - BASE_WIRE_HANDLE).to_s(16)
|
77
79
|
end
|
78
80
|
|
79
81
|
str << ' => { '
|
80
|
-
|
81
|
-
str <<
|
82
|
+
data_str = class_data.collect { |data| data.to_s }
|
83
|
+
str << data_str.join(', ')
|
82
84
|
str << ' }'
|
83
85
|
end
|
84
86
|
|
@@ -94,7 +96,12 @@ module Rex
|
|
94
96
|
values = []
|
95
97
|
|
96
98
|
unless my_class_desc.super_class.description.class == NullReference
|
97
|
-
|
99
|
+
if my_class_desc.super_class.description.class == Reference
|
100
|
+
ref = my_class_desc.super_class.description.handle - BASE_WIRE_HANDLE
|
101
|
+
values += decode_class_data(io, stream.references[ref])
|
102
|
+
else
|
103
|
+
values += decode_class_data(io, my_class_desc.super_class.description)
|
104
|
+
end
|
98
105
|
end
|
99
106
|
|
100
107
|
values += decode_class_fields(io, my_class_desc)
|
@@ -220,4 +227,4 @@ module Rex
|
|
220
227
|
end
|
221
228
|
end
|
222
229
|
end
|
223
|
-
end
|
230
|
+
end
|
data/lib/rex/ole/direntry.rb
CHANGED
File without changes
|
data/lib/rex/ole/samples/dir.rb
CHANGED
File without changes
|
File without changes
|
File without changes
|
@@ -293,7 +293,7 @@ module Rex
|
|
293
293
|
# XXX: Actually implement more of these
|
294
294
|
def process_service(service,banner)
|
295
295
|
meth = "process_service_#{service.gsub("-","_")}"
|
296
|
-
if self.respond_to?
|
296
|
+
if self.respond_to?(meth, true)
|
297
297
|
self.send meth, banner
|
298
298
|
else
|
299
299
|
return (first_line banner)
|
@@ -0,0 +1,252 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
module Rex
|
3
|
+
module Parser
|
4
|
+
###
|
5
|
+
#
|
6
|
+
# This class parses the contents of an NTFS partition file.
|
7
|
+
# Author : Danil Bazin <danil.bazin[at]hsc.fr> @danilbaz
|
8
|
+
#
|
9
|
+
###
|
10
|
+
class NTFS
|
11
|
+
#
|
12
|
+
# Initialize the NTFS class with an already open file handler
|
13
|
+
#
|
14
|
+
DATA_ATTRIBUTE_ID = 128
|
15
|
+
INDEX_ROOT_ID = 144
|
16
|
+
INDEX_ALLOCATION_ID = 160
|
17
|
+
def initialize(file_handler)
|
18
|
+
@file_handler = file_handler
|
19
|
+
data = @file_handler.read(4096)
|
20
|
+
# Boot sector reading
|
21
|
+
@bytes_per_sector = data[11, 2].unpack('v')[0]
|
22
|
+
@sector_per_cluster = data[13].unpack('C')[0]
|
23
|
+
@cluster_per_mft_record = data[64].unpack('c')[0]
|
24
|
+
if @cluster_per_mft_record < 0
|
25
|
+
@bytes_per_mft_record = 2**(-@cluster_per_mft_record)
|
26
|
+
@cluster_per_mft_record = @bytes_per_mft_record.to_f / @bytes_per_sector / @sector_per_cluster
|
27
|
+
else
|
28
|
+
@bytes_per_mft_record = @bytes_per_sector * @sector_per_cluster * @cluster_per_mft_record
|
29
|
+
end
|
30
|
+
@bytes_per_cluster = @sector_per_cluster * @bytes_per_sector
|
31
|
+
@mft_logical_cluster_number = data[48, 8].unpack('Q<')[0]
|
32
|
+
@mft_offset = @mft_logical_cluster_number * @sector_per_cluster * @bytes_per_sector
|
33
|
+
@file_handler.seek(@mft_offset)
|
34
|
+
@mft = @file_handler.read(@bytes_per_mft_record)
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Gather the MFT entry corresponding to his number
|
39
|
+
#
|
40
|
+
def mft_record_from_mft_num(mft_num)
|
41
|
+
mft_num_offset = mft_num * @cluster_per_mft_record
|
42
|
+
mft_data_attribute = mft_record_attribute(@mft)[DATA_ATTRIBUTE_ID]['data']
|
43
|
+
cluster_from_attribute_non_resident(mft_data_attribute, mft_num_offset, @bytes_per_mft_record)
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Get the size of the file in the $FILENAME (64) attribute
|
48
|
+
#
|
49
|
+
def real_size_from_filenameattribute(attribute)
|
50
|
+
filename_attribute = attribute
|
51
|
+
filename_attribute[48, 8].unpack('Q<')[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Gather the name of the file from the $FILENAME (64) attribute
|
56
|
+
#
|
57
|
+
def filename_from_filenameattribute(attribute)
|
58
|
+
filename_attribute = attribute
|
59
|
+
length_of_name = filename_attribute[64].ord
|
60
|
+
# uft16 *2
|
61
|
+
d = ::Encoding::Converter.new('UTF-16LE', 'UTF-8')
|
62
|
+
d.convert(filename_attribute[66, (length_of_name * 2)])
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Get the file from the MFT number
|
67
|
+
# The size must be gived because the $FILENAME attribute
|
68
|
+
# in the MFT entry does not contain it
|
69
|
+
# The file is in $DATA (128) Attribute
|
70
|
+
#
|
71
|
+
def file_content_from_mft_num(mft_num, size)
|
72
|
+
mft_record = mft_record_from_mft_num(mft_num)
|
73
|
+
attribute_list = mft_record_attribute(mft_record)
|
74
|
+
if attribute_list[DATA_ATTRIBUTE_ID]['resident']
|
75
|
+
return attribute_list[DATA_ATTRIBUTE_ID]['data']
|
76
|
+
else
|
77
|
+
data_attribute = attribute_list[DATA_ATTRIBUTE_ID]['data']
|
78
|
+
return cluster_from_attribute_non_resident(data_attribute)[0, size]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# parse one index record and return the name, MFT number and size of the file
|
84
|
+
#
|
85
|
+
def parse_index(index_entry)
|
86
|
+
res = {}
|
87
|
+
filename_size = index_entry[10, 2].unpack('v')[0]
|
88
|
+
filename_attribute = index_entry[16, filename_size]
|
89
|
+
# Should be 8 bytes but it doesn't work
|
90
|
+
# mft_offset = index_entry[0.unpack('Q<',:8])[0]
|
91
|
+
# work with 4 bytes
|
92
|
+
mft_offset = index_entry[0, 4].unpack('V')[0]
|
93
|
+
res[filename_from_filenameattribute(filename_attribute)] = {
|
94
|
+
'mft_offset' => mft_offset,
|
95
|
+
'file_size' => real_size_from_filenameattribute(filename_attribute) }
|
96
|
+
res
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# parse index_record in $INDEX_ROOT and recursively index_record in
|
101
|
+
# INDEX_ALLOCATION
|
102
|
+
#
|
103
|
+
def parse_index_list(index_record, index_allocation_attribute)
|
104
|
+
offset_index_entry_list = index_record[0, 4].unpack('V')[0]
|
105
|
+
index_size = index_record[offset_index_entry_list + 8, 2].unpack('v')[0]
|
106
|
+
index_size_in_bytes = index_size * @bytes_per_cluster
|
107
|
+
index_entry = index_record[offset_index_entry_list, index_size]
|
108
|
+
res = {}
|
109
|
+
while index_entry[12, 4].unpack('V')[0] & 2 != 2
|
110
|
+
res.update(parse_index(index_entry))
|
111
|
+
# if son
|
112
|
+
if index_entry[12, 4].unpack('V')[0] & 1 == 1
|
113
|
+
# should be 8 bytes length
|
114
|
+
vcn = index_entry[-8, 4].unpack('V')[0]
|
115
|
+
vcn_in_bytes = vcn * @bytes_per_cluster
|
116
|
+
res_son = parse_index_list(index_allocation_attribute[vcn_in_bytes + 24, index_size_in_bytes], index_allocation_attribute)
|
117
|
+
res.update(res_son)
|
118
|
+
end
|
119
|
+
offset_index_entry_list += index_size
|
120
|
+
index_size = index_record[offset_index_entry_list + 8, 2].unpack('v')[0]
|
121
|
+
index_size_in_bytes = index_size * @bytes_per_cluster
|
122
|
+
index_entry = index_record [offset_index_entry_list, index_size]
|
123
|
+
end
|
124
|
+
# if son on the last
|
125
|
+
if index_entry[12, 4].unpack('V')[0] & 1 == 1
|
126
|
+
# should be 8 bytes length
|
127
|
+
vcn = index_entry[-8, 4].unpack('V')[0]
|
128
|
+
vcn_in_bytes = vcn * @bytes_per_cluster
|
129
|
+
res_son = parse_index_list(index_allocation_attribute[vcn_in_bytes + 24, index_size_in_bytes], index_allocation_attribute)
|
130
|
+
res.update(res_son)
|
131
|
+
end
|
132
|
+
res
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# return the list of files in attribute directory and their MFT number and size
|
137
|
+
#
|
138
|
+
def index_list_from_attributes(attributes)
|
139
|
+
index_root_attribute = attributes[INDEX_ROOT_ID]
|
140
|
+
index_record = index_root_attribute[16, index_root_attribute.length - 16]
|
141
|
+
if attributes.key?(INDEX_ALLOCATION_ID)
|
142
|
+
return parse_index_list(index_record, attributes[INDEX_ALLOCATION_ID])
|
143
|
+
else
|
144
|
+
return parse_index_list(index_record, '')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def cluster_from_attribute_non_resident(attribute, cluster_num = 0, size_max = ((2**31) - 1))
|
149
|
+
lowvcn = attribute[16, 8].unpack('Q<')[0]
|
150
|
+
highvcn = attribute[24, 8].unpack('Q<')[0]
|
151
|
+
offset = attribute[32, 2].unpack('v')[0]
|
152
|
+
real_size = attribute[48, 8].unpack('Q<')[0]
|
153
|
+
attribut = ''
|
154
|
+
run_list_num = lowvcn
|
155
|
+
old_offset = 0
|
156
|
+
while run_list_num <= highvcn
|
157
|
+
first_runlist_byte = attribute[offset].ord
|
158
|
+
run_offset_size = first_runlist_byte >> 4
|
159
|
+
run_length_size = first_runlist_byte & 15
|
160
|
+
run_length = attribute[offset + 1, run_length_size]
|
161
|
+
run_length += "\x00" * (8 - run_length_size)
|
162
|
+
run_length = run_length.unpack('Q<')[0]
|
163
|
+
|
164
|
+
offset_run_offset = offset + 1 + run_length_size
|
165
|
+
run_offset = attribute[offset_run_offset, run_offset_size]
|
166
|
+
if run_offset[-1].ord & 128 == 128
|
167
|
+
run_offset += "\xFF" * (8 - run_offset_size)
|
168
|
+
else
|
169
|
+
run_offset += "\x00" * (8 - run_offset_size)
|
170
|
+
end
|
171
|
+
run_offset = run_offset.unpack('q<')[0]
|
172
|
+
#offset relative to previous offset
|
173
|
+
run_offset += old_offset
|
174
|
+
|
175
|
+
size_wanted = [run_length * @bytes_per_cluster, size_max - attribut.length].min
|
176
|
+
if cluster_num + (size_max / @bytes_per_cluster) >= run_list_num && (cluster_num < run_length + run_list_num)
|
177
|
+
run_list_offset_in_cluster = run_offset + [cluster_num - run_list_num, 0].max
|
178
|
+
run_list_offset = (run_list_offset_in_cluster) * @bytes_per_cluster
|
179
|
+
run_list_offset = run_list_offset.to_i
|
180
|
+
@file_handler.seek(run_list_offset)
|
181
|
+
|
182
|
+
data = ''
|
183
|
+
while data.length < size_wanted
|
184
|
+
data << @file_handler.read(size_wanted - data.length)
|
185
|
+
end
|
186
|
+
attribut << data
|
187
|
+
end
|
188
|
+
offset += run_offset_size + run_length_size + 1
|
189
|
+
run_list_num += run_length
|
190
|
+
old_offset = run_offset
|
191
|
+
end
|
192
|
+
attribut = attribut[0, real_size]
|
193
|
+
attribut
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# return the attribute list from the MFT record
|
198
|
+
# deal with resident and non resident attributes (but not $DATA due to performance issue)
|
199
|
+
#
|
200
|
+
def mft_record_attribute(mft_record)
|
201
|
+
attribute_list_offset = mft_record[20, 2].unpack('C')[0]
|
202
|
+
curs = attribute_list_offset
|
203
|
+
attribute_identifier = mft_record[curs, 4].unpack('V')[0]
|
204
|
+
res = {}
|
205
|
+
while attribute_identifier != 0xFFFFFFFF
|
206
|
+
# attribute_size=mft_record[curs + 4, 4].unpack('V')[0]
|
207
|
+
# should be on 4 bytes but doesnt work
|
208
|
+
attribute_size = mft_record[curs + 4, 2].unpack('v')[0]
|
209
|
+
# resident
|
210
|
+
if mft_record[curs + 8] == "\x00"
|
211
|
+
content_size = mft_record[curs + 16, 4].unpack('V')[0]
|
212
|
+
content_offset = mft_record[curs + 20, 2].unpack('v')[0]
|
213
|
+
res[attribute_identifier] = mft_record[curs + content_offset, content_size]
|
214
|
+
else
|
215
|
+
# non resident
|
216
|
+
if attribute_identifier == DATA_ATTRIBUTE_ID
|
217
|
+
res[attribute_identifier] = mft_record[curs, attribute_size]
|
218
|
+
else
|
219
|
+
res[attribute_identifier] = cluster_from_attribute_non_resident(mft_record[curs, attribute_size])
|
220
|
+
end
|
221
|
+
end
|
222
|
+
if attribute_identifier == DATA_ATTRIBUTE_ID
|
223
|
+
res[attribute_identifier] = {
|
224
|
+
'data' => res[attribute_identifier],
|
225
|
+
'resident' => mft_record[curs + 8] == "\x00" }
|
226
|
+
end
|
227
|
+
curs += attribute_size
|
228
|
+
attribute_identifier = mft_record[curs, 4].unpack('V')[0]
|
229
|
+
end
|
230
|
+
res
|
231
|
+
end
|
232
|
+
|
233
|
+
#
|
234
|
+
# return the file path in the NTFS partition
|
235
|
+
#
|
236
|
+
def file(path)
|
237
|
+
repertory = mft_record_from_mft_num(5)
|
238
|
+
index_entry = {}
|
239
|
+
path.split('\\').each do |r|
|
240
|
+
attributes = mft_record_attribute(repertory)
|
241
|
+
index = index_list_from_attributes(attributes)
|
242
|
+
unless index.key?(r)
|
243
|
+
fail ArgumentError, 'File path does not exist', caller
|
244
|
+
end
|
245
|
+
index_entry = index[r]
|
246
|
+
repertory = mft_record_from_mft_num(index_entry['mft_offset'])
|
247
|
+
end
|
248
|
+
file_content_from_mft_num(index_entry['mft_offset'], index_entry['file_size'])
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|