aboutsummaryrefslogtreecommitdiff
path: root/wireshark/sharkfest_scripts/http_request_reply_ratio.lua
blob: 6719d2314751b26f546d833dd75cf326d786f2d8 (plain)
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
--
-- (C) 2021 - ntop.org
--
-- This is going to be an example of a lua script that can be written for cybersecurity reasons.
-- HTTP Request/Reply Ratio:
-- the ratio of HTTP requests and replies should be alwais close to 1, because, if not, usually means
-- that there are problems with the client that is sending the requests or there are problems with
-- the server that should receive those requests.

local f_http = Field.new("http")
local f_http_request = Field.new("http.request")
local f_http_reply = Field.new("http.response")
local f_ip_src = Field.new("ip.src")
local f_ip_dst = Field.new("ip.dst")

--############################################

local function getstring(finfo)
	local ok, val = pcall(tostring, finfo)
	if not ok then val = "(unknown)" end
	return val
end

--############################################

local function processResponse(http_table, req_or_rep, src, dst)
    local key = src .. " -> " .. dst

    -- Create the table entry if needed
    if not http_table[key] then
        http_table[key] = {
            requests = 0,
            replies = 0,
        }
    end

    -- Increase the stats
    http_table[key][req_or_rep] = http_table[key][req_or_rep] + 1

    return http_table
end

--############################################

local function processPackets(pinfo,tvb, http_table) 
    -- Call the function that extracts the field
    local http_traffic = f_http()
    local http_request = f_http_request()
    local http_reply = f_http_reply()

    --Check if there is an HTTP request or reply
    if http_traffic then
        if http_request then
            local src = getstring(f_ip_src().value)
            local dst = getstring(f_ip_dst().value)

            http_table = processResponse(http_table, "requests", src, dst)
        elseif http_reply then
            local dst = getstring(f_ip_src().value)
            local src = getstring(f_ip_dst().value)

            http_table = processResponse(http_table, "replies", src, dst)
        end
    end

    return http_table
end

--############################################

local function httpReqRepRatio()
	-- Declare the window we will use
	local tw = TextWindow.new("HTTP Request/Reply Ratio")

	local http_table = {}

	local tap = Listener.new();

	local function removeListener()
		-- This way we remove the listener that otherwise will remain running indefinitely
		tap:remove();
	end

	-- We tell the window to call the remove() function when closed
	tw:set_atclose(removeListener)

	-- This function will be called once for each packet
	function tap.packet(pinfo,tvb)
        http_table = processPackets(pinfo,tvb, http_table)
	end

	-- This function will be called once every few seconds to update our window
	function tap.draw(t)
		tw:clear()
		
        local dangerous_flows = {}
        local ok_flows = {}

        for flow, data in pairs(http_table) do
			local requests = http_table[flow]["requests"]
			local replies = http_table[flow]["replies"]
            local ratio = 0
            local danger = ""

            if replies == 0 then
                ratio = 0
            else
                ratio = requests/replies
            end

            if ratio ~= 1 then
                dangerous_flows[#dangerous_flows + 1] = data
                dangerous_flows[#dangerous_flows]["flow"] = flow
                dangerous_flows[#dangerous_flows]["ratio"] = ratio
            else
                ok_flows[#ok_flows + 1] = data
                ok_flows[#ok_flows]["flow"] = flow
                ok_flows[#ok_flows]["ratio"] = ratio
            end
		end

        if #dangerous_flows > 0 then
            tw:append("------------- DETECTED HTTP REQUEST/REPLY RATIO -------------\n\n")
            tw:append("TOT SUSPICIOUS FLOWS DETECTED:\t" .. #dangerous_flows .. " -------------\n")
        else
            tw:append("------------- HTTP REQUEST/REPLY RATIO SEEMS FINE -------------\n\n")
        end

        tw:append("TOTAL HTTP FLOWS DETECTED:\t\t" .. #dangerous_flows + #ok_flows .. " -------------\n\n")
        
        for _, data in pairs(dangerous_flows) do
            local flow = data["flow"]
			local requests = data["requests"]
			local replies = data["replies"]
            local ratio = data["ratio"]

            tw:append(flow .. ":\n\tRatio:\t\t" .. (ratio) .. "\n\tRequests:\t\t" .. requests .. "\n\tReplies:\t\t" .. replies .. "\n\n");
        end
	end

	-- This function will be called whenever a reset is needed
	-- e.g. when reloading the capture file
	function tap.reset()
		tw:clear()
		http_table = {}
	end

	-- Ensure that all existing packets are processed.
	retap_packets()
end

-- Register the menu Entry
register_menu("Sharkfest/HTTP Request-Reply Ratio", httpReqRepRatio, MENU_TOOLS_UNSORTED)