Created
June 10, 2022 13:31
-
-
Save yuvalif/32ae6d3d57a010d6da4615d506d9c967 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- calculate entropy of an object | |
function object_entropy(full_name) | |
local byte_hist = {} | |
local byte_hist_size = 256 | |
for i = 1,byte_hist_size do | |
byte_hist[i] = 0 | |
end | |
local total = 0 | |
for i, c in pairs(Data) do | |
local byte = c:byte() + 1 | |
byte_hist[byte] = byte_hist[byte] + 1 | |
total = total + 1 | |
end | |
entropy = 0 | |
for _, count in ipairs(byte_hist) do | |
if count ~= 0 then | |
local p = 1.0 * count / total | |
entropy = entropy - (p * math.log(p)/math.log(byte_hist_size)) | |
end | |
end | |
return entropy | |
end | |
function detect_ransomware() [8/4770] | |
if Request.RGWOp ~= 'put_obj' then | |
-- calculate entropy only when uploading an object | |
RGWDebugLog("skipping entropy calculation for "..Request.RGWOp) | |
return | |
end | |
local full_name = Request.Bucket.Name.."\\"..Request.Object.Name | |
local upload_id = Request.HTTP.Parameters["uploadId"] | |
if upload_id ~= nil then | |
if RGW[full_name.."-upload-id"] == upload_id then | |
-- calculate entropy only on the first part of a large object | |
return | |
end | |
RGW[full_name.."-upload-id"] = upload_id | |
end | |
local new_entropy = object_entropy(full_name) | |
if new_entropy == 0 then | |
RGWDebugLog("no data in "..full_name) | |
return | |
end | |
local current_entropy = RGW[full_name.."-entropy"] | |
RGWDebugLog("current entropy of "..full_name.." is "..tostring(current_entropy)) | |
if current_entropy ~= nil then | |
-- object with entropy already exists | |
RGWDebugLog("object "..Request.Object.Name.." updated. entropy changed from "..tostring(current_entropy).." to "..tostring(new_entropy)) | |
local inc_threshold = 0.05 -- 5% increase in object entropy | |
local enc_threshold = 0.5 -- minimum entropy for encryption | |
local bucket_threshold = 0.2 -- if bucket has 20% encrypted files it is quarantines | |
local inc_rate = (new_entropy - current_entropy)/current_entropy | |
if inc_rate > inc_threshold and new_entropy > enc_threshold then | |
RGWDebugLog("entropy of "..full_name.." increased by "..tostring(inc_rate*100).."%") | |
if RGW[Request.Bucket.Name.."-enc-count"] == nil then | |
RGW[Request.Bucket.Name.."-enc-count"] = 1 | |
else | |
RGW.increment(Request.Bucket.Name.."-enc-count") | |
end | |
enc_rate = RGW[Request.Bucket.Name.."-enc-count"]/RGW[Request.Bucket.Name.."-count"] | |
RGWDebugLog(tostring(enc_rate*100).."% of the objects in "..Request.Bucket.Name.." may be encrypted") | |
if enc_rate > bucket_threshold then | |
RGW[Request.Bucket.Name.."-quarantine"] = true | |
end | |
end | |
else | |
RGWDebugLog("new object "..full_name.." uploaded. entropy is "..tostring(new_entropy)) | |
if RGW[Request.Bucket.Name.."-count"] == nil then | |
RGW[Request.Bucket.Name.."-count"] = 1 | |
else | |
RGW.increment(Request.Bucket.Name.."-count") | |
end | |
end | |
RGW[full_name.."-entropy"] = new_entropy | |
end | |
detect_ransomware() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment