Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/spec/lib/rex/proto/mssql/client_mixin_spec.rb
74576 views
1
# -*- coding: binary -*-
2
3
require 'spec_helper'
4
require 'rex/proto/mssql/client'
5
6
RSpec.describe Rex::Proto::MSSQL::ClientMixin do
7
let(:client) { Rex::Proto::MSSQL::Client.allocate }
8
9
describe '#mssql_parse_order' do
10
let(:info) { { errors: [] } }
11
12
it 'consumes the ORDER token data and returns info unchanged' do
13
data = [4, 1, 2].pack('vvv')
14
result = client.mssql_parse_order(data, info)
15
expect(result[:errors]).to be_empty
16
expect(data).to be_empty
17
end
18
19
it 'handles a single column ordinal' do
20
data = [2, 3].pack('vv')
21
result = client.mssql_parse_order(data, info)
22
expect(result[:errors]).to be_empty
23
expect(data).to be_empty
24
end
25
26
it 'preserves remaining data after the ORDER token' do
27
trailing = "\xAB\xCD".b
28
data = [2, 1].pack('vv') + trailing
29
client.mssql_parse_order(data, info)
30
expect(data).to eq(trailing)
31
end
32
33
it 'handles zero-length ORDER token' do
34
data = [0].pack('v')
35
result = client.mssql_parse_order(data, info)
36
expect(result[:errors]).to be_empty
37
expect(data).to be_empty
38
end
39
end
40
41
describe '#mssql_parse_reply' do
42
context 'when response contains an ORDER token (0xA9)' do
43
it 'parses the ORDER token without error' do
44
colmeta = [0x81].pack('C') + [1].pack('v')
45
colmeta += [0, 0].pack('vv')
46
colmeta += [56].pack('C')
47
colmeta += [0].pack('C')
48
49
order = [0xA9].pack('C') + [2, 1].pack('vv')
50
done = [0xFD].pack('C') + [0, 0, 0].pack('vvV')
51
52
data = colmeta + order + done
53
result = client.mssql_parse_reply(data)
54
expect(result[:errors]).to be_empty
55
end
56
57
it 'does not confuse ORDER token (0xA9) with NBCROW token (0xD2)' do
58
colmeta = [0x81].pack('C') + [1].pack('v')
59
colmeta += [0, 0].pack('vv')
60
colmeta += [56].pack('C')
61
colmeta += [0].pack('C')
62
63
order = [0xA9].pack('C') + [4, 1, 2].pack('vvv')
64
row = [0xD1].pack('C') + [42].pack('V')
65
done = [0xFD].pack('C') + [0, 0, 1].pack('vvV')
66
67
data = colmeta + order + row + done
68
result = client.mssql_parse_reply(data)
69
expect(result[:errors]).to be_empty
70
expect(result[:rows]).to eq([[42]])
71
end
72
end
73
end
74
75
describe '#mssql_parse_nbcrow' do
76
let(:info) { { colinfos: [], colnames: [], errors: [] } }
77
78
context 'when column info is missing' do
79
it 'returns early without errors' do
80
data = "\x00\x01\x02"
81
info[:colinfos] = nil
82
result = client.mssql_parse_nbcrow(data, info)
83
expect(result).to eq(info)
84
end
85
end
86
87
context 'when data is empty' do
88
it 'returns info unchanged' do
89
info[:colinfos] = [{ id: :string, name: 'col1' }]
90
data = ''
91
result = client.mssql_parse_nbcrow(data, info)
92
expect(result[:errors]).to be_empty
93
end
94
end
95
end
96
97
describe '#mssql_parse_tds_row' do
98
let(:info) { { colinfos: [], rows: [], errors: [] } }
99
100
context 'when :int column has NULL sentinel' do
101
it 'returns nil for len == 0' do
102
info[:colinfos] = [{ id: :int, name: 'col1' }]
103
data = [0].pack('C')
104
client.mssql_parse_tds_row(data, info)
105
expect(info[:rows].last).to eq([nil])
106
expect(info[:errors]).to be_empty
107
end
108
109
it 'returns nil for len == 255' do
110
info[:colinfos] = [{ id: :int, name: 'col1' }]
111
data = [255].pack('C')
112
client.mssql_parse_tds_row(data, info)
113
expect(info[:rows].last).to eq([nil])
114
expect(info[:errors]).to be_empty
115
end
116
117
it 'parses a 4-byte integer' do
118
info[:colinfos] = [{ id: :int, name: 'col1' }]
119
data = [4].pack('C') + [42].pack('V')
120
client.mssql_parse_tds_row(data, info)
121
expect(info[:rows].last).to eq([42])
122
expect(info[:errors]).to be_empty
123
end
124
end
125
126
context 'when :hex column has NULL sentinel (0xFFFF)' do
127
it 'returns nil for len == 65535' do
128
info[:colinfos] = [{ id: :hex, name: 'col1' }]
129
data = [65535].pack('v')
130
client.mssql_parse_tds_row(data, info)
131
expect(info[:rows].last).to eq([nil])
132
expect(info[:errors]).to be_empty
133
end
134
135
it 'parses hex data' do
136
info[:colinfos] = [{ id: :hex, name: 'col1' }]
137
data = [2].pack('v') + "\x41\x42"
138
client.mssql_parse_tds_row(data, info)
139
expect(info[:rows].last).to eq(['4142'])
140
expect(info[:errors]).to be_empty
141
end
142
end
143
144
context 'when :string column has NULL sentinel (0xFFFF)' do
145
it 'returns nil for len == 65535' do
146
info[:colinfos] = [{ id: :string, name: 'col1' }]
147
data = [65535].pack('v')
148
client.mssql_parse_tds_row(data, info)
149
expect(info[:rows].last).to eq([nil])
150
expect(info[:errors]).to be_empty
151
end
152
153
it 'parses a string value' do
154
info[:colinfos] = [{ id: :string, name: 'col1' }]
155
data = [3].pack('v') + "foo"
156
client.mssql_parse_tds_row(data, info)
157
expect(info[:rows].last).to eq(['foo'])
158
expect(info[:errors]).to be_empty
159
end
160
end
161
162
context 'when :guid column is NULL' do
163
it 'returns nil for read_length == 0' do
164
info[:colinfos] = [{ id: :guid, name: 'col1' }]
165
data = [0].pack('C')
166
client.mssql_parse_tds_row(data, info)
167
expect(info[:rows].last).to eq([nil])
168
expect(info[:errors]).to be_empty
169
end
170
end
171
172
context 'when :int has invalid size' do
173
it 'logs error and consumes len bytes' do
174
info[:colinfos] = [{ id: :int, name: 'col1' }]
175
trailing = "AFTER".b
176
data = [3].pack('C') + "XXX" + trailing
177
client.mssql_parse_tds_row(data, info)
178
expect(info[:errors].length).to eq(1)
179
expect(info[:errors].first).to match(/invalid integer size: 3/)
180
expect(data).to eq(trailing)
181
end
182
end
183
end
184
end
185
186