Skip to content

Commit

Permalink
Cid randomizer dll detector.
Browse files Browse the repository at this point in the history
When a user's cid doesn't match their last cid, we just close the connection, faking a read error. If it's still mismatched when they reconnect, we reject the connection and let them know we are on to them.
  • Loading branch information
MrStonedOne committed Aug 23, 2016
1 parent 062d382 commit f154ede
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 7 deletions.
4 changes: 4 additions & 0 deletions code/controllers/configuration.dm
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
var/forbid_singulo_possession = 0
var/useircbot = 0

var/check_randomizer = 0

//IP Intel vars
var/ipintel_email
var/ipintel_rating_bad = 1
Expand Down Expand Up @@ -402,6 +404,8 @@
config.notify_new_player_age = text2num(value)
if("irc_first_connection_alert")
config.irc_first_connection_alert = 1
if("check_randomizer")
config.check_randomizer = 1
if("ipintel_email")
if (value != "[email protected]")
config.ipintel_email = value
Expand Down
94 changes: 88 additions & 6 deletions code/modules/client/client_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ var/next_external_rsc = 0
if (!dbcon.IsConnected())
return

var/sql_ckey = sanitizeSQL(src.ckey)
var/sql_ckey = sanitizeSQL(ckey)

var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = '[address]' AND ckey != '[sql_ckey]'")
query_ip.Execute()
Expand All @@ -304,15 +304,18 @@ var/next_external_rsc = 0
while (query_cid.NextRow())
related_accounts_cid += "[query_cid.item[1]], "

var/admin_rank = "Player"
if (src.holder && src.holder.rank)
admin_rank = src.holder.rank.name
else
if (check_randomizer())
return

var/watchreason = check_watchlist(sql_ckey)
if(watchreason)
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'>[key_name_admin(src)] is on the watchlist and has just connected - Reason: [watchreason]</font>")
send2irc_adminless_only("Watchlist", "[key_name(src)] is on the watchlist and has just connected - Reason: [watchreason]")

var/admin_rank = "Player"
if (src.holder && src.holder.rank)
admin_rank = src.holder.rank.name

var/sql_ip = sanitizeSQL(src.address)
var/sql_computerid = sanitizeSQL(src.computer_id)
var/sql_admin_rank = sanitizeSQL(admin_rank)
Expand All @@ -326,6 +329,85 @@ var/next_external_rsc = 0
var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]` (`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');")
query_accesslog.Execute()

/client/proc/check_randomizer()
. = FALSE
if (!config.check_randomizer)
return
var/static/cidcheck = list()
var/static/cidcheck_failedckeys = list() //to avoid spamming the admins if the same guy keeps trying.

var/oldcid = cidcheck[ckey]
if (oldcid)
if (oldcid != computer_id) //IT CHANGED!!!
cidcheck -= ckey //so they can try again after removing the cid randomizer.

src << "<span class='userdanger'>Connection Error:</span>"
src << "<span class='danger'>Invalid ComputerID(spoofed). Please remove the ComputerID spoofer from your byond installation and try again.</span>"

if (!cidcheck_failedckeys[ckey])
message_admins("<span class='adminnotice'>[key_name(src)] has been detected as using a cid randomizer. Connection rejected.</span>")
send2irc_adminless_only("CidRandomizer", "[key_name(src)] has been detected as using a cid randomizer. Connection rejected.")
cidcheck_failedckeys[ckey] = 1
note_randomizer_user()

log_access("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])")

del(src)
return TRUE
else
if (cidcheck_failedckeys[ckey])
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer</span>")
send2irc_adminless_only("CidRandomizer", "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.")
cidcheck_failedckeys -= ckey
cidcheck -= ckey
else
var/sql_ckey = sanitizeSQL(ckey)
var/DBQuery/query_cidcheck = dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
query_cidcheck.Execute()

var/lastcid
if (query_cidcheck.NextRow())
lastcid = query_cidcheck.item[1]

if (computer_id != lastcid)
cidcheck[ckey] = computer_id
log_access("Failed Login: [key] [computer_id] [address] - CID randomizer check")

var/url = winget(src, null, "url")
//special javascript to make them reconnect under a new window.
src << browse("<a id='link' href=byond://[url]>byond://[url]</a><script type='text/javascript'>document.getElementById(\"link\").click();window.location=\"byond://winset?command=.quit\"</script>", "border=0;titlebar=0;size=1x1")
winset(src, "reconnectbutton", "is-disable=true") //reconnect keeps the same cid in the randomizer, they could use this button to fake it.
sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command.

//teeheehee (in case the above method doesn't work, its not 100% reliable.)
src << "<pre class=\"system system\">Network connection shutting down due to read error.</pre>"
del(src)
return TRUE

/client/proc/note_randomizer_user()
var/const/adminckey = "CID RANDOMIZER DETECTOR"
var/sql_ckey = sanitizeSQL(ckey)
//check to see if we noted them in the last day.
var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id FROM [format_table_name("notes")] WHERE ckey = '[sql_ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()")
if(!query_get_notes.Execute())
var/err = query_get_notes.ErrorMsg()
log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n")
return
if (query_get_notes.NextRow())
return

//regardless of above, make sure their last note is not from us, as no point in repeating the same note over and over.
query_get_notes = dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[sql_ckey]' ORDER BY timestamp DESC LIMIT 1")
if(!query_get_notes.Execute())
var/err = query_get_notes.ErrorMsg()
log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n")
return
if (query_get_notes.NextRow())
if (query_get_notes.item[1] == adminckey)
return
add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0)


/client/proc/check_ip_intel()
set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep
if (config.ipintel_email)
Expand Down Expand Up @@ -381,4 +463,4 @@ var/next_external_rsc = 0
//Hook, override it to run code when dir changes
//Like for /atoms, but clients are their own snowflake FUCK
/client/proc/setDir(newdir)
dir = newdir
dir = newdir
3 changes: 3 additions & 0 deletions config/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ HOSTEDBY Yournamehere
## Uncomment this to stop people connecting to your server without a registered ckey. (i.e. guest-* are all blocked from connecting)
GUEST_BAN

## Comment to disable checking for the cid randomizer dll. (disabled if database isn't enabled or connected)
CHECK_RANDOMIZER

### IPINTEL:
### This allows you to detect likely proxies by checking ips against getipintel.net
## Rating to warn at: (0.90 is good, 1 is 100% likely to be a spammer/proxy, 0.8 is 80%, etc) anything equal to or higher then this number triggers an admin warning
Expand Down
2 changes: 1 addition & 1 deletion interface/skin.dmf
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ menu "menu"
elem
name = ""
category = "&File"
elem
elem "reconnectbutton"
name = "&Reconnect"
category = "&File"
command = ".reconnect"
Expand Down

0 comments on commit f154ede

Please sign in to comment.