turborex 0.1.1
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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +38 -0
- data/README.rdoc +19 -0
- data/examples/alpc_client.rb +15 -0
- data/examples/alpc_server.rb +14 -0
- data/examples/com_client.rb +19 -0
- data/examples/com_finder.rb +39 -0
- data/examples/create_instance.rb +15 -0
- data/examples/cstruct.rb +19 -0
- data/examples/find_com_client_calls.rb +16 -0
- data/examples/find_rpc_security_callback.rb +12 -0
- data/examples/rpc_finder.rb +117 -0
- data/examples/scan_exports.rb +5 -0
- data/examples/scan_imports.rb +5 -0
- data/examples/tinysdk.rb +17 -0
- data/lib/turborex.rb +21 -0
- data/lib/turborex/cstruct.rb +565 -0
- data/lib/turborex/cstruct/struct_helper.rb +7 -0
- data/lib/turborex/exception.rb +65 -0
- data/lib/turborex/fuzzer.rb +204 -0
- data/lib/turborex/fuzzer/containers.rb +115 -0
- data/lib/turborex/fuzzer/coverage.rb +67 -0
- data/lib/turborex/fuzzer/mutators.rb +25 -0
- data/lib/turborex/fuzzer/seed.rb +30 -0
- data/lib/turborex/monkey.rb +11 -0
- data/lib/turborex/msrpc.rb +14 -0
- data/lib/turborex/msrpc/decompiler.rb +244 -0
- data/lib/turborex/msrpc/midl.rb +747 -0
- data/lib/turborex/msrpc/ndrtype.rb +167 -0
- data/lib/turborex/msrpc/rpcbase.rb +777 -0
- data/lib/turborex/msrpc/rpcfinder.rb +1426 -0
- data/lib/turborex/msrpc/utils.rb +70 -0
- data/lib/turborex/pefile.rb +8 -0
- data/lib/turborex/pefile/pe.rb +61 -0
- data/lib/turborex/pefile/scanner.rb +82 -0
- data/lib/turborex/utils.rb +321 -0
- data/lib/turborex/windows.rb +402 -0
- data/lib/turborex/windows/alpc.rb +844 -0
- data/lib/turborex/windows/com.rb +266 -0
- data/lib/turborex/windows/com/client.rb +84 -0
- data/lib/turborex/windows/com/com_finder.rb +330 -0
- data/lib/turborex/windows/com/com_registry.rb +100 -0
- data/lib/turborex/windows/com/interface.rb +522 -0
- data/lib/turborex/windows/com/utils.rb +210 -0
- data/lib/turborex/windows/constants.rb +82 -0
- data/lib/turborex/windows/process.rb +56 -0
- data/lib/turborex/windows/security.rb +12 -0
- data/lib/turborex/windows/security/ace.rb +76 -0
- data/lib/turborex/windows/security/acl.rb +25 -0
- data/lib/turborex/windows/security/security_descriptor.rb +118 -0
- data/lib/turborex/windows/tinysdk.rb +89 -0
- data/lib/turborex/windows/utils.rb +138 -0
- data/resources/headers/alpc/ntdef.h +72 -0
- data/resources/headers/alpc/ntlpcapi.h +1014 -0
- data/resources/headers/rpc/common.h +162 -0
- data/resources/headers/rpc/guiddef.h +191 -0
- data/resources/headers/rpc/internal_ndrtypes.h +262 -0
- data/resources/headers/rpc/rpc.h +10 -0
- data/resources/headers/rpc/rpcdce.h +266 -0
- data/resources/headers/rpc/rpcdcep.h +187 -0
- data/resources/headers/rpc/rpcndr.h +39 -0
- data/resources/headers/rpc/v4_x64/rpcinternals.h +154 -0
- data/resources/headers/rpc/wintype.h +517 -0
- data/resources/headers/tinysdk/tinysdk.h +5 -0
- data/resources/headers/tinysdk/tinysdk/comdef.h +645 -0
- data/resources/headers/tinysdk/tinysdk/dbghelp.h +118 -0
- data/resources/headers/tinysdk/tinysdk/guiddef.h +194 -0
- data/resources/headers/tinysdk/tinysdk/memoryapi.h +12 -0
- data/resources/headers/tinysdk/tinysdk/poppack.h +12 -0
- data/resources/headers/tinysdk/tinysdk/pshpack4.h +13 -0
- data/resources/headers/tinysdk/tinysdk/winnt.h +1059 -0
- data/resources/headers/tinysdk/tinysdk/wintype.h +326 -0
- metadata +290 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module TurboRex
|
2
|
+
module Exception
|
3
|
+
|
4
|
+
module ALPC
|
5
|
+
include Exception
|
6
|
+
|
7
|
+
class BufferTooSmall < RuntimeError
|
8
|
+
def to_s
|
9
|
+
"The length of Buffer is too small."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TooManyRetries < RuntimeError
|
14
|
+
def to_s
|
15
|
+
"Too many retries."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class UnknownPayloadType < RuntimeError
|
20
|
+
def to_s
|
21
|
+
"The payload type is invalid."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ReplyMessageMismatch < RuntimeError
|
26
|
+
def to_s
|
27
|
+
"An attempt was made to reply to an LPC message, but the thread specified by the client ID in the message was not waiting on that message."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class UnableToAcceptConnection < RuntimeError
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module MSRPC
|
37
|
+
class InvalidParamDescriptor < StandardError
|
38
|
+
end
|
39
|
+
|
40
|
+
class InvalidTypeFormatString < StandardError
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class UnknownSymbolName < StandardError
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class UnknownError < StandardError
|
50
|
+
def to_s
|
51
|
+
"An unknown error occurred."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class NotNTSuccess < StandardError
|
56
|
+
def initialize(ntstatus='')
|
57
|
+
@message = "The return value isn't one of NT_SUCCESS: #{ntstatus}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
@message
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'turborex/windows/com'
|
2
|
+
require 'turborex/fuzzer/containers'
|
3
|
+
require 'turborex/fuzzer/mutators'
|
4
|
+
require 'turborex/fuzzer/coverage'
|
5
|
+
require 'turborex/fuzzer/seed'
|
6
|
+
|
7
|
+
module TurboRex
|
8
|
+
module Fuzzer
|
9
|
+
class InputBase
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class FuzzerBase
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class COMFuzzer < FuzzerBase
|
18
|
+
class Config
|
19
|
+
attr_reader :target
|
20
|
+
|
21
|
+
def new_target(&block)
|
22
|
+
@target = Docile.dsl_eval(TargetBuilder.new, &block).build
|
23
|
+
end
|
24
|
+
|
25
|
+
def build
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Target = Struct.new(:clsid, :interface, :method, :params, :context)
|
31
|
+
Parameter = Struct.new(:index, :container, :mutator, :fixed, :seed, :depends_on, :relationship)
|
32
|
+
|
33
|
+
class ParamBuilder
|
34
|
+
def initialize(index, args)
|
35
|
+
@args = args
|
36
|
+
@struct = Parameter.new
|
37
|
+
@struct.index = index
|
38
|
+
end
|
39
|
+
|
40
|
+
def container(c)
|
41
|
+
@struct.container = c
|
42
|
+
end
|
43
|
+
|
44
|
+
def seed(s, opts = {})
|
45
|
+
|
46
|
+
if s.is_a?(Array)
|
47
|
+
elsif s.is_a?(TurboRex::Fuzzer::Seed)
|
48
|
+
s = [s]
|
49
|
+
else
|
50
|
+
raise "Invalid seed type: #{s.class}"
|
51
|
+
end
|
52
|
+
|
53
|
+
@struct.seed = s
|
54
|
+
|
55
|
+
if opts[:depends_on] && opts[:relationship]
|
56
|
+
depends_arg = @args.find {|a| a.name == opts[:depends_on].to_s}
|
57
|
+
unless depends_arg
|
58
|
+
raise "No such parameter: #{opts[:depends_on]}"
|
59
|
+
end
|
60
|
+
|
61
|
+
@struct.depends_on = opts[:depends_on]
|
62
|
+
@struct.relationship = opts[:relationship]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def mutator(m)
|
67
|
+
@struct.mutator = m
|
68
|
+
end
|
69
|
+
|
70
|
+
def fixed(value)
|
71
|
+
@struct.fixed = value
|
72
|
+
end
|
73
|
+
|
74
|
+
def build
|
75
|
+
@struct
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class TargetBuilder
|
80
|
+
def initialize
|
81
|
+
@params = []
|
82
|
+
end
|
83
|
+
|
84
|
+
def interface(iface)
|
85
|
+
@interface = iface
|
86
|
+
end
|
87
|
+
|
88
|
+
def clsid(clsid)
|
89
|
+
@clsid = clsid
|
90
|
+
end
|
91
|
+
|
92
|
+
def context(context)
|
93
|
+
@context = context
|
94
|
+
end
|
95
|
+
|
96
|
+
def method(name)
|
97
|
+
method = @interface.methods.find {|m| m.name == name.to_s}
|
98
|
+
raise "No such method #{name}" unless method
|
99
|
+
|
100
|
+
@method = method
|
101
|
+
end
|
102
|
+
|
103
|
+
def build
|
104
|
+
Target.new(@clsid, @interface, @method, @params, @context)
|
105
|
+
end
|
106
|
+
|
107
|
+
def method_missing(m, *args, &block)
|
108
|
+
if m.to_s.start_with?('param_')
|
109
|
+
name = m.to_s.split('param_')[-1]
|
110
|
+
|
111
|
+
index = @method.type.args.index {|a| a.name == name}
|
112
|
+
raise "No such parameter #{name}" unless index
|
113
|
+
arg = @method.type.args[index]
|
114
|
+
raise "The THIS pointer can't be specified." if index == 0
|
115
|
+
@params[index-1] = Docile.dsl_eval(ParamBuilder.new(index-1, @method.type.args), &block).build
|
116
|
+
else
|
117
|
+
super(m, *args, &block)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class Input < InputBase
|
123
|
+
def initialize(config)
|
124
|
+
configure = config.fuzzer_configure
|
125
|
+
target = configure.target
|
126
|
+
@clsid = target.clsid
|
127
|
+
@interface = target.interface
|
128
|
+
@method = target.method
|
129
|
+
@method_name = @method.name.to_sym
|
130
|
+
|
131
|
+
@client = TurboRex::Windows::COM::Client.new(@clsid)
|
132
|
+
@client.create_instance cls_context: target.context, interface: @interface
|
133
|
+
end
|
134
|
+
|
135
|
+
def feed(*args)
|
136
|
+
#raw_args = args.map {|a| a.buf}
|
137
|
+
#feed_raw(*raw_args)
|
138
|
+
@interface.send(@method_name, *args)
|
139
|
+
end
|
140
|
+
|
141
|
+
# def feed_raw(*args)
|
142
|
+
# @interface.send(@method_name, *args)
|
143
|
+
# end
|
144
|
+
end
|
145
|
+
|
146
|
+
attr_reader :input
|
147
|
+
attr_reader :config
|
148
|
+
|
149
|
+
def initialize(config)
|
150
|
+
@config = config
|
151
|
+
@input = Input.new(config)
|
152
|
+
@growth_medium = []
|
153
|
+
|
154
|
+
params = config.fuzzer_configure.target.params
|
155
|
+
params.each do |p|
|
156
|
+
if p.fixed
|
157
|
+
p.container.fixed = p.fixed
|
158
|
+
end
|
159
|
+
|
160
|
+
TurboRex::Fuzzer::SeedGroup.new()
|
161
|
+
@growth_medium << p.container
|
162
|
+
end
|
163
|
+
|
164
|
+
params.map {|p| p.seed }
|
165
|
+
end
|
166
|
+
|
167
|
+
def generate
|
168
|
+
@growth_medium.map {|c| c.padding }
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
class Config
|
174
|
+
attr_reader :mechanism
|
175
|
+
attr_reader :fuzzer_configure
|
176
|
+
|
177
|
+
def mechanism=(m)
|
178
|
+
raise "Should be one of these values: 'rpc', 'com'" unless [:com, :rpc].include?(m.to_sym)
|
179
|
+
@mechanism = m
|
180
|
+
end
|
181
|
+
|
182
|
+
def configure(&block)
|
183
|
+
case mechanism.to_sym
|
184
|
+
when :rpc
|
185
|
+
raise NotImplementedError
|
186
|
+
when :com
|
187
|
+
@fuzzer_configure = Docile.dsl_eval(COMFuzzer::Config.new, &block).build
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def self.create_fuzzer(&block)
|
193
|
+
config = Config.new
|
194
|
+
yield(config)
|
195
|
+
|
196
|
+
case config.mechanism.to_sym
|
197
|
+
when :com
|
198
|
+
COMFuzzer.new(config)
|
199
|
+
when :rpc
|
200
|
+
#RPCFuzzer.new(config)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'turborex/windows'
|
2
|
+
|
3
|
+
module TurboRex
|
4
|
+
module Fuzzer
|
5
|
+
module Container
|
6
|
+
class ContainerBase
|
7
|
+
attr_reader :buf
|
8
|
+
|
9
|
+
def fixed=(v)
|
10
|
+
@fixed = true
|
11
|
+
set_data v
|
12
|
+
end
|
13
|
+
|
14
|
+
def mutate(mutator)
|
15
|
+
return @buf if @fixed
|
16
|
+
set_data mutator.mutate(@buf)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class BooleanContainer
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class ByteContainer
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class SmallContainer
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class ShortContainer
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class LongContainer
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class HyperContainer
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class FloatContainer
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class DoubleContainer
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
class CharContainer
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class WchartContainer
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class OLESTRContainer < ContainerBase
|
61
|
+
def set_data(data)
|
62
|
+
wchar = TurboRex::Windows::Utils.multibyte_to_widechar(data)
|
63
|
+
@buf = TurboRex::Windows::Win32API.alloc_c_ary('WCHAR', @length / 2)
|
64
|
+
@buf.str = wchar
|
65
|
+
@buf
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class BSTRContainer
|
70
|
+
def set_data(data)
|
71
|
+
if data.is_a? OLESTRContainer
|
72
|
+
|
73
|
+
else
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class FixedSizeBufferContainer < ContainerBase
|
80
|
+
def initialize(size, opts = {})
|
81
|
+
@size = size
|
82
|
+
@offset = @opts[:offset]
|
83
|
+
@buf = TurboRex::Windows::Win32API.alloc_c_ary('BYTE', @size)
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_data(data)
|
87
|
+
@offset ? @buf.str[@offset] = data : @buf.str = data
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class VariantSizeBufferContainer < ContainerBase
|
92
|
+
def set_data(data)
|
93
|
+
@buf = TurboRex::Windows::Win32API.alloc_c_ary('BYTE', data.bytesize)
|
94
|
+
@buf.str = data
|
95
|
+
@buf
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class StructureContainer < ContainerBase
|
100
|
+
def initialize(name, typedef=nil, opts = {})
|
101
|
+
if typedef
|
102
|
+
TurboRex::Windows::Win32API.parse_c(typedef)
|
103
|
+
end
|
104
|
+
|
105
|
+
@buf = TurboRex::Windows::Win32API.alloc_c_struct(name)
|
106
|
+
@member = opts[:member]
|
107
|
+
end
|
108
|
+
|
109
|
+
def set_data(data)
|
110
|
+
@member ? @buf.send("#{@member}=", data) : @buf.str = data
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module TurboRex
|
2
|
+
module Fuzzer
|
3
|
+
class CoverageClient
|
4
|
+
def initialize(mapping_name, buf_size=65536)
|
5
|
+
setting_mapping(mapping_name, buf_size)
|
6
|
+
@virgin_bits = [0xFF] * buf_size
|
7
|
+
@view_size = buf_size
|
8
|
+
@bitmap_size = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def trace_bits
|
12
|
+
page = [0].pack('C')*@view_size
|
13
|
+
return if TurboRex::Windows::Win32API.readprocessmemory(-1, @buf, page, @view_size, 0) == 0
|
14
|
+
page
|
15
|
+
end
|
16
|
+
|
17
|
+
# def has_new_bits?(trace_bits=trace_bits, virgin_bits=@virgin_bits)
|
18
|
+
# ret = false
|
19
|
+
# trace_bits.bytes.to_a.each do |b, i|
|
20
|
+
# virgin_bit = virgin_bits[i]
|
21
|
+
# unless (b & virgin_bit).zero?
|
22
|
+
# unless ret
|
23
|
+
# if virgin_bit == 0xFF
|
24
|
+
# ret = true
|
25
|
+
# @bitmap_size += 1
|
26
|
+
# else
|
27
|
+
# ret = :new_hit
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
|
31
|
+
# virgin_byte = virgin_byte & ~b
|
32
|
+
# virgin_bits[i] = virgin_bit
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
|
36
|
+
# ret
|
37
|
+
# end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def setting_mapping(mapping_name, buf_size)
|
42
|
+
@mapping_name = mapping_name
|
43
|
+
|
44
|
+
@hmap = TurboRex::Windows::Win32API.openfilemappinga(
|
45
|
+
TurboRex::Windows::Win32API::FILE_MAP_ALL_ACCESS,
|
46
|
+
false,
|
47
|
+
mapping_name
|
48
|
+
)
|
49
|
+
|
50
|
+
raise "Error opening file mapping" unless @hmap
|
51
|
+
|
52
|
+
@buf = TurboRex::Windows::Win32API.mapviewoffile(
|
53
|
+
@hmap,
|
54
|
+
TurboRex::Windows::Win32API::FILE_MAP_ALL_ACCESS,
|
55
|
+
0,
|
56
|
+
0,
|
57
|
+
buf_size
|
58
|
+
)
|
59
|
+
|
60
|
+
unless @buf
|
61
|
+
TurboRex::Windows::Win32API.closehandle(@hmap)
|
62
|
+
raise "Error mapping view of file"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|