librex 0.0.12 → 0.0.13
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.
- data/README.markdown +1 -1
- data/Rakefile +1 -1
- data/lib/rex/io/stream.rb +1 -1
- data/lib/rex/parser/nmap_xml.rb +4 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun.rb.ts.rb +6 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb.ut.rb +31 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +47 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb.ut.rb +36 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/{model.rb → dll.rb} +4 -226
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +100 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb +42 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +148 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb +127 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +2 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +3 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +75 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb.ut.rb +103 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +44 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +2 -2
- data/lib/rex/proto/dhcp/server.rb +7 -6
- data/lib/rex/proto/ntlm/utils.rb +505 -100
- data/lib/rex/proto/rfb/cipher.rb +6 -0
- data/lib/rex/proto/smb/client.rb +40 -332
- data/lib/rex/proto/smb/simpleclient.rb +3 -1
- data/lib/rex/proto/smb/utils.rb +0 -4
- metadata +14 -4
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..','..','..','..','..', 'lib'))
|
4
|
+
|
5
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_function'
|
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 DLLFunction::UnitTest < Test::Unit::TestCase
|
15
|
+
|
16
|
+
VALID_RETURN_TYPE = 'DWORD'
|
17
|
+
NON_RETURN_DATATYPE = 'INVALID_RETURN_TYPE'
|
18
|
+
|
19
|
+
VALID_DIRECTION = 'out'
|
20
|
+
UNKNOWN_DIRECTION = 'unknown'
|
21
|
+
|
22
|
+
VALID_DATATYPE = 'PBLOB'
|
23
|
+
UNKNOWN_DATATYPE = 'UNKNOWN_DATATYPE'
|
24
|
+
|
25
|
+
def test_initialize
|
26
|
+
# TODO: haven't gotten around to writing this yet. Feel free to
|
27
|
+
# skip("incomplete test coverage")
|
28
|
+
#
|
29
|
+
# assert_nothing_raised("valid initialization should not raise") do
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# assert_raised(ArgumentError, "check_type_exists should raise ArgumentError on unknown datatypes") do
|
33
|
+
# end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# Copyright (c) 2010, patrickHVE@googlemail.com
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
# * Redistributions of source code must retain the above copyright
|
7
|
+
# notice, this list of conditions and the following disclaimer.
|
8
|
+
# * Redistributions in binary form must reproduce the above copyright
|
9
|
+
# notice, this list of conditions and the following disclaimer in the
|
10
|
+
# documentation and/or other materials provided with the distribution.
|
11
|
+
# * The names of the author may not be used to endorse or promote products
|
12
|
+
# derived from this software without specific prior written permission.
|
13
|
+
#
|
14
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
15
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
16
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
# DISCLAIMED. IN NO EVENT SHALL patrickHVE@googlemail.com BE LIABLE FOR ANY
|
18
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
19
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
20
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
21
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
22
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
23
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
|
+
|
25
|
+
module Rex
|
26
|
+
module Post
|
27
|
+
module Meterpreter
|
28
|
+
module Extensions
|
29
|
+
module Stdapi
|
30
|
+
module Railgun
|
31
|
+
|
32
|
+
#
|
33
|
+
# shared functions
|
34
|
+
#
|
35
|
+
#
|
36
|
+
module DLLHelper
|
37
|
+
|
38
|
+
# converts ruby string to zero-terminated ASCII string
|
39
|
+
def str_to_ascii_z(str)
|
40
|
+
return str+"\x00"
|
41
|
+
end
|
42
|
+
|
43
|
+
# converts 0-terminated ASCII string to ruby string
|
44
|
+
def asciiz_to_str(asciiz)
|
45
|
+
zero_byte_idx = asciiz.index("\x00")
|
46
|
+
if zero_byte_idx != nil
|
47
|
+
return asciiz[0, zero_byte_idx]
|
48
|
+
else
|
49
|
+
return asciiz
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# converts ruby string to zero-terminated WCHAR string
|
54
|
+
def str_to_uni_z(str)
|
55
|
+
enc = str.unpack("C*").pack("v*")
|
56
|
+
enc += "\x00\x00"
|
57
|
+
return enc
|
58
|
+
end
|
59
|
+
|
60
|
+
# converts 0-terminated UTF16 to ruby string
|
61
|
+
def uniz_to_str(uniz)
|
62
|
+
uniz.unpack("v*").pack("C*").unpack("A*")[0]
|
63
|
+
end
|
64
|
+
|
65
|
+
# parses a number param and returns the value
|
66
|
+
# raises an exception if the param cannot be converted to a number
|
67
|
+
# examples:
|
68
|
+
# nil => 0
|
69
|
+
# 3 => 3
|
70
|
+
# "MB_OK" => 0
|
71
|
+
# "SOME_CONSTANT | OTHER_CONSTANT" => 17
|
72
|
+
# "tuna" => !!!!!!!!!!Exception
|
73
|
+
#
|
74
|
+
# Parameter "win_consts" is a WinConstantManager
|
75
|
+
def param_to_number(v, win_consts = @win_consts)
|
76
|
+
if v.class == NilClass then
|
77
|
+
return 0
|
78
|
+
elsif v.class == Fixnum then
|
79
|
+
return v # ok, it's already a number
|
80
|
+
elsif v.class == Bignum then
|
81
|
+
return v # ok, it's already a number
|
82
|
+
elsif v.class == String then
|
83
|
+
dw = win_consts.parse(v) # might raise an exception
|
84
|
+
if dw != nil
|
85
|
+
return dw
|
86
|
+
else
|
87
|
+
raise ArgumentError, "Param #{v} (class #{v.class}) cannot be converted to a number. It's a string but matches no constants I know."
|
88
|
+
end
|
89
|
+
else
|
90
|
+
raise "Param #{v} (class #{v.class}) should be a number but isn't"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# assembles the buffers "in" and "inout"
|
95
|
+
def assemble_buffer(direction, function, args)
|
96
|
+
layout = {} # paramName => BufferItem
|
97
|
+
blob = ""
|
98
|
+
#puts " building buffer: #{direction}"
|
99
|
+
function.params.each_with_index do |param_desc, param_idx|
|
100
|
+
#puts " processing #{param_desc[0]} #{param_desc[1]} #{param_desc[2]}"
|
101
|
+
# we care only about inout buffers
|
102
|
+
if param_desc[2] == direction
|
103
|
+
buffer = nil
|
104
|
+
# Special case:
|
105
|
+
# The user can choose to supply a Null pointer instead of a buffer
|
106
|
+
# in this case we don't need space in any heap buffer
|
107
|
+
if param_desc[0][0,1] == 'P' # type is a pointer
|
108
|
+
if args[param_idx] == nil
|
109
|
+
next
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
case param_desc[0] # required argument type
|
114
|
+
when "PDWORD"
|
115
|
+
dw = param_to_number(args[param_idx])
|
116
|
+
buffer = [dw].pack('V')
|
117
|
+
when "PWCHAR"
|
118
|
+
raise "param #{param_desc[1]}: string expected" unless args[param_idx].class == String
|
119
|
+
buffer = str_to_uni_z(args[param_idx])
|
120
|
+
when "PCHAR"
|
121
|
+
raise "param #{param_desc[1]}: string expected" unless args[param_idx].class == String
|
122
|
+
buffer = str_to_ascii_z(args[param_idx])
|
123
|
+
when "PBLOB"
|
124
|
+
raise "param #{param_desc[1]}: please supply your BLOB as string!" unless args[param_idx].class == String
|
125
|
+
buffer = args[param_idx]
|
126
|
+
# other types (non-pointers) don't reference buffers
|
127
|
+
# and don't need any treatment here
|
128
|
+
end
|
129
|
+
|
130
|
+
if buffer != nil
|
131
|
+
#puts " adding #{buffer.length} bytes to heap blob"
|
132
|
+
layout[param_desc[1]] = BufferItem.new(param_idx, blob.length, buffer.length, param_desc[0])
|
133
|
+
blob += buffer
|
134
|
+
# sf: force 8 byte alignment to satisfy x64, wont matter on x86.
|
135
|
+
while( blob.length % 8 != 0 )
|
136
|
+
blob += "\x00"
|
137
|
+
end
|
138
|
+
#puts " heap blob size now #{blob.length}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
#puts " built buffer: #{direction}"
|
143
|
+
return [layout, blob]
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end; end; end; end; end; end;
|
@@ -0,0 +1,127 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..','..','..','..','..', 'lib'))
|
4
|
+
|
5
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper'
|
6
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager'
|
7
|
+
require 'rex/text'
|
8
|
+
require 'test/unit'
|
9
|
+
|
10
|
+
module Rex
|
11
|
+
module Post
|
12
|
+
module Meterpreter
|
13
|
+
module Extensions
|
14
|
+
module Stdapi
|
15
|
+
module Railgun
|
16
|
+
class DLLHelper::UnitTest < Test::Unit::TestCase
|
17
|
+
|
18
|
+
###
|
19
|
+
# We will test against this instance of DLLHelper (a module)
|
20
|
+
#
|
21
|
+
# We freeze the instance and make the reference constant to ensure consistency
|
22
|
+
##
|
23
|
+
TEST_DLL_HELPER = Object.new.extend(DLLHelper).freeze
|
24
|
+
|
25
|
+
def test_str_to_ascii_z
|
26
|
+
original_string = '23 Skidoo!'
|
27
|
+
|
28
|
+
# converts ruby string to zero-terminated ASCII string
|
29
|
+
zero_terminated_ascii_attempt = TEST_DLL_HELPER.str_to_ascii_z(original_string)
|
30
|
+
|
31
|
+
assert(zero_terminated_ascii_attempt.end_with?("\x00"),
|
32
|
+
"str_to_ascii_z should result in a 0 terminated string")
|
33
|
+
|
34
|
+
assert(zero_terminated_ascii_attempt.start_with?(original_string),
|
35
|
+
"str_to_ascii_z should still start with original string")
|
36
|
+
|
37
|
+
assert_equal(original_string.length + 1, zero_terminated_ascii_attempt.length,
|
38
|
+
"str_to_ascii_z should have length of original pluss room for a terminal 0")
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_asciiz_to_str
|
42
|
+
target_string = '23 Skidoo!'
|
43
|
+
post_zero_noise = 'Loud noises!'
|
44
|
+
zero_terminated_string = target_string + "\x00" + post_zero_noise
|
45
|
+
|
46
|
+
actual_string = TEST_DLL_HELPER.asciiz_to_str(zero_terminated_string)
|
47
|
+
|
48
|
+
assert(actual_string.start_with?(target_string),
|
49
|
+
"asciiz_to_str should preserve string before zero")
|
50
|
+
|
51
|
+
assert(!actual_string.end_with?(post_zero_noise),
|
52
|
+
"asciiz_to_str should ignore characters after zero")
|
53
|
+
|
54
|
+
assert_equal(target_string, actual_string,
|
55
|
+
"asciiz_to_str should only return the contents of the string before (exclusive) the zero")
|
56
|
+
|
57
|
+
assert_equal(target_string, TEST_DLL_HELPER.asciiz_to_str(target_string),
|
58
|
+
"asciiz_to_str should return input verbatim should that input not be zero-terminated")
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_str_to_uni_z
|
63
|
+
ruby_string = "If I were a rich man..."
|
64
|
+
|
65
|
+
target_zero_terminated_unicode = Rex::Text.to_unicode(ruby_string) + "\x00\x00"
|
66
|
+
actual_zero_terminated_unicode = TEST_DLL_HELPER.str_to_uni_z(ruby_string)
|
67
|
+
|
68
|
+
assert(actual_zero_terminated_unicode.end_with?("\x00\x00"),
|
69
|
+
"str_to_uni_z should result in a double-zero terminated string")
|
70
|
+
|
71
|
+
assert_equal(target_zero_terminated_unicode, actual_zero_terminated_unicode,
|
72
|
+
"str_to_uni_z should convert ruby string to zero-terminated WCHAR string")
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_uniz_to_str
|
76
|
+
target_string = 'Foo bar baz'
|
77
|
+
|
78
|
+
zero_terminated_unicode = Rex::Text.to_unicode(target_string) + "\x00\x00"
|
79
|
+
|
80
|
+
assert_equal(target_string, TEST_DLL_HELPER.uniz_to_str(zero_terminated_unicode),
|
81
|
+
'uniz_to_str should convert 0-terminated UTF16 to ruby string')
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_assemble_buffer
|
86
|
+
# TODO: provide test coverage
|
87
|
+
#skip("Currently DLLHelper.assemble_buffer does not have coverage")
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_param_to_number
|
91
|
+
consts_manager = WinConstManager.new
|
92
|
+
|
93
|
+
x_key = 'X'
|
94
|
+
x_value = 23
|
95
|
+
|
96
|
+
y_key = 'Y'
|
97
|
+
y_value = 5
|
98
|
+
|
99
|
+
logical_or = x_key + '|' + y_key
|
100
|
+
target_result_of_logical_or = x_value | y_value
|
101
|
+
|
102
|
+
consts_manager.add_const(y_key, y_value)
|
103
|
+
consts_manager.add_const(x_key, x_value)
|
104
|
+
|
105
|
+
assert_equal(x_value, TEST_DLL_HELPER.param_to_number(x_key, consts_manager),
|
106
|
+
"param_to_number should return the appropriate value for a given constant")
|
107
|
+
|
108
|
+
assert_equal(y_value, TEST_DLL_HELPER.param_to_number(y_key, consts_manager),
|
109
|
+
"param_to_number should return the appropriate value for a given constant")
|
110
|
+
|
111
|
+
assert_equal(0, TEST_DLL_HELPER.param_to_number(nil, consts_manager),
|
112
|
+
"param_to_number should return zero when given nil")
|
113
|
+
|
114
|
+
assert_equal(target_result_of_logical_or, TEST_DLL_HELPER.param_to_number(logical_or, consts_manager),
|
115
|
+
"param_to_number should perform an OR should the input be in the form '#{logical_or}'")
|
116
|
+
|
117
|
+
assert_raise(ArgumentError, 'param_to_number should raise an error when a given key does not exist') do
|
118
|
+
TEST_DLL_HELPER.param_to_number('DOESNT_EXIST', consts_manager)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -26,7 +26,8 @@ require 'pp'
|
|
26
26
|
require 'enumerator'
|
27
27
|
require 'rex/post/meterpreter/extensions/stdapi/railgun/api_constants'
|
28
28
|
require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv'
|
29
|
-
require 'rex/post/meterpreter/extensions/stdapi/railgun/
|
29
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper'
|
30
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/buffer_item'
|
30
31
|
|
31
32
|
module Rex
|
32
33
|
module Post
|
@@ -28,11 +28,13 @@
|
|
28
28
|
|
29
29
|
require 'pp'
|
30
30
|
require 'enumerator'
|
31
|
+
|
31
32
|
require 'rex/post/meterpreter/extensions/stdapi/railgun/api_constants'
|
32
33
|
require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv'
|
33
34
|
require 'rex/post/meterpreter/extensions/stdapi/railgun/util'
|
34
|
-
require 'rex/post/meterpreter/extensions/stdapi/railgun/
|
35
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager'
|
35
36
|
require 'rex/post/meterpreter/extensions/stdapi/railgun/multicall'
|
37
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/dll'
|
36
38
|
|
37
39
|
module Rex
|
38
40
|
module Post
|
@@ -45,7 +47,6 @@ module Railgun
|
|
45
47
|
# The Railgun class to dynamically expose the Windows API.
|
46
48
|
#
|
47
49
|
class Railgun
|
48
|
-
|
49
50
|
def initialize( client )
|
50
51
|
|
51
52
|
@client = client
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright (c) 2010, patrickHVE@googlemail.com
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
# * Redistributions of source code must retain the above copyright
|
7
|
+
# notice, this list of conditions and the following disclaimer.
|
8
|
+
# * Redistributions in binary form must reproduce the above copyright
|
9
|
+
# notice, this list of conditions and the following disclaimer in the
|
10
|
+
# documentation and/or other materials provided with the distribution.
|
11
|
+
# * The names of the author may not be used to endorse or promote products
|
12
|
+
# derived from this software without specific prior written permission.
|
13
|
+
#
|
14
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
15
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
16
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
# DISCLAIMED. IN NO EVENT SHALL patrickHVE@googlemail.com BE LIABLE FOR ANY
|
18
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
19
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
20
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
21
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
22
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
23
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
|
+
|
25
|
+
module Rex
|
26
|
+
module Post
|
27
|
+
module Meterpreter
|
28
|
+
module Extensions
|
29
|
+
module Stdapi
|
30
|
+
module Railgun
|
31
|
+
|
32
|
+
#
|
33
|
+
# Manages our library of windows constants
|
34
|
+
#
|
35
|
+
class WinConstManager
|
36
|
+
|
37
|
+
def initialize(initial_consts = {})
|
38
|
+
@consts = {}
|
39
|
+
|
40
|
+
initial_consts.each_pair do |name, value|
|
41
|
+
add_const(name, value)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load utility
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_const(name, value)
|
48
|
+
@consts[name] = value
|
49
|
+
end
|
50
|
+
|
51
|
+
# parses a string constaining constants and returns an integer
|
52
|
+
# the string can be either "CONST" or "CONST1 | CONST2"
|
53
|
+
#
|
54
|
+
# this function will NOT throw an exception but return "nil" if it can't parse a string
|
55
|
+
def parse(s)
|
56
|
+
if s.class != String
|
57
|
+
return nil # it's not even a string'
|
58
|
+
end
|
59
|
+
return_value = 0
|
60
|
+
for one_const in s.split('|')
|
61
|
+
one_const = one_const.strip()
|
62
|
+
if not @consts.has_key? one_const
|
63
|
+
return nil # at least one "Constant" is unknown to us
|
64
|
+
end
|
65
|
+
return_value |= @consts[one_const]
|
66
|
+
end
|
67
|
+
return return_value
|
68
|
+
end
|
69
|
+
|
70
|
+
def is_parseable(s)
|
71
|
+
return parse(s) != nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end; end; end; end; end; end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..','..','..','..','..', 'lib'))
|
4
|
+
|
5
|
+
require 'rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager'
|
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 WinConstManager::UnitTest < Test::Unit::TestCase
|
15
|
+
def test_is_parseable
|
16
|
+
const_manager = WinConstManager.new
|
17
|
+
|
18
|
+
first_key = 'SOME_NUMBER'
|
19
|
+
second_key = 'SOME_OTHER_NUMBER'
|
20
|
+
boolean_logic = first_key + ' | ' + second_key
|
21
|
+
|
22
|
+
# XXX: Should check (un)parseability before adding constants too?
|
23
|
+
|
24
|
+
const_manager.add_const(first_key, 43123)
|
25
|
+
const_manager.add_const(second_key, 234)
|
26
|
+
|
27
|
+
assert(const_manager.is_parseable(boolean_logic),
|
28
|
+
"is_parseable should consider boolean logic statements parseable")
|
29
|
+
|
30
|
+
assert(const_manager.is_parseable(first_key),
|
31
|
+
"is_parseable should consider constants parseable")
|
32
|
+
|
33
|
+
assert(! const_manager.is_parseable(5),
|
34
|
+
"is_parseable should not consider non-string keys as parseable")
|
35
|
+
|
36
|
+
assert(! const_manager.is_parseable('| FOO |'),
|
37
|
+
"is_parseable should not consider malformed boolean expressions parseable")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_add_const
|
41
|
+
target_key = 'VALID_KEY'
|
42
|
+
target_value = 23
|
43
|
+
|
44
|
+
const_manager = WinConstManager.new
|
45
|
+
|
46
|
+
const_manager.add_const(target_key, target_value)
|
47
|
+
|
48
|
+
assert_equal(target_value, const_manager.parse(target_key),
|
49
|
+
"add_const should add a constant/value pair that can be trieved with parse")
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_initialization
|
54
|
+
target_key = 'VALID_KEY'
|
55
|
+
target_value = 23
|
56
|
+
|
57
|
+
const_manager = WinConstManager.new(target_key => target_value)
|
58
|
+
|
59
|
+
assert_equal(target_value, const_manager.parse(target_key),
|
60
|
+
"upon initialization, should add any provided constants.")
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_parse
|
64
|
+
target_key = 'VALID_KEY'
|
65
|
+
target_value = 23
|
66
|
+
invalid_key = 8
|
67
|
+
|
68
|
+
const_manager = WinConstManager.new
|
69
|
+
|
70
|
+
const_manager.add_const(target_key, target_value)
|
71
|
+
|
72
|
+
assert_equal(target_value, const_manager.parse(target_key),
|
73
|
+
"parse should retrieve the corresponding value when a key is provided")
|
74
|
+
|
75
|
+
# From API: "should not throw an exception given an invalid key"
|
76
|
+
assert_nothing_thrown do
|
77
|
+
const_manager.parse(invalid_key)
|
78
|
+
end
|
79
|
+
|
80
|
+
assert_equal(nil, const_manager.parse(invalid_key),
|
81
|
+
"parse should return nil when an invalid key is provided")
|
82
|
+
|
83
|
+
x_key = 'X'
|
84
|
+
x_value = 228
|
85
|
+
y_key = 'Y'
|
86
|
+
y_value = 15
|
87
|
+
|
88
|
+
boolean_logic = x_key + ' | ' + y_key
|
89
|
+
target_boolean_logic_result = x_value | y_value
|
90
|
+
|
91
|
+
const_manager.add_const(x_key, x_value)
|
92
|
+
const_manager.add_const(y_key, y_value)
|
93
|
+
|
94
|
+
assert_equal(target_boolean_logic_result, const_manager.parse(boolean_logic),
|
95
|
+
"parse should evaluate boolean expressions consisting of OR")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|