|
json = require "cjson.safe"
|
|
md5 = require "md5"
|
|
|
|
-- log_info
|
|
app_type = "web"
|
|
event_type = "lua"
|
|
event_name = "http"
|
|
name = "web_http_audit.json"
|
|
|
|
-- web_info
|
|
login_url = "/login"
|
|
success_code = 0
|
|
|
|
-- common_mapping
|
|
http_common_mapping = '{"accept":"accept","accept-charset":"accept_charset","accept-encoding":"accept_encoding","accept-language":"accept_language","accept-datetime":"accept_datetime","authorization":"authorization","cache-control":"cache_control","from":"from","max-forwards":"max_forwards","origin":"origin","pragma":"pragma","proxy-authorization":"proxy_authorization","via":"via","vary":"vary","x-requested-with":"x_requested_with","x-forwarded-proto":"x_forwarded_proto","accept-range":"accept_range","allow":"allow","connection":"connection","content-encoding":"content_encoding","content-language":"content_language","content-location":"content_location","content-md5":"content_md5","content-range":"content_range","date":"date","last-modified":"last_modified","location":"location","proxy-authenticate":"proxy_authenticate","referrer":"refer","retry-after":"retry_after","server":"server","transfer-encoding":"transfer_encoding","upgrade":"upgrade","www-authenticate":"www_authenticate","x-authenticated-user":"x_authenticated_user","x-forwarded-for":"xff","x-real-ip":"x_real_ip"}'
|
|
common_mapping_table = json.decode(http_common_mapping)
|
|
|
|
-- request_mapping
|
|
http_request_mapping = '{"content-length":"request_content_length","content-type":"request_content_type","appversion":"app_version","usercountry":"user_country","localcountry":"local_country","device":"device","devtype":"device_type","deviceid":"device_id","canvas":"canvas","webgl":"webgl","x-ftoken":"x-ftoken"}'
|
|
|
|
request_mapping_table = json.decode(http_request_mapping)
|
|
|
|
-- response_mapping
|
|
http_response_mapping = '{"content-length":"response_content_length","content-type":"response_content_type"}'
|
|
response_mapping_table = json.decode(http_response_mapping)
|
|
|
|
-- bypass_host
|
|
bypass_host = {
|
|
"www.test1.com",
|
|
"www.test2.com"
|
|
}
|
|
|
|
-- bypass_url
|
|
bypass_url = {
|
|
"/bypass_1.html",
|
|
"/bypass_2.html"
|
|
}
|
|
|
|
-- bypass_ua
|
|
bypass_ua = {
|
|
"Cloudflare-Traffic-Manager"
|
|
}
|
|
|
|
-- request_session_id_pattern
|
|
session_id_pattern = {
|
|
"sessionID-1_=(.-);",
|
|
"sessionID-2_=(.-);"
|
|
}
|
|
|
|
-- defind function
|
|
function md5Encode(args)
|
|
m = md5.new()
|
|
m:update(args)
|
|
return md5.tohex(m:finish())
|
|
end
|
|
|
|
function urlDecode(args)
|
|
s = string.gsub(args, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end)
|
|
return s
|
|
end
|
|
|
|
function string.split(s, p)
|
|
rt = {}
|
|
string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end )
|
|
return rt
|
|
end
|
|
|
|
function string.trim(s)
|
|
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
|
|
end
|
|
|
|
function formatBody(args)
|
|
t = {}
|
|
data = string.split(args, '&')
|
|
for n, v in ipairs(data) do
|
|
d = string.split(v, '=')
|
|
t[d[1]] = d[2]
|
|
end
|
|
return t
|
|
end
|
|
|
|
|
|
-- default funtion
|
|
function init(args)
|
|
local needs = {}
|
|
needs["protocol"] = "http"
|
|
return needs
|
|
end
|
|
|
|
function setup(args)
|
|
filename = SCLogPath() .. "/" .. name
|
|
file = assert(io.open(filename, "a"))
|
|
SCLogInfo("web_http_audit filename: " .. filename)
|
|
http = 0
|
|
end
|
|
|
|
function log(args)
|
|
|
|
-- init tables
|
|
http_table = {}
|
|
|
|
http_hostname = HttpGetRequestHost()
|
|
if http_hostname then
|
|
if string.match(http_hostname, "test1") == nil and string.match(http_hostname, "test2") == nil then
|
|
return
|
|
end
|
|
for _, host in ipairs(bypass_host) do
|
|
if http_hostname == host then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
http_table["hostname"] = http_hostname
|
|
|
|
http_ua = HttpGetRequestHeader("User-Agent")
|
|
if http_ua then
|
|
for _, ua in ipairs(bypass_ua) do
|
|
if string.match(http_ua, ua) then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
http_table["user_agent"] = http_ua
|
|
|
|
http_url = HttpGetRequestUriNormalized()
|
|
for _, url in ipairs(bypass_url) do
|
|
if url == http_url then
|
|
return
|
|
end
|
|
end
|
|
http_table["url"] = http_url
|
|
|
|
if http_url then
|
|
http_url_path = string.split(http_url, "?")[1]
|
|
http_table["url_path"] = http_url_path
|
|
end
|
|
|
|
rl = HttpGetRequestLine()
|
|
if rl then
|
|
http_method = string.match(rl, "%w+")
|
|
http_table["method"] = http_method
|
|
end
|
|
|
|
rsl = HttpGetResponseLine()
|
|
if rsl then
|
|
status_code = string.match(rsl, "%s(%d+)%s")
|
|
http_table["status"] = tonumber(status_code)
|
|
|
|
http_protocol = string.match(rsl, "(.-)%s")
|
|
http_table["protocol"] = http_protocol
|
|
end
|
|
|
|
cookie = HttpGetRequestHeader("Cookie")
|
|
http_table["cookie"] = cookie
|
|
|
|
set_cookie = HttpGetResponseHeader("Set-Cookie")
|
|
http_table["set_cookie"] = set_cookie
|
|
|
|
---[[
|
|
if cookie then
|
|
--[[
|
|
-- request_token
|
|
for _, pattern in ipairs(session_id_pattern) do
|
|
session_id = string.match(cookie, pattern)
|
|
if session_id then
|
|
http_table["token"] = md5Encode(session_id)
|
|
break
|
|
end
|
|
end
|
|
--]]
|
|
|
|
-- request_member_id
|
|
request_member_id = string.match(cookie, "memberId=(.-);")
|
|
if request_member_id then
|
|
http_table["member_id"] = tonumber(request_member_id)
|
|
end
|
|
|
|
-- email
|
|
userinfo_email = string.match(cookie, "userinfo_email=(.-);")
|
|
if userinfo_email then
|
|
http_table["email"] = urlDecode(userinfo_email)
|
|
end
|
|
end
|
|
|
|
if set_cookie then
|
|
-- response_token
|
|
--[[
|
|
for _, pattern in ipairs(session_id_pattern) do
|
|
session_id = string.match(set_cookie, pattern)
|
|
if session_id then
|
|
http_table["token"] = md5Encode(session_id)
|
|
break
|
|
end
|
|
end
|
|
--]]
|
|
|
|
-- response_member_id
|
|
response_member_id = string.match(set_cookie, "memberId=(.-);")
|
|
if response_member_id then
|
|
http_table["member_id"] = tonumber(response_member_id)
|
|
end
|
|
|
|
-- userinfo_email
|
|
userinfo_email = string.match(set_cookie, "userinfo_email=(.-);")
|
|
if userinfo_email then
|
|
http_table["email"] = urlDecode(userinfo_email)
|
|
end
|
|
end
|
|
|
|
--]]
|
|
|
|
-- login_audit
|
|
if http_url == login_url and http_method == "POST" then
|
|
-- token && member_id
|
|
if set_cookie then
|
|
session_id = string.match(set_cookie, "sessionID=(.-);")
|
|
if session_id then
|
|
http_table["token"] = md5Encode(session_id)
|
|
member_id = string.match(set_cookie, "memberId=(.-);")
|
|
if member_id then
|
|
http_table["member_id"] = tonumber(member_id)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- login_results
|
|
a, o, e = HttpGetResponseBody()
|
|
if a then
|
|
for n, v in ipairs(a) do
|
|
body = json.decode(v)
|
|
results_code = tonumber(body["code"])
|
|
if results_code == success_code then
|
|
results = "success"
|
|
else
|
|
results = "failed"
|
|
end
|
|
end
|
|
http_table["results"] = results
|
|
http_table["results_code"] = results_code
|
|
end
|
|
|
|
-- login_email
|
|
a, o, e = HttpGetRequestBody()
|
|
if a then
|
|
for n, v in ipairs(a) do
|
|
res = formatBody(v)
|
|
if res['email'] then
|
|
http_table["email"] = urlDecode(res['email'])
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- RequestHeaders
|
|
rh = HttpGetRequestHeaders()
|
|
if rh then
|
|
for k, v in pairs(rh) do
|
|
key = string.lower(k)
|
|
|
|
common_var = common_mapping_table[key]
|
|
if common_var then
|
|
http_table[common_var] = v
|
|
end
|
|
|
|
request_var = request_mapping_table[key]
|
|
if request_var then
|
|
http_table[request_var] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ResponseHeaders
|
|
rsh = HttpGetResponseHeaders()
|
|
if rsh then
|
|
for k, v in pairs(rsh) do
|
|
key = string.lower(k)
|
|
|
|
common_var = common_mapping_table[key]
|
|
if common_var then
|
|
http_table[common_var] = v
|
|
end
|
|
|
|
response_var = response_mapping_table[key]
|
|
if response_var then
|
|
http_table[response_var] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- timestring = SCPacketTimeString() 2019-09-10T06:08:35.582449+0000
|
|
sec, usec = SCPacketTimestamp()
|
|
timestring = os.date("!%Y-%m-%dT%T", sec) .. '.' .. usec .. '+0000'
|
|
|
|
-- flow_info
|
|
ip_version, src_ip, dst_ip, protocol, src_port, dst_port = SCFlowTuple()
|
|
|
|
-- flow_id
|
|
id = SCFlowId()
|
|
flow_id = string.format("%.0f", id)
|
|
flow_id = tonumber(flow_id)
|
|
|
|
-- alerts
|
|
has_alerts = SCFlowHasAlerts()
|
|
|
|
-- true_client_ip
|
|
true_client_ip = HttpGetRequestHeader("True-Client-IP")
|
|
if true_client_ip then
|
|
http_table["proxy_ip"] = src_ip
|
|
http_table["true_client_ip"] = true_client_ip
|
|
src_ip = true_client_ip
|
|
end
|
|
|
|
-- session_id
|
|
tetrad = src_ip .. src_port .. dst_ip .. dst_port
|
|
session_id = md5Encode(tetrad)
|
|
|
|
-- table
|
|
raw_data = {
|
|
timestamp = timestring,
|
|
flow_id = flow_id,
|
|
session_id = session_id,
|
|
src_ip = src_ip,
|
|
src_port = src_port,
|
|
proto = "TCP",
|
|
dest_ip = dst_ip,
|
|
dest_port = dst_port,
|
|
event_name = event_name,
|
|
event_type = event_type,
|
|
app_type = app_type,
|
|
http = http_table,
|
|
alerted = has_alerts
|
|
}
|
|
|
|
-- json encode
|
|
data = json.encode(raw_data)
|
|
|
|
-- write_data
|
|
file:write(data .. "\n")
|
|
file:flush()
|
|
|
|
http = http + 1
|
|
end
|
|
|
|
function deinit (args)
|
|
SCLogInfo ("web_http_audit transactions logged: " .. http);
|
|
file:close(file)
|
|
end
|