Mod Detection using sign epxloit
Based on PacketEventsSK v1.1.3 with SkBee v3.23.0 on Paper v26.1.2
This example makes use of a sign exploit described in MC-265322 and on wurst wiki. It can be used to see which mods are or aren't installed on a connected player. (and is thus very powerful for anti cheating purposes)
Basically the way it works:
- server sends a fake sign with a line having a translatable component or keybind component (
clientbound block changepacket andclientbound block entity datapacket) - server forces the client to open the editor of the sign (
clientbound open sign editorpacket) - server forces the client to close the editor (
clientbound close windowpacket) - client closes the editor and as a response sends the "new content" (which is unchanged) to the server (
serverbound update signpacket received by server on line 57) - server reads the new content: if it parsed the translatable/keybind component it has the keybind set and thus has the mod otherwise not
applescript
on load:
delete {-blackListedKeybinds::*}
add "key.freecam.toggle" to {-blackListedKeybinds::*}
add "key.freecam.playerControl" to {-blackListedKeybinds::*}
add "key.freecam.tripodReset" to {-blackListedKeybinds::*}
add "key.freecam.configGui" to {-blackListedKeybinds::*}
function createSignNBT(bind: string) :: nbt compound:
set {_nbtString} to "{front_text:{messages:[{""keybind"":""%{_bind}%""},{""text"":""""},{""text"":""""},{""text"":""""}]}}"
return nbt compound from {_nbtString}
function startKeybindChecks(p: player):
set {_uuid} to uuid of {_p}
delete {-keybindQueue::%{_uuid}%::*}
loop {-blackListedKeybinds::*}:
add loop-value to {-keybindQueue::%{_uuid}%::*}
checkNextKeybind({_p})
function checkNextKeybind(p: player):
set {_uuid} to uuid of {_p}
set {_keybind} to first element of {-keybindQueue::%{_uuid}%::*}
if {_keybind} is set:
check({_p}, {_keybind})
else:
delete {-keybindQueue::%{_uuid}%::*}
function check(p: player, keybind: string):
set {_pos} to vector of {_p}'s location
set {_blockPacket} to a new clientbound block change packet:
block position: {_pos}
block state: oak sign[]
set {_setTextPacket} to a new clientbound block entity data packet:
block position: {_pos}
block entity type: sign block entity type
nbt compound: createSignNBT({_keybind})
set {_signPacket} to clientbound open sign editor packet:
block position: {_pos}
sign side: front
set {_closeWindowPacket} to a clientbound close window packet
set {_revertBlockPacket} to new clientbound block change packet:
block position: {_pos}
block state: air[]
# Sends the packets (order sensitive)
send packet {_blockPacket}, {_setTextPacket}, {_signPacket}, {_closeWindowPacket} and {_revertBlockPacket} to {_p}
on serverbound update sign packet sync processed:
set {_p} to event-player
set {_uuid} to uuid of {_p}
if {-keybindQueue::%{_uuid}%::*} is set:
set {_firstIndex} to first element of indices of {-keybindQueue::%{_uuid}%::*}
set {_expected} to {-keybindQueue::%{_uuid}%::%{_firstIndex}%}
delete {-keybindQueue::%{_uuid}%::%{_firstIndex}%}
set {_updateSignPacket} to event-packet
set {_text} to first element of packet sign lines of event-packet
if {_text} is not {_expected}:
delete {-keybindQueue::%{_uuid}%::*}
kick {_p} due to "Unsupported client modification detected!"
else:
send "%{_p}% passed keybind check for: %{_expected}%" to console
wait 1 tick
if {_p} is online:
checkNextKeybind({_p})
on join:
wait 3 seconds
startKeybindChecks(player)