Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
beefproject
GitHub Repository: beefproject/beef
Path: blob/master/test/integration/tc_dns_rest.rb
1154 views
1
#
2
# Copyright (c) 2006-2025 Wade Alcorn - [email protected]
3
# Browser Exploitation Framework (BeEF) - https://beefproject.com
4
# See the file 'doc/COPYING' for copying permission
5
#
6
require 'test/unit'
7
require 'rest-client'
8
require 'json'
9
require '../common/test_constants'
10
11
class TC_DnsRest < Test::Unit::TestCase
12
13
class << self
14
15
def startup
16
json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json
17
@@headers = {:content_type => :json, :accept => :json}
18
19
response = RestClient.post("#{RESTAPI_ADMIN}/login",
20
json,
21
@@headers)
22
23
result = JSON.parse(response.body)
24
@@token = result['token']
25
26
$root_dir = '../../'
27
$:.unshift($root_dir)
28
29
require 'core/loader'
30
31
BeEF::Core::Configuration.new(File.join($root_dir, 'config.yaml'))
32
BeEF::Core::Configuration.instance.load_extensions_config
33
34
@@config = BeEF::Core::Configuration.instance
35
end
36
37
def shutdown
38
$root_dir = nil
39
end
40
41
end
42
43
# Tests POST /api/dns/rule handler with valid input
44
def test_1_add_rule_good
45
pattern = 'foo.bar'
46
resource = 'A'
47
dns_response = ['1.2.3.4']
48
49
json = {:pattern => pattern, :resource => resource, :response => dns_response}.to_json
50
51
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
52
json,
53
@@headers)
54
55
check_rest_response(rest_response)
56
57
result = JSON.parse(rest_response.body)
58
first_id = result['id']
59
60
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
61
json,
62
@@headers)
63
64
# Verify that adding an existing rule returns its id
65
check_rest_response(rest_response)
66
67
result = JSON.parse(rest_response.body)
68
second_id = result['id']
69
70
assert_equal(first_id, second_id)
71
end
72
73
# Tests POST /api/dns/rule handler with invalid input
74
def test_2_add_rule_bad
75
pattern = ''
76
resource = 'A'
77
dns_response = ['1.1.1.1']
78
79
hash = {:pattern => pattern, :resource => resource, :response => dns_response}
80
81
# Test that an empty "pattern" key returns 400
82
assert_raise RestClient::BadRequest do
83
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
84
hash.to_json,
85
@@headers)
86
end
87
88
hash['pattern'] = 'foo.bar.baz'
89
hash['resource'] = ''
90
91
# Test that an empty "resource" key returns 400
92
assert_raise RestClient::BadRequest do
93
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
94
hash.to_json,
95
@@headers)
96
end
97
98
hash['resource'] = 'A'
99
hash['response'] = []
100
101
# Test that an empty "response" key returns 400
102
assert_raise RestClient::BadRequest do
103
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
104
hash.to_json,
105
@@headers)
106
end
107
108
hash['response'] = 42
109
110
# Test that a non-array "response" key returns 400
111
assert_raise RestClient::BadRequest do
112
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
113
hash.to_json,
114
@@headers)
115
end
116
end
117
=begin
118
# Tests POST /api/dns/rule handler with each supported RR type
119
def test_3_add_rule_types
120
pattern = 'be.ef'
121
resource = 'AAAA'
122
response = ['2001:db8:ac10:fe01::']
123
124
# Test AAAA type
125
rule = {'pattern' => pattern, 'resource' => resource, 'response' => response}
126
127
regex = %r{
128
^#{rule['pattern']}\.\t+
129
\d+\t+
130
IN\t+
131
#{rule['resource']}\t+
132
#{rule['response'][0]}$
133
}x
134
135
add_rule(rule)
136
check_dns_response(regex, rule['resource'], rule['pattern'])
137
138
# Test CNAME type
139
rule['resource'] = 'CNAME'
140
rule['response'] = ['fe.eb.']
141
142
regex = %r{
143
^#{rule['pattern']}\.\t+
144
\d+\t+
145
IN\t+
146
#{rule['resource']}\t+
147
#{rule['response'][0]}$
148
}x
149
150
add_rule(rule)
151
check_dns_response(regex, rule['resource'], rule['pattern'])
152
153
# Test HINFO type
154
rule['resource'] = 'HINFO'
155
rule['response'] = ['M6800', 'VMS']
156
157
regex = %r{
158
^#{rule['pattern']}\.\t+
159
\d+\t+
160
IN\t+
161
#{rule['resource']}\t+
162
"#{rule['response'][0]}"\s+
163
"#{rule['response'][1]}"$
164
}x
165
166
add_rule(rule)
167
check_dns_response(regex, rule['resource'], rule['pattern'])
168
169
# Test MINFO type
170
rule['resource'] = 'MINFO'
171
rule['response'] = ['rmail.be.ef.', 'email.be.ef.']
172
173
regex = %r{
174
^#{rule['pattern']}\.\t+
175
\d+\t+
176
IN\t+
177
#{rule['resource']}\t+
178
#{rule['response'][0]}\s+
179
#{rule['response'][1]}$
180
}x
181
182
add_rule(rule)
183
check_dns_response(regex, rule['resource'], rule['pattern'])
184
185
# Test MX type
186
rule['resource'] = 'MX'
187
rule['response'] = [10, 'mail.be.ef.']
188
189
regex = %r{
190
^#{rule['pattern']}\.\t+
191
\d+\t+
192
IN\t+
193
#{rule['resource']}\t+
194
#{rule['response'][0]}\s+
195
#{rule['response'][1]}$
196
}x
197
198
add_rule(rule)
199
check_dns_response(regex, rule['resource'], rule['pattern'])
200
201
# Test NS type
202
rule['resource'] = 'NS'
203
rule['response'] = ['ns.be.ef.']
204
205
regex = %r{
206
^#{rule['pattern']}\.\t+
207
\d+\t+
208
IN\t+
209
#{rule['resource']}\t+
210
#{rule['response'][0]}$
211
}x
212
213
add_rule(rule)
214
check_dns_response(regex, rule['resource'], rule['pattern'])
215
216
# Test PTR type
217
rule['resource'] = 'PTR'
218
rule['response'] = ['4.3.2.1.in-addr.arpa.']
219
220
regex = %r{
221
^#{rule['pattern']}\.\t+
222
\d+\t+
223
IN\t+
224
#{rule['resource']}\t+
225
#{rule['response'][0]}$
226
}x
227
228
add_rule(rule)
229
check_dns_response(regex, rule['resource'], rule['pattern'])
230
231
# Test SOA type
232
rule['resource'] = 'SOA'
233
rule['response'] = [
234
"ns.#{rule['pattern']}.",
235
"mail.#{rule['pattern']}.",
236
2012031500,
237
10800,
238
3600,
239
604800,
240
3600
241
]
242
243
regex = %r{
244
^#{rule['pattern']}\.\t+
245
\d+\t+
246
IN\t+
247
#{rule['resource']}\t+
248
.*
249
}x
250
251
add_rule(rule)
252
check_dns_response(regex, rule['resource'], rule['pattern'])
253
254
# Test TXT type
255
rule['resource'] = 'TXT'
256
rule['response'] = ['b33f_is_s0_l33t']
257
258
regex = %r{
259
^#{rule['pattern']}\.\t+
260
\d+\t+
261
IN\t+
262
#{rule['resource']}\t+
263
"#{rule['response'][0]}"$
264
}x
265
266
add_rule(rule)
267
check_dns_response(regex, rule['resource'], rule['pattern'])
268
269
# Test WKS type
270
rule['resource'] = 'WKS'
271
rule['response'] = ['9.9.9.9', 6, 0]
272
273
regex = %r{
274
^#{rule['pattern']}\.\t+
275
\d+\t+
276
IN\t+
277
#{rule['resource']}\t+
278
#{rule['response'][0]}\s
279
0\s5\s6$
280
}x
281
282
add_rule(rule)
283
check_dns_response(regex, rule['resource'], rule['pattern'])
284
285
# Test that an invalid RR returns 400
286
rule['resource'] = 'BeEF'
287
288
assert_raise RestClient::BadRequest do
289
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
290
rule.to_json,
291
@@headers)
292
end
293
end
294
=begin
295
# Tests GET /api/dns/rule/:id handler with valid input
296
def test_4_get_rule_good
297
pattern = 'wheres.the.beef'
298
resource = 'A'
299
dns_response = ['4.2.4.2']
300
301
json = {:pattern => pattern, :resource => resource, :response => dns_response}.to_json
302
303
rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
304
json,
305
@@headers)
306
307
check_rest_response(rest_response)
308
result = JSON.parse(rest_response.body)
309
id = result['id']
310
311
rest_response = RestClient.get("#{RESTAPI_DNS}/rule/#{id}", :params => {:token => @@token})
312
313
assert_not_nil(rest_response.body)
314
assert_equal(200, rest_response.code)
315
316
result = JSON.parse(rest_response.body)
317
318
assert_equal(id, result['id'])
319
assert_equal(pattern, result['pattern'])
320
assert_equal(resource, result['resource'])
321
assert_equal(dns_response, result['response'])
322
end
323
324
# Tests GET /api/dns/rule/:id handler with invalid input
325
def test_5_get_rule_bad
326
id = 42
327
328
assert_raise RestClient::ResourceNotFound do
329
response = RestClient.get("#{RESTAPI_DNS}/rule/#{id}", :params => {:token => @@token})
330
end
331
332
id = '(*_*)'
333
334
assert_raise RestClient::BadRequest do
335
RestClient.get("#{RESTAPI_DNS}/rule/#{id}", :params => {:token => @@token})
336
end
337
end
338
339
# Tests GET /api/dns/ruleset handler
340
def test_6_get_ruleset
341
rest_response = RestClient.get("#{RESTAPI_DNS}/ruleset", :params => {:token => @@token})
342
343
assert_not_nil(rest_response.body)
344
assert_equal(200, rest_response.code)
345
346
result = JSON.parse(rest_response.body)
347
assert_equal(15, result['count'])
348
349
result['ruleset'].each do |rule|
350
assert(rule['id'])
351
assert(rule['pattern'])
352
assert(rule['resource'])
353
assert(rule['response'].length != 0)
354
end
355
end
356
=end
357
private
358
359
# Adds a new DNS rule
360
def add_rule(params)
361
response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}",
362
params.to_json,
363
@@headers)
364
365
check_rest_response(response)
366
end
367
368
# Standard assertions for verifying response from RESTful API
369
def check_rest_response(response)
370
assert_not_nil(response.body)
371
assert_equal(200, response.code)
372
373
result = JSON.parse(response.body)
374
375
assert(result['success'])
376
assert(result['id'])
377
end
378
379
# Compares output of dig command against regex
380
def check_dns_response(regex, type, pattern)
381
address = @@config.get('beef.extension.dns.address')
382
port = @@config.get('beef.extension.dns.port')
383
384
dig_output = IO.popen(["dig", "@#{address}", "-p", "#{port}", "-t", "#{type}", "#{pattern}"], 'r+').read
385
assert_match(regex, dig_output)
386
end
387
388
end
389
390