CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/proto/dcerpc/response.rb
Views: 11704
1
# -*- coding: binary -*-
2
3
module Rex
4
module Proto
5
module DCERPC
6
class Response
7
8
attr_accessor :frag_len, :auth_len, :type, :vers_major, :vers_minor
9
attr_accessor :flags, :data_rep, :call_id, :max_frag_xmit, :max_frag_recv
10
attr_accessor :assoc_group, :sec_addr_len, :sec_addr, :num_results
11
attr_accessor :nack_reason, :xfer_syntax_uuid, :xfer_syntax_vers
12
attr_accessor :ack_reason, :ack_result, :ack_xfer_syntax_uuid, :ack_xfer_syntax_vers
13
attr_accessor :alloc_hint, :context_id, :cancel_cnt, :status, :stub_data
14
attr_accessor :raw
15
16
FLAG_FIRST_FRAG = 1 << 0
17
FLAG_LAST_FRAG = 1 << 1
18
19
# Create a new DCERPC::Response object
20
# This can be initialized in two ways:
21
# 1) Call .new() with the first 10 bytes of packet, then call parse on the rest
22
# 2) Call .new() with the full packet contents
23
def initialize(data)
24
25
self.ack_result = []
26
self.ack_reason = []
27
self.ack_xfer_syntax_uuid = []
28
self.ack_xfer_syntax_vers = []
29
30
if (! data or data.length < 10)
31
raise Rex::Proto::DCERPC::Exceptions::InvalidPacket, 'DCERPC response packet is incomplete'
32
end
33
34
if (data.length == 10)
35
self.frag_len = data[8,2].unpack('v')[0]
36
self.raw = data
37
end
38
39
if (data.length > 10)
40
self.raw = data
41
self.parse
42
end
43
end
44
45
# Parse the contents of a DCERPC response packet and fill out all the fields
46
def parse(body = '')
47
self.raw = self.raw + body
48
self.type = self.raw[2,1].unpack('C')[0]
49
50
uuid = Rex::Proto::DCERPC::UUID
51
data = self.raw
52
53
if(not data)
54
raise Rex::Proto::DCERPC::Exceptions::InvalidPacket, 'DCERPC response packet is incomplete'
55
end
56
57
# BIND_ACK == 12, ALTER_CONTEXT_RESP == 15
58
if (self.type == 12 or self.type == 15)
59
60
# Decode most of the DCERPC header
61
self.vers_major,
62
self.vers_minor,
63
trash,
64
self.flags,
65
self.data_rep,
66
self.frag_len,
67
self.auth_len,
68
self.call_id,
69
self.max_frag_xmit,
70
self.max_frag_recv,
71
self.assoc_group,
72
self.sec_addr_len = data.unpack('CCCCNvvVvvVv')
73
74
75
if(not self.frag_len or data.length < self.frag_len)
76
raise Rex::Proto::DCERPC::Exceptions::InvalidPacket, 'DCERPC response packet is incomplete'
77
end
78
79
# Keep an offset into the packet handy
80
x = 0
81
82
# XXX This is still somewhat broken (4 digit ports)
83
self.sec_addr = data[26, self.sec_addr_len]
84
85
# Move the pointer into the packet forward
86
x += 26 + self.sec_addr_len
87
88
# Align the pointer on a dword boundary
89
while (x % 4 != 0)
90
x += 1
91
end
92
93
# Figure out how many results we have (multiple-context binds)
94
self.num_results = data[ x, 4 ].unpack('V')[0]
95
96
# Move the pointer to the ack_result[0] offset
97
x += 4
98
99
# Initialize the ack_result index
100
ack = 0
101
102
# Scan through all results and add them to the result arrays
103
while ack < self.num_results
104
self.ack_result[ack] = data[ x + 0, 2 ].unpack('v')[0]
105
self.ack_reason[ack] = data[ x + 2, 2 ].unpack('v')[0]
106
self.ack_xfer_syntax_uuid[ack] = uuid.uuid_unpack(data[ x + 4, 16 ])
107
self.ack_xfer_syntax_vers[ack] = data[ x + 20, 4 ].unpack('V')[0]
108
x += 24
109
ack += 1
110
end
111
112
# End of BIND_ACK || ALTER_CONTEXT_RESP
113
end
114
115
# BIND_NACK == 13
116
if (self.type == 13)
117
118
# Decode most of the DCERPC header
119
self.vers_major,
120
self.vers_minor,
121
trash,
122
self.flags,
123
self.data_rep,
124
self.frag_len,
125
self.auth_len,
126
self.call_id,
127
self.nack_reason = data.unpack('CCCCNvvVv')
128
end
129
130
# RESPONSE == 2
131
if (self.type == 2)
132
133
# Decode the DCERPC response header
134
self.vers_major,
135
self.vers_minor,
136
trash,
137
self.flags,
138
self.data_rep,
139
self.frag_len,
140
self.auth_len,
141
self.call_id,
142
self.alloc_hint,
143
self.context_id,
144
self.cancel_cnt = data.unpack('CCCCNvvVVvC')
145
146
stub_offset = 24
147
# Error out if the whole header was not read
148
if !(self.alloc_hint and self.context_id and self.cancel_cnt)
149
raise Rex::Proto::DCERPC::Exceptions::InvalidPacket, 'DCERPC response packet is incomplete'
150
end
151
152
# Put the application data into self.stub_data
153
self.stub_data = data[stub_offset..self.frag_len - self.auth_len]
154
# End of RESPONSE
155
end
156
157
# FAULT == 3
158
if (self.type == 3)
159
160
# Decode the DCERPC response header
161
self.vers_major,
162
self.vers_minor,
163
trash,
164
self.flags,
165
self.data_rep,
166
self.frag_len,
167
self.auth_len,
168
self.call_id,
169
self.alloc_hint,
170
self.context_id,
171
self.cancel_cnt,
172
trash,
173
self.status = data.unpack('CCCCNvvVVvCCV')
174
175
# Put the application data into self.stub_data
176
self.stub_data = data[data.length - self.alloc_hint, 0xffff]
177
# End of FAULT
178
end
179
180
end
181
182
protected
183
# attr_accessor :raw
184
185
end
186
end
187
end
188
end
189
190
191