-
Notifications
You must be signed in to change notification settings - Fork 9
/
cve-2020-16899.lua
executable file
·83 lines (66 loc) · 2.94 KB
/
cve-2020-16899.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
function init(args)
local needs = {}
needs["packet"] = tostring(true)
return needs
end
function match(args)
local packet = args["packet"]
if packet == nil then
print("Packet buffer empty! Aborting...")
return 0
end
-- SCPacketPayload starts at byte 5 of the ICMPv6 header, so we use the packet buffer instead.
local buffer = SCPacketPayload()
local search_str = string.sub(buffer, 1, 8)
local s, _ = string.find(packet, search_str, 1, true)
local offset = s - 4
-- Only inspect Router Advertisement (Type = 134) ICMPv6 packets.
local type = tonumber(packet:byte(offset))
if type ~= 134 then
return 0
end
-- ICMPv6 Options start at byte 17 of the ICMPv6 payload.
offset = offset + 16
-- Continue looking for Options until we've run out of packet bytes.
while offset < string.len(packet) do
-- We're only interested in DNSSL Options (Type = 31).
local option_type = tonumber(packet:byte(offset))
-- The Option's Length field counts in 8-byte increments, so Length = 2 means the Option is 16 bytes long.
offset = offset + 1
local length = tonumber(packet:byte(offset))
-- The vulnerability is exercised when Length is greater than 35 for a DNSSL Option.
if option_type == 31 and length >= 35 then
-- Move to the DNS Search List field, skipping over Reserved (2 bytes) and Lifetime (4 bytes).
offset = offset + 7
-- Compute the last byte of the Search List and ensure we have enough bytes remaining in our buffer.
local end_of_option = offset + ((length - 1) * 8) - 1
if end_of_option > string.len(packet) then
return 0
end
-- Calculate the length of each DNS name (including padding) and flag any with length >= 264 bytes.
while offset <= end_of_option do
-- Holds the length of the current DNS name being read.
local dns_name_len = 0
-- Count the bytes of the DNS name (non-null).
while offset <= string.len(packet) and tonumber(packet:byte(offset)) ~= 0 do
dns_name_len = dns_name_len + 1
offset = offset + 1
end
-- Count the bytes of the null padding.
while offset <= string.len(packet) and tonumber(packet:byte(offset)) == 0 do
dns_name_len = dns_name_len + 1
offset = offset + 1
end
-- If the total length of the DNS name with padding is 264 bytes or greater, flag the packet.
if dns_name_len >= 264 then
return 1
end
end
-- Otherwise, move to the start of the next Option, if present.
else
offset = offset + (length * 8) - 1
end
end
-- If no malicious data is found, return 0.
return 0
end