This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 0e770b2b49
commit 94063e4369
7342 changed files with 1718932 additions and 14 deletions

View File

@@ -0,0 +1,137 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if (SERVER) then
util.AddNetworkString("ixBindGrab")
util.AddNetworkString("ixBindGrabList")
end
CAMI.RegisterPrivilege({
Name = "Helix - Check Bind",
MinAccess = "superadmin"
})
ix.command.Add("PlyGetBinds", {
description = "Get a list of all of someone's binds.",
privilege = "Check Bind",
arguments = {ix.type.player, bit.bor(ix.type.optional, ix.type.bool)},
OnRun = function(self, client, target, all)
if (IsValid(target.ixBindGrab) and target.ixBindGrabTime and target.ixBindGrabTime > CurTime()) then
return "Someone else is checking this player's binds already. Please wait a few seconds!"
end
target.ixBindGrab = client
target.ixBindGrabTime = CurTime() + 5
target.ixBindGrabAll = all
net.Start("ixBindGrab")
net.Send(target)
end,
bNoIndicator = true
})
if (CLIENT) then
net.Receive("ixBindGrab", function()
net.Start("ixBindGrab")
for i = 1, BUTTON_CODE_LAST do
net.WriteString(string.Left(input.LookupKeyBinding(i) or "", 255))
end
net.SendToServer()
end)
local blacklist = {
["slot0"] = true,
["slot1"] = true,
["slot2"] = true,
["slot3"] = true,
["slot4"] = true,
["slot5"] = true,
["slot6"] = true,
["slot7"] = true,
["slot8"] = true,
["slot9"] = true,
["+zoom"] = true,
["+forward"] = true,
["+back"] = true,
["+moveleft"] = true,
["+moveright"] = true,
["+jump"] = true,
["+speed"] = true,
["+walk"] = true,
["+duck"] = true,
["+lookup"] = true,
["+left"] = true,
["+lookdown"] = true,
["+right"] = true,
["+attack"] = true,
["+attack2"] = true,
["+reload"] = true,
["+use"] = true,
["invprev"] = true,
["invnext"] = true,
["+menu"] = true,
["+menu_context"] = true,
["gmod_undo"] = true,
["+showscores"] = true,
["gm_showhelp"] = true,
["gm_showteam"] = true,
["gm_showspare1"] = true,
["gm_showspare2"] = true,
["noclip"] = true,
["messagemode"] = true,
["toggleconsole"] = true,
["cancelselect"] = true,
["pause"] = true,
["save quick"] = true,
["load quick"] = true,
["impulse 100"] = true,
["+voicerecord"] = true,
["jpeg"] = true,
}
net.Receive("ixBindGrabList", function()
local all = net.ReadBool()
MsgN(net.ReadString().."'s binds ("..net.ReadString()..")")
for i = 1, BUTTON_CODE_LAST do
local bind = net.ReadString()
if (!all and blacklist[bind]) then continue end
if (bind and bind != "") then
if (#bind == 255) then
bind = bind.."..."
end
MsgN((input.GetKeyName(i) or i)..": ", bind)
end
end
LocalPlayer():Notify("Binds were printed in console!")
end)
else
net.Receive("ixBindGrab", function(len, client)
if (!IsValid(client.ixBindGrab) or !CAMI.PlayerHasAccess(client.ixBindGrab, "Helix - Check Bind")) then return end
net.Start("ixBindGrabList")
net.WriteBool(client.ixBindGrabAll)
net.WriteString(client:SteamName())
net.WriteString(client:SteamID())
for i = 1, BUTTON_CODE_LAST do
net.WriteString(string.Left(net.ReadString(), 255))
end
net.Send(client.ixBindGrab)
client.ixBindGrab = nil
end)
end

View File

@@ -0,0 +1,507 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local pcall = pcall
local util = util
local ix = ix
local string = string
local net = net
local ipairs = ipairs
local IsValid = IsValid
local os = os
local L = L
local math = math
local table = table
local pairs = pairs
local print = print
local CHTTP = CHTTP
local player = player
local CAMI = CAMI
if (!CHTTP) then
pcall(require, "chttp")
end
local PLUGIN = PLUGIN
PLUGIN.TYPE_UNKNOWN = 1
PLUGIN.TYPE_KNOWN = 2
local COOKIE_KEY = "qvFT4QSSST8K4tZF"
local fileChecks = {
{"hl2_misc_001.vpk", "hl2"},
{"ep2_pak_008.vpk", "ep2"},
{"cstrike_pak_003.vpk", "css", "cstrike"},
{"bin/client_panorama.dll", "csgo"},
{"detail.vbsp", "gmod", "garrysmod"}
}
util.AddNetworkString("RecieveDupe")
ix.util.Include("sv_antialt_db.lua")
ix.lang.AddTable("english", {
altSignupProxy = "Vous essayez de rejoindre Willard Networks en tant que nouvel utilisateur tout en utilisant un proxy ou un VPN. Pour lutter contre les autres comptes, nous ne l'autorisons pas.\n\nVeuillez désactiver votre proxy/VPN et rejoindre le serveur. Après avoir rejoint le serveur avec succès une fois, vous pouvez réactiver votre proxy/VPN pour de futures visites.\n\nSi vous n'utilisez pas de proxy ou de VPN, veuillez contacter un membre de l'équipe du STAFF sur nos forums ou discord"
})
ix.log.AddType("altNewClient", function(client)
return string.format("[AltChecker] %s rejoint pour la première fois.", client:SteamName())
end)
ix.log.AddType("altKnownNewCookie", function(client)
return string.format("[AltChecker] %s rejoint avec une installation inconnue.", client:SteamName())
end)
ix.log.AddType("altKnownCookieMatched", function(client, matched, total)
return string.format("[AltChecker] %s rejoint sans cookie, mais l'installation correspond au cookie existant. %d/%d", client:SteamName(), matched, total)
end)
hook.Add("PlayerInitialSpawn", "bastionAntiAlt", function(client)
if (client:IsBot()) then return end
client.ixAltData = {
checks = 4 + #fileChecks,
altLogging = 0,
error = false,
received = false,
checkComplete = false,
newAltFound = false,
mode = 0,
localCookie = "",
cookies = false,
ip = false,
timestamps = false,
otherCookies = {},
otherIPs = {},
otherTimestamps = {},
otherTimestampsNZ = {},
otherTimeMatches = {},
discordAlert = {
cookies = {},
timestamps = {},
ips = {},
altIDs = {}
}
}
-- Lookup user data
PLUGIN:AltLoadUserData(client)
if (PLUGIN.API_KEY) then
-- Lookup user IP
PLUGIN:AltLookupIP(client)
else
client.ixAltData.checkes = client.ixAltData.checks - 1
end
-- Check for IP matches
PLUGIN:AltLookupIPMatches(client)
-- Request cookie and install timestamps
PLUGIN:RequestClientData(client)
end)
function PLUGIN:RequestClientData(client)
net.Start("RecieveDupe")
net.WriteUInt(1, 3)
net.WriteString(COOKIE_KEY)
for _, v in ipairs(fileChecks) do
net.WriteString(v[1])
net.WriteString(v[3] or v[2])
end
net.Send(client)
end
net.Receive("RecieveDupe", function(len, client)
if (!IsValid(client) or !client.ixAltData or client.ixAltData.received) then return end
local data = client.ixAltData
data.received = true
-- set cookie
data.localCookie = net.ReadString()
-- set file timestamps
data.timestamps = {}
for i = 1, #fileChecks do
data.timestamps[i] = net.ReadUInt(32)
end
-- Check for cookie matches
if (data.localCookie != "") then
PLUGIN:AltLookupCookieMatches(client, data)
else
PLUGIN:AltPreFinalChecking(client)
end
-- Check for install timestamp matches
data.otherTimestamps = {}
data.otherTimestampsNZ = {}
for i = 1, #fileChecks do
PLUGIN:AltLookupTimestampMatches(client, data, fileChecks[i][2], data.timestamps[i])
end
end)
function PLUGIN:AltPreFinalChecking(client)
if (!IsValid(client)) then return end
local data = client.ixAltData
-- if we errored, don't do anything
-- check will be reexecuted when the client rejoins
if (data.error) then return end
-- check if all queries finished
data.checks = data.checks - 1
if (data.checks != 0) then return end
-- cookie matches (STRONG)
if (#data.otherCookies > 0) then
for _, v in ipairs(data.otherCookies) do
self:AltFound(client, v[2], "cookie", "cookie")
data.discordAlert.cookies[#data.discordAlert.cookies + 1] = (v[2] or "").." ("..(v[1] or "")..")"
data.discordAlert.altIDs[v[2]] = true
end
end
-- IP (WEAK)
if (#data.otherIPs > 0) then
for _, v in ipairs(data.otherIPs) do
data.discordAlert.ips[#data.discordAlert.ips + 1] = v[2]
data.discordAlert.altIDs[v[2]] = true
end
end
-- time matches (STRONG-MEDIUM)
self:AggregateTimestampMatches(data)
-- If no local cookie and player is known, check if a known cookie was time-matched
if (data.localCookie == "" and data.mode == self.TYPE_KNOWN) then
self:FindMatchingCookie(client, data)
end
if (#data.otherTimeMatches > 0) then
-- go looking for the other clients that own our matched timestamps
self:AltLookupCookieForTimestamps(client, data, #fileChecks)
else
-- else we don't need to wait for the lookup above
data.checkComplete = true
self:AltFinalChecking(client)
end
end
function PLUGIN:AltFinalChecking(client)
if (!IsValid(client)) then return end
local data = client.ixAltData
if (!data.checkComplete or data.altLogging != 0) then return end
self:DiscordAlert(client)
-- update IP list
local steamID = client:SteamID64()
local ip = self.GetIPAddress(client)
local query = mysql:Select("bastion_antialt_userips")
query:Where("steamid", steamID)
query:Where("ip", ip)
query:Callback(function(result)
if (!result or #result == 0) then
local query2 = mysql:Insert("bastion_antialt_userips")
query2:Insert("steamid", steamID)
query2:Insert("ip", ip)
query2:Insert("last_seen", os.time())
query2:Execute()
else
local query2 = mysql:Update("bastion_antialt_userips")
query2:Where("id", result[1].id)
query2:Update("last_seen", os.time())
query2:Execute()
end
end)
query:Execute()
-- Kick if new player on proxy/vpn
if (data.mode == self.TYPE_UNKNOWN) then
if (self.API_KEY and (data.ip.proxy == "yes" or (data.ip.risk or 0) > 60)) then
if (ix.config.Get("VPNKick")) then
self:ProxyAlert(client)
client:Kick(L("altSignupProxy", client))
else
if (!self:NotifyProxyJoin(client) or ix.config.Get("ProxyAlwaysAlert")) then
self:ProxyAlert(client)
end
end
elseif (data.localCookie == "") then
ix.log.Add(client, "altNewClient")
self:GenerateCookie(client, data)
else
-- Update the cookie's timestamps
self:StoreCookieInfo(data, fileChecks)
-- Add this cookie to client as well so it can be time matched/timestamps updated
self:StoreClientCookie(client, data)
end
elseif (data.localCookie == "") then
ix.log.Add(client, "altKnownNewCookie")
self:GenerateCookie(client, data)
else
-- Update the cookie's timestamps
self:StoreCookieInfo(data, fileChecks)
-- Add this cookie to client as well so it can be time matched/timestamps updated
self:StoreClientCookie(client, data)
end
if (sam) then
timer.Simple(3, function()
if (!IsValid(client)) then return end
local query1 = mysql:Select("bastion_antialt_alts")
query1:Where("steamid", client:SteamID64())
query1:Select("alt_id")
query1:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then return end
local query2 = mysql:Select("bastion_antialt_alts")
query2:Where("alt_id", result[1].alt_id)
query2:WhereNotEqual("steamid", client:SteamID64())
query2:Select("steamid")
query2:Callback(function(result2)
if (!IsValid(client)) then return end
if (!result2 or #result2 == 0) then return end
for k, v in ipairs(result2) do
sam.player.is_banned(util.SteamIDFrom64(v.steamid), function(banned)
if (!banned or !IsValid(client)) then return end
client:Kick("You have a banned alt account.")
return
end)
end
end)
query2:Execute()
end)
query1:Execute()
end)
end
end
--[[
COOKIE STUFF
]]
function PLUGIN:WhitelistPlayer(client)
local data = client.ixAltData
if (!data) then return end
if (data.localCookie) then
ix.log.Add(client, "altNewClient")
self:GenerateCookie(client, data)
return true
end
end
function PLUGIN.RandomString()
local result = {} -- The empty table we start with
while (#result != 64) do
local char = string.char(math.random(32, 126))
if (string.find(char, "%w")) then
result[#result + 1] = char
end
end
return table.concat(result)
end
function PLUGIN:GenerateCookie(client, data)
local cookie = self.RandomString()
self:UpdateLocalCookie(client, data, cookie)
local query = mysql:Insert("bastion_antialt_users")
query:Insert("steamid", client:SteamID64())
query:Insert("steam_name", client:SteamName())
query:Insert("cookie", cookie)
query:Execute()
end
function PLUGIN:UpdateLocalCookie(client, data, cookie)
data.localCookie = cookie
net.Start("RecieveDupe")
net.WriteUInt(2, 3)
net.WriteString(COOKIE_KEY)
net.WriteString(cookie)
net.Send(client)
self:StoreCookieInfo(data, fileChecks)
end
function PLUGIN:FindMatchingCookie(client, data)
for _, v in ipairs(data.otherTimeMatches) do
for _, v1 in ipairs(data.cookies) do
if (v1.cookie == v[1]) then
-- found a timestamp match belonging to the client, restore cookie
-- in case of e.g. gmod reinstall
ix.log.Add(client, "altKnownCookieMatched", v[2], #fileChecks)
self:UpdateLocalCookie(client, data, v[1])
return
end
end
end
end
--[[
LOGGING AND ALERTING
]]
local ALT_OFFSET = 0
function PLUGIN:AltFound(client, steamid, type, info)
local ids = {client:SteamID64(), steamid}
local data = client.ixAltData
data.altLogging = data.altLogging + 1
local query = mysql:Select("bastion_antialt_alts")
query:WhereIn("steamid", ids)
query:Callback(function(result)
if (!result or #result == 0) then
local alt_id = os.time() + ALT_OFFSET
ALT_OFFSET = ALT_OFFSET + 1
local text = table.concat(ids,"+")..": "..info.." (alt-id: "..alt_id..")"
self:InsertNewAlt(ids[1], alt_id, type, text)
self:InsertNewAlt(steamid, alt_id, type, text)
data.newAltFound = true
elseif (#result == 1) then
self:InsertNewAlt(
result[1].steamid == steamid and ids[1] or steamid,
result[1].alt_id,
type,
table.concat(ids,"+")..": "..info.." (alt-id: "..result[1].alt_id..")"
)
data.newAltFound = true
elseif (result[2].alt_id != result[1].alt_id) then
self:MergeAlts(
result[2].alt_id,
result[1].alt_id,
table.concat(ids,"+")..": "..info.." (alt-id: "..result[1].alt_id..")"
)
data.newAltFound = true
end
data.altLogging = data.altLogging - 1
self:AltFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:DiscordAlert(client)
if (!self.DISCORD_WEBHOOK_ALTS or self.DISCORD_WEBHOOK_ALTS == "") then return end
local data = client.ixAltData
if (!data.newAltFound) then return end
local tbl = {
embeds = {{
title = "Alt found for "..client:SteamName(),
description = "An alt account match was found for **"..client:SteamName().."** (*"..client:SteamID64().."*)\n\n__COOKIE__: 99.99% certainty via installed cookie\nShown as 'SteamID64 (SteamName)'\n__TIMESTAMP__: check via installation date/time or absense of mounted games (hl2,ep2,css,csgo,gmod)\nMore matches = more certainty, especially if all/most are installed\nShown as 'SteamID64 (SteamName; date/time matches - installed matches)'\n__IP__: users that connected from the same IP address at any point\nShown as 'SteamID64'",
color = 13632027,
timestamp = os.date("%Y-%m-%d %X%z"),
footer = {
text = "Bastion Alt Checker for GMod by Gr4Ss"
},
author = {
name = "Bastion Alt Checker"
},
fields = {
}
}}
}
if (data.discordAlert.cookies and #data.discordAlert.cookies > 0) then
table.insert(tbl.embeds[1].fields, {name = "COOKIE", value = table.concat(data.discordAlert.cookies, "\n")})
end
if (data.discordAlert.timestamps and #data.discordAlert.timestamps > 0) then
table.insert(tbl.embeds[1].fields, {name = "TIMESTAMP", value = table.concat(data.discordAlert.timestamps, "\n")})
end
if (data.discordAlert.ips and #data.discordAlert.ips > 0) then
table.insert(tbl.embeds[1].fields, {
name = "IP",
value = string.format("Address: [%s](https://proxycheck.io/threats/%s)\n", data.ipAddress, data.ipAddress)..
table.concat(data.discordAlert.ips, "\n")
})
end
local ipLinks = {"["..client:SteamID64().."](https://steamidfinder.com/lookup/"..client:SteamID64().."/)"}
for k in pairs(data.discordAlert.altIDs) do
ipLinks[#ipLinks + 1] = "["..k.."](https://steamidfinder.com/lookup/"..k.."/)"
end
table.insert(tbl.embeds[1].fields, {
name = "SteamID Finder Links",
value = table.concat(ipLinks,"\n")
})
for _, field in ipairs(tbl.embeds[1].fields) do
if (string.len(field.value) > 1024) then
field.value = string.sub(field.value, 1, 1024)
end
end
local request = {
failed = function(error) print("discord error", error) end,
success = function(code, body, headers)
if (code != 200) then print("discord error", code, body) end
end,
method = "post",
url = self.DISCORD_WEBHOOK_ALTS,
body = util.TableToJSON(tbl),
type = "application/json; charset=utf-8"
}
CHTTP(request)
end
function PLUGIN:ProxyAlert(client)
if (!self.DISCORD_WEBHOOK_ALTS or self.DISCORD_WEBHOOK_ALTS == "") then return end
local ip, steamID = client.ixAltData.ipAddress, client:SteamID64()
local tbl = {
embeds = {{
title = "New player using VPN - "..client:SteamName(),
description = client:SteamName().." joined WN for the first time, but was using a proxy/VPN. They have been kicked.\n\n"..
string.format("More info: [%s](https://proxycheck.io/threats/%s) & [%s](https://steamidfinder.com/lookup/%s/)", ip, ip, steamID, steamID),
color = 16312092,
timestamp = os.date("%Y-%m-%d %X%z"),
footer = {
text = "Bastion Alt Checker for GMod by Gr4Ss"
},
author = {
name = "Bastion Alt Checker"
}
}}
}
local request = {
failed = function(error) print("discord error", error) end,
method = "post",
url = self.DISCORD_WEBHOOK_ALTS,
body = util.TableToJSON(tbl),
type = "application/json; charset=utf-8"
}
CHTTP(request)
end
function PLUGIN:NotifyProxyJoin(client)
local bSend = false
for _, v in ipairs(player.GetAll()) do
if (CAMI.PlayerHasAccess(v, "Helix - Proxy Notify")) then
bSend = true
v:NotifyLocalized("bastionProxyNotify", client:SteamName())
end
end
return bSend
end

View File

@@ -0,0 +1,461 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local IsValid = IsValid
local string = string
local os = os
local print = print
local util = util
local CHTTP = CHTTP
local ipairs = ipairs
local table = table
local pairs = pairs
local netstream = netstream
local SortedPairsByMemberValue = SortedPairsByMemberValue
local PLUGIN = PLUGIN
local MAX_CACHE_AGE = 7 * 24 * 3600 -- 7 days
PLUGIN.ipCache = {}
hook.Add("DatabaseConnected", "bastionAntiAlt", function()
local query = mysql:Create("bastion_antialt_users")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("steam_name", "VARCHAR(128) NOT NULL")
query:Create("cookie", "VARCHAR(64) NOT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_antialt_cookies")
query:Create("cookie", "VARCHAR(64) NOT NULL")
query:Create("ts_hl2", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_ep2", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_css", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_csgo", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_gmod", "INT(11) UNSIGNED DEFAULT NULL")
query:PrimaryKey("cookie")
query:Execute()
query = mysql:Create("bastion_antialt_userips")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("ip", "VARCHAR(15) NOT NULL")
query:Create("last_seen", "INT(11) UNSIGNED NOT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_antialt_ip")
query:Create("ip", "VARCHAR(15) NOT NULL")
query:Create("updated", "INT(11) UNSIGNED NOT NULL")
query:Create("asn", "VARCHAR(12) NOT NULL")
query:Create("provider", "VARCHAR(128) NOT NULL")
query:Create("isocode", "VARCHAR(2) NOT NULL")
query:Create("proxy", "TINYINT(1) UNSIGNED DEFAULT 0")
query:Create("type", "VARCHAR(32) NOT NULL")
query:Create("risk", "INT UNSIGNED NOT NULL")
query:Create("attack_count", "INT UNSIGNED DEFAULT NULL")
query:Create("attack_history", "TEXT DEFAULT NULL")
query:PrimaryKey("ip")
query:Execute()
query = mysql:Create("bastion_antialt_alts")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("alt_id", "INT UNSIGNED NOT NULL")
query:Create("type", "VARCHAR(10) NOT NULL")
query:Create("info", "TEXT NOT NULL")
query:PrimaryKey("steamid")
query:Execute()
end)
function PLUGIN:AltLoadUserData(client)
local query = mysql:Select("bastion_antialt_users")
query:Where("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client.ixAltData.mode = self.TYPE_UNKNOWN
else
client.ixAltData.mode = self.TYPE_KNOWN
client.ixAltData.cookies = result
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN.GetIPAddress(client)
local ip = client:IPAddress()
return string.gsub(ip, ":%d+$", "", 1)
end
function PLUGIN:AltLookupIP(client)
local ip = self.GetIPAddress(client)
client.ixAltData.ipAddress = ip
if (self.ipCache[ip]) then
-- ip address still in cache
client.ixAltData.ip = self.ipCache[ip]
self:AltPreFinalChecking(client)
else
-- lookup address
local query = mysql:Select("bastion_antialt_ip")
query:Where("ip", ip)
query:Callback(function(result)
if (!result or #result == 0 or (result[1].updated < (os.time() - MAX_CACHE_AGE))) then
self:AltFetchIP(client, ip, !result or #result == 0)
else
-- load in data from the DB
if (result[1].proxy == 1) then
result[1].proxy = "yes"
else
result[1].proxy = "no"
end
client.ixAltData.ip = result[1]
self:AltPreFinalChecking(client)
end
end)
query:Execute()
end
end
function PLUGIN:AltFetchIP(client, ip, bCreateNew)
-- address not found or record too old, look it up
local url = string.format("https://proxycheck.io/v2/%s?key=%s&vpn=1&asn=1&risk=1", ip, self.API_KEY)
local request = {
failed = function(error)
-- error stop matching
print("[BASTION] Alt check IP API call failed with error: "..error)
print("[BASTION] Client: "..client:SteamName().."; ip: "..ip)
client.ixAltData.error = true
end,
success = function(code, body, headers)
if (!IsValid(client)) then return end
local httpResult = util.JSONToTable(body)
if (!httpResult) then
-- error stop matching
print("[BASTION] Alt check IP API call failed to parse httpResult.")
client.ixAltData.error = true
return
end
local status = httpResult.status
if (status == "denied" or status == "error" or status == "warning") then
print("[BASTION] Alt check IP API call failed. Status: "..status.."; Message: "..(httpResult.message or "no message").."\n")
if (status != "warning") then
-- error stop matching
client.ixAltData.error = true
return
end
end
-- we got the data
local lookup = httpResult[ip]
self:StoreIPLookup(ip, lookup, bCreateNew)
client.ixAltData.ip = lookup
self:AltPreFinalChecking(client)
end,
url = url,
method = "GET"
}
CHTTP(request)
end
function PLUGIN:AltLookupCookieMatches(client, data)
local query = mysql:Select("bastion_antialt_users")
query:Where("cookie", data.localCookie)
query:WhereNotEqual("steamid", client:SteamID64())
query:Callback(function(result)
-- we found other cookies
if (result and #result > 0) then
for k, v in ipairs(result) do
data.otherCookies[k] = {v.steam_name, v.steamid}
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AltLookupIPMatches(client)
local query = mysql:Select("bastion_antialt_userips")
query:Where("ip", PLUGIN.GetIPAddress(client))
query:WhereNotEqual("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (result and #result > 0) then
for k, v in ipairs(result) do
client.ixAltData.otherIPs[k] = {v.ip, v.steamid}
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AltLookupTimestampMatches(client, data, game, timestamp)
local query = mysql:Select("bastion_antialt_cookies")
query:Where("ts_"..game, timestamp)
if (data.localCookie != "") then
-- not interested in timestamps that we know for this client
query:WhereNotEqual("cookie", data.localCookie)
end
query:Callback(function(result)
if (result and #result > 0) then
for _, v in ipairs(result) do
data.otherTimestamps[v.cookie] = data.otherTimestamps[v.cookie] or {}
table.insert(data.otherTimestamps[v.cookie], game)
-- track timestamp matches
-- non-zero timestamps are worth a lot more, so tracked separately too
if (timestamp != 0) then
data.otherTimestampsNZ[v.cookie] = data.otherTimestampsNZ[v.cookie] or {}
data.otherTimestampsNZ[v.cookie][game] = true
end
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AggregateTimestampMatches(data)
data.otherTimeMatches = {}
for cookie, matches in pairs(data.otherTimestamps) do
if (#matches == 1) then continue end
data.otherTimeMatches[#data.otherTimeMatches + 1] = {cookie, #matches}
end
table.SortByMember(data.otherTimeMatches, 2, false)
end
function PLUGIN:AltLookupCookieForTimestamps(client, data, maxMatches)
local cookies = {}
for cookie, matches in pairs(data.otherTimestamps) do
-- only find cookies if at least 2 matches of which one is non-zero
if (#matches >= 2 and data.otherTimestampsNZ[cookie]) then
cookies[#cookies + 1] = cookie
end
end
if (#cookies == 0) then
data.checkComplete = true
self:AltFinalChecking(client)
return
end
local query = mysql:Select("bastion_antialt_users")
query:WhereNotEqual("steamid", client:SteamID64())
query:WhereIn("cookie", cookies)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (result and #result > 0) then
for _, v in ipairs(result) do
local installed = table.GetKeys(data.otherTimestampsNZ[v.cookie])
local text = string.format("%d/%d matches - installed: %s)",
#data.otherTimestamps[v.cookie],
maxMatches,
table.concat(installed, "+")
)
self:AltFound(client, v.steamid, "timestamp", text)
data.discordAlert.timestamps[# data.discordAlert.timestamps + 1] = v.steamid.." ("..v.steam_name.."; "..text..")"
data.discordAlert.altIDs[v.steamid] = true
end
end
data.checkComplete = true
self:AltFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:StoreCookieInfo(data, fileChecks)
local query = mysql:Select("bastion_antialt_cookies")
query:Where("cookie", data.localCookie)
query:Callback(function(result)
if (!result or #result == 0) then
local queryInsert = mysql:Insert("bastion_antialt_cookies")
queryInsert:Insert("cookie", data.localCookie)
for k, v in ipairs(fileChecks) do
queryInsert:Insert("ts_"..v[2], data.timestamps[k])
end
queryInsert:Execute()
else
local queryUpdate = mysql:Update("bastion_antialt_cookies")
queryUpdate:Where("cookie", data.localCookie)
for k, v in ipairs(fileChecks) do
queryUpdate:Update("ts_"..v[2], data.timestamps[k])
end
queryUpdate:Execute()
end
end)
query:Execute()
end
function PLUGIN:StoreClientCookie(client, data)
local query = mysql:Select("bastion_antialt_users")
query:Where("cookie", data.localCookie)
query:Where("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
local queryInsert = mysql:Insert("bastion_antialt_users")
queryInsert:Insert("steamid", client:SteamID64())
queryInsert:Insert("steam_name", client:SteamName())
queryInsert:Insert("cookie", data.localCookie)
queryInsert:Execute()
end
end)
query:Execute()
end
function PLUGIN:StoreIPLookup(ip, httpResult, bNewEntry)
if (!bNewEntry) then
local query = mysql:Update("bastion_antialt_ip")
query:Where("ip", ip)
query:Update("updated", os.time())
query:Update("asn", httpResult.asn)
query:Update("provider", httpResult.provider)
query:Update("isocode", httpResult.isocode)
query:Update("proxy", httpResult.proxy == "yes" and 1 or 0)
query:Update("type", httpResult.type)
query:Update("risk", httpResult.risk or 0)
if (httpResult["attack history"]) then
query:Update("attack_count", httpResult["attack history"].Total)
query:Update("attack_history", util.TableToJSON(httpResult["attack history"]))
end
query:Execute()
else
local query = mysql:Insert("bastion_antialt_ip")
query:Insert("ip", ip)
query:Insert("updated", os.time())
query:Insert("asn", httpResult.asn)
query:Insert("provider", httpResult.provider)
query:Insert("isocode", httpResult.isocode)
query:Insert("proxy", httpResult.proxy == "yes" and 1 or 0)
query:Insert("type", httpResult.type)
query:Insert("risk", httpResult.risk or 0)
if (httpResult["attack history"]) then
query:Insert("attack_count", httpResult["attack history"].Total)
query:Insert("attack_history", util.TableToJSON(httpResult["attack history"]))
end
query:Execute()
end
end
function PLUGIN:InsertNewAlt(steamid, alt_id, type, text)
local query = mysql:Insert("bastion_antialt_alts")
query:Insert("steamid", steamid)
query:Insert("alt_id", alt_id)
query:Insert("type", type)
query:Insert("info", text)
query:Execute()
end
function PLUGIN:MergeAlts(old_id, new_id, text)
local query = mysql:Select("bastion_antialt_alts")
query:Where("alt_id", old_id)
query:Callback(function(result2)
for _, v in ipairs(result2) do
local queryUpdate = mysql:Update("bastion_antialt_alts")
queryUpdate:Where("steamid", v.steamid)
queryUpdate:Update("alt_id", new_id)
queryUpdate:Update("info", v.info.." - "..text)
queryUpdate:Execute()
end
end)
query:Execute()
end
function PLUGIN:LookupSteamID(client, steamid)
if (string.find(steamid, "^STEAM_")) then
steamid = util.SteamIDTo64()
end
local query = mysql:Select("bastion_antialt_alts")
query:Where("steamid", steamid)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local querySelect = mysql:Select("bastion_antialt_alts")
querySelect:Where("alt_id", result[1].alt_id)
querySelect:Callback(function(finalResult)
if (!IsValid(client)) then return end
local toReturn = {"Alts for "..steamid..":", "(SteamID64) - (detection trigger type) - (info)"}
for _, v in ipairs(finalResult) do
toReturn[#toReturn + 1] = v.steamid.." - "..v.type.." - info: "..v.info
end
netstream.Start(client, "PrintInfoList", toReturn)
client:NotifyLocalized("bastionResultsPrinted")
end)
querySelect:Execute()
end)
query:Execute()
end
function PLUGIN:LookupIPUsers(client, steamid)
if (string.find(steamid, "^STEAM_")) then
steamid = util.SteamIDTo64(steamid)
end
local query = mysql:query("bastion_antialt_userips")
query:Where("steamid", steamid)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local list = {}
for k, v in ipairs(result) do
list[k] = v.ip
end
local querySelect = mysql:query("bastion_antialt_userips")
querySelect:WhereIn("ip", list)
querySelect:WhereNotEqual("steamid", steamid)
querySelect:Callback(function(finalResult)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local toReturn = {"Other users on same IP as "..steamid, "(SteamID64) - (ip) - (last seen on this ip)"}
for _, v in SortedPairsByMemberValue(finalResult, "steamid") do
toReturn[#toReturn + 1] = v.steamid.." - "..v.ip.." - "..os.date("%Y-%m-%d", v.last_seen)
end
netstream.Start(client, "PrintInfoList", toReturn)
client:NotifyLocalized("bastionResultsPrinted")
end)
querySelect:Execute()
end)
query:Execute()
end

View File

@@ -0,0 +1,96 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local hook = hook
local ix = ix
local util = util
local PLUGIN = PLUGIN
PLUGIN.permaBan = {
-- Crazyman (~Atle/Gr4Ss), code stealing
["STEAM_0:1:120921609"] = true,
["2.73.226.221"] = true,
["2.72.176.41"] = true,
["2.132.96.235"] = true,
["2.132.103.122"] = true,
["2.132.147.172"] = true,
["2.132.150.162"] = true,
["95.57.132.81"] = true,
-- carlsmei (~Atle/Gr4Ss), code stealing
["STEAM_0:0:216726444"] = true,
-- Schwarz Kruppzo (~Atle/Gr4Ss), code stealing
["STEAM_0:1:44629398"] = true,
-- KoC (~Atle/Gr4Ss), toxic, ban evasion
["76561198017957016"] = true,
["76561199123547331"] = true,
["73.121.218.83"] = true,
["136.144.43.116"] = true,
["136.144.43.63"] = true,
-- Kalingi (Staff vote, Hiros/Gr4Ss), toxic, threatening hacks & blackmail
["76561198066620287"] = true,
["STEAM_0:1:53177279"] = true,
["24.197.171.2"] = true,
-- Brando (~Atle/Gr4Ss), pedo
["STEAM_0:1:54660756"] = true,
-- Walter (~Atle/Gr4Ss), none
["STEAM_0:1:43085888"] = true,
-- PrplSckz/The Enemy (~Rad/Gr4Ss), forum DDoS
["STEAM_0:1:68538156"] = true,
-- Hackers (~Gr4Ss)
["STEAM_0:1:13809165"] = true,
["STEAM_0:1:4916602"] = true,
["STEAM_0:1:517232907"] = true,
["STEAM_0:1:17046093"] = true,
-- Exploiters
["STEAM_0:0:549109050"] = true,
["76561199131288084"] = true,
["76561199087140341"] = true,
["76561199206105794"] = true,
["76561198874018211"] = true,
["109.252.109.68"] = true,
["76561199121843993"] = true,
-- Zeroday / Newport Gaming - Sketchy dude + some hacking & exploiting (~M!NT/RAD)
["172.82.32.147"] = true,
["76561199441966033"] = true,
-- Cazo
["82.0.106.136"] = true,
["76561199150421701"] = true,
-- lqut (Translating ISIS Propaganda) (~M!NT/RAD)
["STEAM_0:0:173208852"] = true,
["5.30.219.71"] = true,
["76561198306683432"] = true,
-- madbluntz (doxxing, minging, ddosing, etc etc) (~M!NT)
["176.117.229.107"] = true,
["176.117.229.107"] = true,
["178.214.250.178"] = true,
["46.191.232.69"] = true,
["178.168.94.11"] = true,
["163.182.82.195"] = true,
["104.231.185.125"] = true,
["STEAM_0:0:763201893"] = true,
["STEAM_0:0:629741416"] = true,
["STEAM_0:1:764405213"] = true,
["STEAM_0:1:817531224"] = true,
["STEAM_0:0:785033797"] = true,
["STEAM_0:1:421783352"] = true,
["STEAM_0:1:78544439"] = true,
["STEAM_0:1:178702634"] = true,
["STEAM_0:0:627119036"] = true,
["STEAM_0:0:585787645"] = true,
["STEAM_0:1:43085888"] = true,
}
hook.Add("CheckPassword", "bastionBanList", function(steamid, networkid)
if (PLUGIN.permaBan[steamid] or PLUGIN.permaBan[util.SteamIDFrom64(steamid)] or PLUGIN.permaBan[networkid]) then
ix.log.AddRaw("[BANS] "..steamid.." ("..networkid..") a essayé de se connecter mais est strictement interdit.")
return false
end
end)

View File

@@ -0,0 +1,211 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local hook_Add = hook.Add
local timer_Create = timer.Create
local os_time = os.time
local pairs = pairs
local net_ReadHeader = net.ReadHeader
local util_NetworkIDToString = util.NetworkIDToString
local ix = ix
local IsValid = IsValid
local string_len = string.len
local string_sub = string.sub
-- Code inspired by:
-- Gmod Net Library Debug
-- https://github.com/HexaneNetworks/gmod-netlibrary-debug
-- v2.3
-- October 2020
local PLUGIN = PLUGIN
hook_Add("DatabaseConnected", "bastionNetDB", function()
local query = mysql:Create("bastion_netlog")
query:Create("id", "BIGINT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("name", "VARCHAR(50) NOT NULL")
query:Create("length", "INT UNSIGNED NOT NULL")
query:Create("count", "INT UNSIGNED NOT NULL")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("args", "VARCHAR(200) DEFAULT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_netspam")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("name", "VARCHAR(50) NOT NULL")
query:Create("type", "BOOL NOT NULL")
query:Create("count", "INT UNSIGNED NOT NULL")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("steam_name", "VARCHAR(50) NOT NULL")
query:Create("ip", "VARCHAR(25) NOT NULL")
query:Create("time", "INT NOT NULL")
query:PrimaryKey("id")
query:Execute()
end)
local netSpamCount = {}
local netFlagged = {}
local comSpamCount = {}
local comFlagged = {}
local threshold = 20
timer_Create("ixBastionNetSpam.Clear", 1.1, 0, function()
local time = os_time()
for steamID, data in pairs(netFlagged) do
for name in pairs(data.names) do
local query = mysql:Insert("bastion_netspam")
query:Insert("name", name)
query:Insert("type", 0)
query:Insert("count", netSpamCount[steamID][name] or 0)
query:Insert("steamid", steamID)
query:Insert("steam_name", data.steamName)
query:Insert("ip", data.ip)
query:Insert("time", time)
query:Execute()
end
end
netSpamCount = {}
netFlagged = {}
for steamID, data in pairs(comFlagged) do
for name in pairs(data.commands) do
local query = mysql:Insert("bastion_netspam")
query:Insert("name", name)
query:Insert("type", 1)
query:Insert("count", comSpamCount[steamID][name] or 0)
query:Insert("steamid", steamID)
query:Insert("steam_name", data.steamName)
query:Insert("ip", data.ip)
query:Insert("time", time)
query:Execute()
end
end
comSpamCount = {}
comFlagged = {}
end)
local netIgnoreList = {
["76561198002319953"] = 2
}
local netSpamAmount = {
["NetStreamDS"] = 20,
["76561198002319953"] = 30
}
function net.Incoming(len, client)
local i = net_ReadHeader()
local name = util_NetworkIDToString(i)
if (!name) then return end
local func = net.Receivers[name:lower()]
if (!func) then return end
--
-- len includes the 16 bit int which told us the message name
--
len = len - 16
if (ix.config.Get("netAntiSpam")) then
local steamID = IsValid(client) and client:SteamID64() or "UNKNOWN"
netSpamCount[steamID] = netSpamCount[steamID] or {}
netSpamCount[steamID][name] = (netSpamCount[steamID][name] or 0) + 1
if (netSpamCount[steamID][name] > (netSpamAmount[name] or threshold)) then
if (!netFlagged[steamID]) then
netFlagged[steamID] = {
names = {},
steamID = steamID,
steamName = IsValid(client) and (client.SteamName and client:SteamName() or client:Name()) or "UNKNOWN PLAYER NAME",
ip = IsValid(client) and client:IPAddress() or "UNKNOWN IP"
}
if (!ix.config.Get("netLoggingEnabled")) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", name)
query:Insert("length", len)
query:Insert("count", netSpamCount[steamID][name])
query:Insert("steamid", steamID)
query:Execute()
end
end
netFlagged[steamID].names[name] = true
end
if (ix.config.Get("netLoggingEnabled") and (!netIgnoreList[name] or netIgnoreList[name] < netSpamCount[steamID][name])) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", name)
query:Insert("length", len)
query:Insert("count", netSpamCount[steamID][name])
query:Insert("steamid", steamID)
query:Execute()
end
end
func(len, client)
end
local conSpamAmount = {
}
local conIgnoreList = {
}
PLUGIN.oldRun = PLUGIN.oldRun or concommand.Run
function concommand.Run(client, command, args, argString)
if (IsValid(client) and command and ix.config.Get("netAntiSpam")) then
local steamID = IsValid(client) and client:SteamID64() or "UNKNOWN"
comSpamCount[steamID] = comSpamCount[steamID] or {}
comSpamCount[steamID][command] = (comSpamCount[steamID][command] or 0) + 1
if (comSpamCount[steamID][command] > (conSpamAmount[command] or threshold)) then
if (!comFlagged[steamID]) then
comFlagged[steamID] = {
commands = {},
steamID = steamID,
steamName = IsValid(client) and (client.SteamName and client:SteamName() or client:Name()) or "UNKNOWN PLAYER NAME",
ip = IsValid(client) and client:IPAddress() or "UNKNOWN IP"
}
if (!ix.config.Get("netLoggingEnabled")) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", command)
query:Insert("length", #argString)
query:Insert("count", netSpamCount[steamID][command])
query:Insert("steamid", steamID)
query:Insert("args", string_len(argString or "") > 200 and string_sub(argString, 1, 200) or argString or "")
query:Execute()
end
end
comFlagged[steamID].commands[command] = true
end
if (ix.config.Get("netLoggingEnabled") and (!conIgnoreList[command] or conIgnoreList[command] < comSpamCount[steamID][command])) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", command)
query:Insert("length", #argString)
query:Insert("count", comSpamCount[steamID][command])
query:Insert("steamid", steamID)
query:Insert("args", string_len(argString or "") > 200 and string_sub(argString, 1, 200) or argString or "")
query:Execute()
end
end
return PLUGIN.oldRun(client, command, args, argString)
end

View File

@@ -0,0 +1,100 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
--Made by Liquid
PLUGIN.MIN_PLAYER_COUNT = 30
PLUGIN.STOP_AFTER_CONNECTED_FOR = 600
PLUGIN.MIN_SIZE = 100
PLUGIN.TRACE_SIZE = 1000
ORIGINAL_NET = ORIGINAL_NET or table.Copy(net)
local _net = ORIGINAL_NET
local IsValid = IsValid
local currentMessageName
hook.Add("DatabaseConnected", "bastionNetSizeLog", function()
local query = mysql:Create("bastion_netsizelog")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("timestamp", "INT(11) UNSIGNED NOT NULL")
query:Create("realtime", "FLOAT NOT NULL")
query:Create("message_name", "VARCHAR(128) NOT NULL")
query:Create("size", "INT(11) UNSIGNED NOT NULL")
query:Create("stack_trace", "TEXT DEFAULT NULL")
query:PrimaryKey("id")
query:Callback(function()
local delete = mysql:Delete("bastion_netsizelog")
delete:WhereLT("timestamp", os.time() - 3 * 24 * 3600)
delete:Execute()
end)
query:Execute()
end)
local function netLog(players)
local count = player.GetCount()
if (count > 1 and count <= PLUGIN.MIN_PLAYER_COUNT) then return end
if (type(players) == "Player") then
players = {players}
elseif (type(players) == "CRecipientFilter") then
players = players:GetPlayers()
end
local size = _net.BytesWritten()
if (size <= PLUGIN.MIN_SIZE) then return end
for k, v in ipairs(players) do
if (!IsValid(v)) then continue end
if (v.ixStopNetLog or v:TimeConnected() > PLUGIN.STOP_AFTER_CONNECTED_FOR) then
v.ixStopNetLog = true
continue
end
local query = mysql:Insert("bastion_netsizelog")
query:Insert("steamid", v:SteamID64())
query:Insert("timestamp", os.time())
query:Insert("realtime", RealTime())
query:Insert("message_name", currentMessageName)
query:Insert("size", size)
if (size >= PLUGIN.TRACE_SIZE or currentMessageName == "NetStreamDS") then
query:Insert("stack_trace", debug.traceback())
end
query:Execute()
end
end
net.Start = function(name, unreliable)
currentMessageName = name
return _net.Start(name, unreliable)
end
net.Send = function(players)
netLog(players)
currentMessageName = nil
return _net.Send(players)
end
net.SendOmit = function(players)
netLog(players)
currentMessageName = nil
return _net.SendOmit(players)
end
net.Broadcast = function(pos)
netLog(player.GetAll())
currentMessageName = nil
return _net.Broadcast()
end