librex 0.0.70 → 0.0.71
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.markdown +5 -10
- data/Rakefile +1 -1
- data/lib/rex/arch.rb +1 -1
- data/lib/rex/encoder/bloxor/bloxor.rb +1 -0
- data/lib/rex/encoder/ndr.rb +1 -1
- data/lib/rex/exploitation/heaplib.rb +4 -2
- data/lib/rex/exploitation/powershell.rb +62 -0
- data/lib/rex/exploitation/powershell/function.rb +63 -0
- data/lib/rex/exploitation/powershell/obfu.rb +98 -0
- data/lib/rex/exploitation/powershell/output.rb +151 -0
- data/lib/rex/exploitation/powershell/param.rb +23 -0
- data/lib/rex/exploitation/powershell/parser.rb +183 -0
- data/lib/rex/exploitation/powershell/psh_methods.rb +70 -0
- data/lib/rex/exploitation/powershell/script.rb +99 -0
- data/lib/rex/exploitation/ropdb.rb +1 -0
- data/lib/rex/mac_oui.rb +1 -0
- data/lib/rex/ole/util.rb +2 -2
- data/lib/rex/parser/group_policy_preferences.rb +185 -0
- data/lib/rex/parser/outpost24_nokogiri.rb +1 -0
- data/lib/rex/poly/machine.rb +1 -0
- data/lib/rex/poly/machine/machine.rb +1 -0
- data/lib/rex/poly/machine/x86.rb +1 -0
- data/lib/rex/post/meterpreter/extensions/android/android.rb +128 -0
- data/lib/rex/post/meterpreter/extensions/android/tlv.rb +40 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb +32 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +6 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +4 -4
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +2 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb +4 -4
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +4 -4
- data/lib/rex/post/meterpreter/packet.rb +3 -3
- data/lib/rex/post/meterpreter/ui/console.rb +2 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +383 -0
- data/lib/rex/proto/dcerpc/ndr.rb +1 -1
- data/lib/rex/proto/ipmi/channel_auth_reply.rb +1 -0
- data/lib/rex/proto/ipmi/open_session_reply.rb +1 -0
- data/lib/rex/proto/ipmi/rakp2.rb +1 -0
- data/lib/rex/proto/natpmp/packet.rb +8 -8
- data/lib/rex/proto/ntp.rb +3 -0
- data/lib/rex/proto/ntp/constants.rb +12 -0
- data/lib/rex/proto/ntp/modes.rb +130 -0
- data/lib/rex/proto/pjl.rb +1 -0
- data/lib/rex/proto/pjl/client.rb +1 -0
- data/lib/rex/proto/sip.rb +4 -0
- data/lib/rex/proto/sip/response.rb +61 -0
- data/lib/rex/proto/smb/exceptions.rb +11 -3
- data/lib/rex/random_identifier_generator.rb +1 -0
- data/lib/rex/registry/lfkey.rb +1 -1
- data/lib/rex/registry/nodekey.rb +10 -10
- data/lib/rex/registry/valuekey.rb +5 -5
- data/lib/rex/registry/valuelist.rb +1 -1
- data/lib/rex/socket/ip.rb +1 -0
- data/lib/rex/sslscan/result.rb +1 -0
- data/lib/rex/sslscan/scanner.rb +1 -0
- data/lib/rex/text.rb +2 -13
- data/lib/rex/ui/text/output/buffer/stdout.rb +1 -0
- data/lib/rex/ui/text/table.rb +4 -4
- metadata +23 -4
data/lib/rex/proto/dcerpc/ndr.rb
CHANGED
data/lib/rex/proto/ipmi/rakp2.rb
CHANGED
@@ -12,32 +12,32 @@ module Proto
|
|
12
12
|
module NATPMP
|
13
13
|
|
14
14
|
# Return a NAT-PMP request to get the external address.
|
15
|
-
def
|
15
|
+
def external_address_request
|
16
16
|
[ 0, 0 ].pack('nn')
|
17
17
|
end
|
18
18
|
|
19
19
|
# Parse a NAT-PMP external address response +resp+.
|
20
20
|
# Returns the decoded parts of the response as an array.
|
21
|
-
def
|
22
|
-
(ver, op, result, epoch, addr) = resp.unpack("
|
21
|
+
def parse_external_address_response(resp)
|
22
|
+
(ver, op, result, epoch, addr) = resp.unpack("CCnNN")
|
23
23
|
[ ver, op, result, epoch, Rex::Socket::addr_itoa(addr) ]
|
24
24
|
end
|
25
25
|
|
26
26
|
# Return a NAT-PMP request to map remote port +rport+/+protocol+ to local port +lport+ for +lifetime+ ms
|
27
|
-
def
|
28
|
-
[
|
27
|
+
def map_port_request(lport, rport, protocol, lifetime)
|
28
|
+
[ Rex::Proto::NATPMP::Version, # version
|
29
29
|
protocol, # opcode, which is now the protocol we are asking to forward
|
30
30
|
0, # reserved
|
31
31
|
lport,
|
32
32
|
rport,
|
33
33
|
lifetime
|
34
|
-
].pack("
|
34
|
+
].pack("CCnnnN")
|
35
35
|
end
|
36
36
|
|
37
37
|
# Parse a NAT-PMP mapping response +resp+.
|
38
38
|
# Returns the decoded parts as an array.
|
39
|
-
def
|
40
|
-
resp.unpack("
|
39
|
+
def parse_map_port_response(resp)
|
40
|
+
resp.unpack("CCnNnnN")
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'bit-struct'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
module Proto
|
7
|
+
module NTP
|
8
|
+
|
9
|
+
# A very generic NTP message
|
10
|
+
#
|
11
|
+
# Uses the common/similar parts from versions 1-4 and considers everything
|
12
|
+
# after to be just one big field. For the particulars on the different versions,
|
13
|
+
# see:
|
14
|
+
# http://tools.ietf.org/html/rfc958#appendix-B
|
15
|
+
# http://tools.ietf.org/html/rfc1059#appendix-B
|
16
|
+
# pages 45/48 of http://tools.ietf.org/pdf/rfc1119.pdf
|
17
|
+
# http://tools.ietf.org/html/rfc1305#appendix-D
|
18
|
+
# http://tools.ietf.org/html/rfc5905#page-19
|
19
|
+
class NTPGeneric < BitStruct
|
20
|
+
# 0 1 2 3
|
21
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
22
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
23
|
+
# |LI | VN | mode| Stratum | Poll | Precision |
|
24
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
25
|
+
unsigned :li, 2, default: 0
|
26
|
+
unsigned :version, 3, default: 0
|
27
|
+
unsigned :mode, 3, default: 0
|
28
|
+
unsigned :stratum, 8, default: 0
|
29
|
+
unsigned :poll, 8, default: 0
|
30
|
+
unsigned :precision, 8, default: 0
|
31
|
+
rest :payload
|
32
|
+
end
|
33
|
+
|
34
|
+
# An NTP control message. Control messages are only specified for NTP
|
35
|
+
# versions 2-4, but this is a fuzzer so why not try them all...
|
36
|
+
class NTPControl < BitStruct
|
37
|
+
# 0 1 2 3
|
38
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
39
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
40
|
+
# |00 | VN | 6 |R E M| op | Sequence |
|
41
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
42
|
+
# | status | association id |
|
43
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
44
|
+
# | offset | count |
|
45
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
46
|
+
unsigned :reserved, 2, default: 0
|
47
|
+
unsigned :version, 3, default: 0
|
48
|
+
unsigned :mode, 3, default: 6
|
49
|
+
unsigned :response, 1, default: 0
|
50
|
+
unsigned :error, 1, default: 0
|
51
|
+
unsigned :more, 1, default: 0
|
52
|
+
unsigned :operation, 5, default: 0
|
53
|
+
unsigned :sequence, 16, default: 0
|
54
|
+
unsigned :status, 16, default: 0
|
55
|
+
unsigned :association_id, 16, default: 0
|
56
|
+
# TODO: there *must* be bugs in the handling of these next two fields!
|
57
|
+
unsigned :payload_offset, 16, default: 0
|
58
|
+
unsigned :payload_size, 16, default: 0
|
59
|
+
rest :payload
|
60
|
+
end
|
61
|
+
|
62
|
+
# An NTP "private" message. Private messages are only specified for NTP
|
63
|
+
# versions 2-4, but this is a fuzzer so why not try them all...
|
64
|
+
class NTPPrivate < BitStruct
|
65
|
+
# 0 1 2 3
|
66
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
67
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
68
|
+
# |R M| VN | 7 |A| Sequence | Implementation| Req code |
|
69
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
70
|
+
# | err | Number of data items | MBZ | Size of data item |
|
71
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
72
|
+
unsigned :response, 1, default: 0
|
73
|
+
unsigned :more, 1, default: 0
|
74
|
+
unsigned :version, 3, default: 0
|
75
|
+
unsigned :mode, 3, default: 7
|
76
|
+
unsigned :auth, 1, default: 0
|
77
|
+
unsigned :sequence, 7, default: 0
|
78
|
+
unsigned :implementation, 8, default: 0
|
79
|
+
unsigned :request_code, 8, default: 0
|
80
|
+
unsigned :error, 4, default: 0
|
81
|
+
unsigned :record_count, 12, default: 0
|
82
|
+
unsigned :mbz, 4, default: 0
|
83
|
+
unsigned :record_size, 12, default: 0
|
84
|
+
rest :payload
|
85
|
+
|
86
|
+
def records
|
87
|
+
records = []
|
88
|
+
1.upto(record_count) do |record_num|
|
89
|
+
records << payload[record_size*(record_num-1), record_size]
|
90
|
+
end
|
91
|
+
records
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.ntp_control(version, operation, payload = nil)
|
96
|
+
n = NTPControl.new
|
97
|
+
n.version = version
|
98
|
+
n.operation = operation
|
99
|
+
if payload
|
100
|
+
n.payload_offset = 0
|
101
|
+
n.payload_size = payload.size
|
102
|
+
n.payload = payload
|
103
|
+
end
|
104
|
+
n
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.ntp_private(version, implementation, request_code, payload = nil)
|
108
|
+
n = NTPPrivate.new
|
109
|
+
n.version = version
|
110
|
+
n.implementation = implementation
|
111
|
+
n.request_code = request_code
|
112
|
+
n.payload = payload if payload
|
113
|
+
n
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.ntp_generic(version, mode)
|
117
|
+
n = NTPGeneric.new
|
118
|
+
n.version = version
|
119
|
+
n.mode = mode
|
120
|
+
n
|
121
|
+
end
|
122
|
+
|
123
|
+
# Parses the given message and provides a description about the NTP message inside
|
124
|
+
def self.describe(message)
|
125
|
+
ntp = NTPGeneric.new(message)
|
126
|
+
"#{message.size}-byte version #{ntp.version} mode #{ntp.mode} reply"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/rex/proto/pjl.rb
CHANGED
data/lib/rex/proto/pjl/client.rb
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
3
|
+
module Rex
|
4
|
+
module Proto
|
5
|
+
# SIP protocol support
|
6
|
+
module SIP
|
7
|
+
SIP_STATUS_REGEX = /^SIP\/(\d\.\d) (\d{3})\s*(.*)$/
|
8
|
+
|
9
|
+
# Represents a generic SIP message
|
10
|
+
class Message
|
11
|
+
attr_accessor :headers
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@headers = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns a list of all values from all +name+ headers, regardless of case,
|
18
|
+
# or nil if no matching header is found
|
19
|
+
def header(name)
|
20
|
+
matches = @headers.select { |k, _| k.downcase == name.downcase }
|
21
|
+
return nil if matches.empty?
|
22
|
+
matches.values.flatten
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a hash of header name to values mapping
|
26
|
+
# from the provided message, or nil if no headers
|
27
|
+
# are found
|
28
|
+
def self.extract_headers(message)
|
29
|
+
pairs = message.scan(/^([^\s:]+):\s*(.*)$/)
|
30
|
+
return nil if pairs.empty?
|
31
|
+
headers = {}
|
32
|
+
pairs.each do |pair|
|
33
|
+
headers[pair.first] ||= []
|
34
|
+
headers[pair.first] << pair.last.strip
|
35
|
+
end
|
36
|
+
headers
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Represents a SIP response message
|
41
|
+
class Response < Message
|
42
|
+
attr_accessor :code, :message, :status_line, :version
|
43
|
+
|
44
|
+
# Parses +data+, constructs and returns a Response
|
45
|
+
def self.parse(data)
|
46
|
+
response = Response.new
|
47
|
+
# do some basic sanity checking on this response to ensure that it is SIP
|
48
|
+
response.status_line = data.split(/\r\n/)[0]
|
49
|
+
unless response.status_line && response.status_line =~ SIP_STATUS_REGEX
|
50
|
+
fail(ArgumentError, "Invalid SIP status line: #{response.status_line}")
|
51
|
+
end
|
52
|
+
response.version = Regexp.last_match(1)
|
53
|
+
response.code = Regexp.last_match(2)
|
54
|
+
response.message = Regexp.last_match(3)
|
55
|
+
response.headers = extract_headers(data)
|
56
|
+
response
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -739,11 +739,15 @@ class Error < ::RuntimeError
|
|
739
739
|
# returns an error string if it exists, otherwise just the error code
|
740
740
|
def get_error(error)
|
741
741
|
string = ''
|
742
|
-
if @@errors[error]
|
742
|
+
if error && @@errors[error]
|
743
743
|
string = @@errors[error]
|
744
|
-
|
744
|
+
elsif error
|
745
745
|
string = sprintf('0x%.8x',error)
|
746
|
+
else
|
747
|
+
string = "Unknown error"
|
746
748
|
end
|
749
|
+
|
750
|
+
string
|
747
751
|
end
|
748
752
|
end
|
749
753
|
|
@@ -781,6 +785,10 @@ class InvalidPacket < Error
|
|
781
785
|
attr_accessor :word_count
|
782
786
|
attr_accessor :command
|
783
787
|
attr_accessor :error_code
|
788
|
+
|
789
|
+
def error_name
|
790
|
+
get_error(error_code)
|
791
|
+
end
|
784
792
|
end
|
785
793
|
|
786
794
|
class InvalidWordCount < InvalidPacket
|
@@ -807,7 +815,7 @@ end
|
|
807
815
|
class ErrorCode < InvalidPacket
|
808
816
|
def to_s
|
809
817
|
'The server responded with error: ' +
|
810
|
-
self.
|
818
|
+
self.error_name +
|
811
819
|
" (Command=#{self.command} WordCount=#{self.word_count})"
|
812
820
|
end
|
813
821
|
end
|
data/lib/rex/registry/lfkey.rb
CHANGED
@@ -41,7 +41,7 @@ class LFHashRecord
|
|
41
41
|
attr_accessor :nodekey_offset, :nodekey_name_verification
|
42
42
|
|
43
43
|
def initialize(hive_blob, offset)
|
44
|
-
@nodekey_offset = hive_blob[offset, 4].unpack('
|
44
|
+
@nodekey_offset = hive_blob[offset, 4].unpack('V').first
|
45
45
|
@nodekey_name_verification = hive_blob[offset+0x04, 4].to_s
|
46
46
|
end
|
47
47
|
|
data/lib/rex/registry/nodekey.rb
CHANGED
@@ -23,16 +23,16 @@ class NodeKey
|
|
23
23
|
return
|
24
24
|
end
|
25
25
|
|
26
|
-
@timestamp = hive[offset+0x04, 8].unpack('
|
27
|
-
@parent_offset = hive[offset+0x10, 4].unpack('
|
28
|
-
@subkeys_count = hive[offset+0x14, 4].unpack('
|
29
|
-
@lf_record_offset = hive[offset+0x1c, 4].unpack('
|
30
|
-
@value_count = hive[offset+0x24, 4].unpack('
|
31
|
-
@value_list_offset = hive[offset+0x28, 4].unpack('
|
32
|
-
@security_key_offset = hive[offset+0x2c, 4].unpack('
|
33
|
-
@class_name_offset = hive[offset+0x30, 4].unpack('
|
34
|
-
@name_length = hive[offset+0x48, 2].unpack('
|
35
|
-
@class_name_length = hive[offset+0x4a, 2].unpack('
|
26
|
+
@timestamp = hive[offset+0x04, 8].unpack('Q').first
|
27
|
+
@parent_offset = hive[offset+0x10, 4].unpack('V').first
|
28
|
+
@subkeys_count = hive[offset+0x14, 4].unpack('V').first
|
29
|
+
@lf_record_offset = hive[offset+0x1c, 4].unpack('V').first
|
30
|
+
@value_count = hive[offset+0x24, 4].unpack('V').first
|
31
|
+
@value_list_offset = hive[offset+0x28, 4].unpack('V').first
|
32
|
+
@security_key_offset = hive[offset+0x2c, 4].unpack('V').first
|
33
|
+
@class_name_offset = hive[offset+0x30, 4].unpack('V').first
|
34
|
+
@name_length = hive[offset+0x48, 2].unpack('C').first
|
35
|
+
@class_name_length = hive[offset+0x4a, 2].unpack('C').first
|
36
36
|
@name = hive[offset+0x4c, @name_length].to_s
|
37
37
|
|
38
38
|
windows_time = @timestamp
|
@@ -17,10 +17,10 @@ class ValueKey
|
|
17
17
|
return
|
18
18
|
end
|
19
19
|
|
20
|
-
@name_length = hive[offset+0x02, 2].unpack('
|
21
|
-
@length_of_data = hive[offset+0x04, 4].unpack('
|
22
|
-
@data_offset = hive[offset+ 0x08, 4].unpack('
|
23
|
-
@value_type = hive[offset+0x0C, 4].unpack('
|
20
|
+
@name_length = hive[offset+0x02, 2].unpack('C').first
|
21
|
+
@length_of_data = hive[offset+0x04, 4].unpack('V').first
|
22
|
+
@data_offset = hive[offset+ 0x08, 4].unpack('V').first
|
23
|
+
@value_type = hive[offset+0x0C, 4].unpack('C').first
|
24
24
|
|
25
25
|
if @value_type == 1
|
26
26
|
@readable_value_type = "Unicode character string"
|
@@ -34,7 +34,7 @@ class ValueKey
|
|
34
34
|
@readable_value_type = "Multiple unicode strings separated with '\\x00'"
|
35
35
|
end
|
36
36
|
|
37
|
-
flag = hive[offset+0x10, 2].unpack('
|
37
|
+
flag = hive[offset+0x10, 2].unpack('C').first
|
38
38
|
|
39
39
|
if flag == 0
|
40
40
|
@name = "Default"
|
@@ -18,7 +18,7 @@ class ValueList
|
|
18
18
|
valuekey_offset = hive[offset + inner_offset, 4]
|
19
19
|
next if !valuekey_offset
|
20
20
|
|
21
|
-
valuekey_offset = valuekey_offset.unpack('
|
21
|
+
valuekey_offset = valuekey_offset.unpack('V').first
|
22
22
|
@values << ValueKey.new(hive, valuekey_offset + 0x1000)
|
23
23
|
inner_offset = inner_offset + 4
|
24
24
|
end
|
data/lib/rex/socket/ip.rb
CHANGED
data/lib/rex/sslscan/result.rb
CHANGED
data/lib/rex/sslscan/scanner.rb
CHANGED
data/lib/rex/text.rb
CHANGED
@@ -3,6 +3,7 @@ require 'digest/md5'
|
|
3
3
|
require 'digest/sha1'
|
4
4
|
require 'stringio'
|
5
5
|
require 'cgi'
|
6
|
+
require 'rex/exploitation/powershell'
|
6
7
|
|
7
8
|
%W{ iconv zlib }.each do |libname|
|
8
9
|
begin
|
@@ -305,19 +306,7 @@ module Text
|
|
305
306
|
# Converts a raw string to a powershell byte array
|
306
307
|
#
|
307
308
|
def self.to_powershell(str, name = "buf")
|
308
|
-
return
|
309
|
-
|
310
|
-
code = str.unpack('C*')
|
311
|
-
buff = "[Byte[]]$#{name} = 0x#{code[0].to_s(16)}"
|
312
|
-
1.upto(code.length-1) do |byte|
|
313
|
-
if(byte % 10 == 0)
|
314
|
-
buff << "\r\n$#{name} += 0x#{code[byte].to_s(16)}"
|
315
|
-
else
|
316
|
-
buff << ",0x#{code[byte].to_s(16)}"
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
return buff
|
309
|
+
return Rex::Exploitation::Powershell::Script.to_byte_array(str, name)
|
321
310
|
end
|
322
311
|
|
323
312
|
#
|