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