--[[ Anti Fake-bot script for PtokaX Версия от 12.03.2017 Автор: Быстрый_ответ cifra.ozerki@gmail.com Постоянная ссылка: https://db.tt/GFSNTkUd Обсуждение: http://dchublist.ru/forum/viewtopic.php?f=6&t=1010 Обнаруживает фэйк-ботов, банит либо блокирует им соединения. Сообщает об этом админу. Сохраняет таблицу блокировок в файл. Принцип обнаружения: ищет в результатах поиска файлы с примерно одинаковым размером. Также см. пояснения ниже. Для начала работы достаточно вписать (sHubIp) IP своего хаба (не доменное имя, а именно IP). Для работы онлайн-режима нужно скачать Curl и положить его в папку "ptokax/curl" Для работы локального детектора нужно указать в настройках PtokaX UDP порт, отличный от нуля. ]] --[[ История изменений 20.08.2015 + скачивание с AVDB - базы RoLex-а + выбор режима работы + возможность банить, а не только блочить 21.08.2015 + уведомления о банах и обновлении базы 07.09.2015 + очистка старых записей 09.09.2015 + сохранение при выходе + очистка памяти + если уже есть бан, то не баним + баним сразу при старте * если баним, то таблицу тоже сохраняем 12.03.2017 * переделаны критерии определения ]] -- НАСТРОЙКИ local iMode = 0 -- Режим работы. 0 - локальный детектор + онлайн-база, 1 - только локальный, 2 - только онлайн local sHubIp = "127.0.0.1" -- изменить на свой IP local iHubUdpPort = SetMan.GetString(4) local sHubBot = SetMan.GetString(21) local AvdbTime = 0 local AvdbTimer = 111 -- Таймер обновления базы, в минутах local AvdbClear = 30 -- Таймер очистки файла базы, в днях local iBan = 1 -- Что делать с обнаруженными ботами. Если число больше 0, то баним на такое кол-во ДНЕЙ. Если 0, то только блочим соединения. local sReason = "Autoban virus-bot" -- Текст для причины бана local fFile = Core.GetPtokaXPath().."scripts/antifake.dat" -- Имя файла для сохранения таблицы блокировок local tPrefix = -- префикс (начало) строки { "100 best","download", "free", "driver", "top 100", "top girl", "18 girl", "sexy girl","top wallpaper", "sexy wallpaper", "anti virus", "0day", "apple","microsoft", "nero","tools", "windows", "office", "adobe", "google", "android", "crack", "patch", "keygen", "serial", "trojan", "torrent", "advanced", "ahead", "collection", "wallpaper", "porn", "ptsc", "pthc", "preteen", "lolita", "sex", "img_ .jpg", "01 .mp3" } local tSuffix = {".exe",".zip",".rar",} -- суффикс (конец) строки -- Скрипт перебирает ВСЕ префиксы и суффиксы и соединяет их в поисковый запрос. -- Соответственно, для выдачи результата нужно подождать какое-то время . local FakeTimer = 30 -- Таймер поиска, в секундах local FakeDiff = 256 -- Разница размера файлов в результатах поиска, в байтах. Увеличение может привести к ложным срабатываниям. local FakeCnt = 50 -- Счетчик ответов на поиск. Если юзер ответил на наш поиск более этого числа раз, то блокируем его. Уменьшение может привести к ложным срабатываниям. tBk = {} OnStartup=function() sSearch,iNum,tFtable,tStrings=false,0,{},{} for _,k in ipairs(tPrefix) do for _,n in ipairs(tSuffix) do table.insert(tStrings,k:gsub (" ", "$")..n) end end if loadfile(fFile) then dofile(fFile) end if not iMode then iMode= 0 end if iMode~=1 then AvdbLoad() TmrMan.AddTimer(AvdbTimer * 60000,"AvdbLoad") end if iMode~=2 then TmrMan.AddTimer(FakeTimer * 1000,"FakeSearch") end Clear() TmrMan.AddTimer(60*60000,"Clear") for _,usr in ipairs(Core.GetOnlineUsers()) do UserConnected(usr) end end UserConnected=function(tUser) if Check(tUser.sNick) then if iBan and iBan>0 then fBan(tUser.sIP) end end end FakeSearch=function() if iNum==#tStrings then FakeStats() iNum=1 else iNum = iNum+1 end sSearch = tStrings[iNum] Core.SendToAll(("$Search %s:%d F?F?0?1?%s|"):format(sHubIp, iHubUdpPort, sSearch)) collectgarbage("collect") end UDPSRArrival=function(tUser, sData) if not sSearch then return false end local n = tUser.sNick --if tBk[n] then return true end local sFile, sSize = sData:match"^$SR [^ ]+ (.-)(%d+) .+" if not sSize then return false end if sFile:lower():find ("part%d+%.rar$") then return false end if sFile and sFile:lower():find(sSearch:sub(1,-6)) then if tFtable[n] then if math.abs(tFtable[n].ls - sSize) < FakeDiff then tFtable[n].cnt=tFtable[n].cnt+1 end tFtable[n].ls=sSize else tFtable[n]={cnt=1,ls=sSize,ip=tUser.sIP,sh=tUser.iShareSize} end end end FakeStats=function() local c = 0 for i,v in pairs(tFtable) do if v.cnt>=FakeCnt then local code = IP2Country.GetCountryCode(v.ip) or "" Say(("%s \t%s \t%s \t%s \t%s"):format("Обнаружен фэйк-бот:",i,v.ip,code,v.cnt) ) table.insert (tBk,{nk=i,ip=v.ip,sh=tonumber(v.sh),t=os.time()}) if iBan and iBan>0 then fBan(v.ip) end c=c+1 end end tFtable={} if c>0 then SaveFile(tBk,"tBk",fFile) Say("Фэйк-ботов заблокировано: "..c) end end ConnectToMeArrival=function(tUser,sData) if iBan and iBan>0 then return false end local sNick = sData:match"^$ConnectToMe (%S+) %S+" if Check(sNick) then return true end end Say=function(msg) Core.SendPmToProfile(0,sHubBot,msg) end SaveFile=function(tab,tablename,file) local f,e = io.open(file,"w") if f then Serialize(tab,tablename,f) f:flush() f:close() else Say(file..", ошибка: ".. e) end end Serialize=function(tTable, sTableName, hFile, sTab) sTab = sTab or ""; hFile:write(sTab..sTableName.." = {\n") for key, value in pairs(tTable) do if type(value)~= "function" then local sKey = (type(key) == "string") and string.format("[%q]",key) or string.format("[%d]",key); if(type(value) == "table") then Serialize(value, sKey, hFile, sTab.."\t"); else local sValue = (type(value) == "string") and string.format("%q",value) or tostring(value); hFile:write(sTab.."\t"..sKey.." = "..sValue); end hFile:write(",\n"); end end hFile:write(sTab.."}"); end string.lower=function(s) return s:gsub('([А-ЯA-Z])', function(str) return string.char(str:byte()+32) end):gsub('Ё', 'ё') end AvdbLoad=function() local buf,rHost,path = "","\"http://www.te-home.net/avdb.php?do=load&time="..AvdbTime.."&cotime=0\"",Core.GetPtokaXPath().."curl/" local file = path.."temp" local command = "curl -m 8 -o "..file.." "..rHost if Core.GetPtokaXPath():byte() ~= 47 then command = path..command end if not os.rename(file,file) then os.execute (command) end local f,e= io.open(file,"rb") if f then buf=f:read("*a") f:close() os.remove(file) --if iMode==2 then tBk={} end if AvdbTime==0 then tBk={} end AvdbTime=os.time() else Say("Can not load AVDB: "..tostring(e)) end local c = 0 for nk,ip,sh in buf:gmatch("(%S+)|(%d+%.%d+%.%d+%.%d+)|(%d+)%s") do table.insert (tBk,{nk=nk,ip=ip,sh=tonumber(sh),t=os.time()}) c = c + 1 end if c>0 then Say("Loaded "..c.." items (total "..#tBk..")") SaveFile(tBk,"tBk",fFile) end end fBan=function(ip) local tab = Core.GetUsers(ip) if tab and #tab > 0 then local t2 = #BanMan.GetTempBan(ip) if t2 == 0 then BanMan.TempBanIP(ip,iBan*1440,sReason,sHubBot,true) for i,v in ipairs(tab) do Core.Disconnect(v.sNick) Say(v.sIP.." с ником "..v.sNick.." был забанен на "..iBan.." дней, наказал "..sHubBot.." по причине: "..sReason) end end end end Clear = function() local c,t,m = 0,os.time(),AvdbClear*86400 for i,v in ipairs(tBk) do if t - m > v.t then tBk[i] = nil c=c+1 end end if c>0 then SaveFile(tBk,"tBk",fFile) Say("AVDB cleared "..c.." items (total "..#tBk..")") end end OnExit=function() SaveFile(tBk,"tBk",fFile) end Check=function(s) local u = Core.GetUser(s) for _,v in ipairs(tBk) do if (v.nk == u.sNick and v.ip == u.sIP) or (v.nk == u.sNick and v.sh == u.iShareSize) or (v.ip == u.sIP and v.sh == u.iShareSize) then return true end end end