Players get disconnected due to speedhack detection not working correctly #10

Closed
opened 2023-12-31 09:13:28 +02:00 by Exynox · 2 comments
Owner

This can be triggered immediately after a warp, especially when using a mount:

[2023-12-31 09:11:20.035] [debug] [char_item.cpp:5162] [SA]Admin: USE_ITEM White Lion (inven 1, cell: 30)
[2023-12-31 09:11:20.555] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82642
[2023-12-31 09:11:20.795] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668
[2023-12-31 09:11:20.795] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668
[2023-12-31 09:11:21.075] [debug] [char_item.cpp:5162] [SA]Admin: USE_ITEM White Lion (inven 1, cell: 30)
[2023-12-31 09:11:21.075] [debug] [char_affect.cpp:585] AddAffect [SA]Admin type 221 apply 109 20114 flag 0 duration 90180
[2023-12-31 09:11:21.075] [debug] [char_affect.cpp:585] AddAffect [SA]Admin type 533 apply 19 0 flag 0 duration 90180
[2023-12-31 09:11:21.555] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668
[2023-12-31 09:11:21.836] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82636
[2023-12-31 09:11:22.155] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82642
[2023-12-31 09:11:22.234] [debug] [item_manager.cpp:449] ITEM_SAVE Moon Elixir (E):40000097 in [SA]Admin window 1
[2023-12-31 09:11:22.235] [debug] [item_manager.cpp:449] ITEM_SAVE White Lion:40000012 in [SA]Admin window 2
[2023-12-31 09:11:22.475] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82648
[2023-12-31 09:11:22.795] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82655
[2023-12-31 09:11:22.994] [debug] [char.cpp:2647] SECTREE DIFFER: [SA]Admin 150x43 was 150x42
[2023-12-31 09:11:23.115] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82661
[2023-12-31 09:11:23.435] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668
[2023-12-31 09:11:23.555] [debug] [char.cpp:1282] DISCONNECT: [SA]Admin (DESC::~DESC)
[2023-12-31 09:11:23.555] [debug] [char.cpp:1200] SAVE: [SA]Admin 962522x276219
This can be triggered immediately after a warp, especially when using a mount: ``` [2023-12-31 09:11:20.035] [debug] [char_item.cpp:5162] [SA]Admin: USE_ITEM White Lion (inven 1, cell: 30) [2023-12-31 09:11:20.555] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82642 [2023-12-31 09:11:20.795] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668 [2023-12-31 09:11:20.795] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668 [2023-12-31 09:11:21.075] [debug] [char_item.cpp:5162] [SA]Admin: USE_ITEM White Lion (inven 1, cell: 30) [2023-12-31 09:11:21.075] [debug] [char_affect.cpp:585] AddAffect [SA]Admin type 221 apply 109 20114 flag 0 duration 90180 [2023-12-31 09:11:21.075] [debug] [char_affect.cpp:585] AddAffect [SA]Admin type 533 apply 19 0 flag 0 duration 90180 [2023-12-31 09:11:21.555] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668 [2023-12-31 09:11:21.836] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82636 [2023-12-31 09:11:22.155] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82642 [2023-12-31 09:11:22.234] [debug] [item_manager.cpp:449] ITEM_SAVE Moon Elixir (E):40000097 in [SA]Admin window 1 [2023-12-31 09:11:22.235] [debug] [item_manager.cpp:449] ITEM_SAVE White Lion:40000012 in [SA]Admin window 2 [2023-12-31 09:11:22.475] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82648 [2023-12-31 09:11:22.795] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82655 [2023-12-31 09:11:22.994] [debug] [char.cpp:2647] SECTREE DIFFER: [SA]Admin 150x43 was 150x42 [2023-12-31 09:11:23.115] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82661 [2023-12-31 09:11:23.435] [info] [input_main.cpp:1574] SPEEDHACK: slow timer name [SA]Admin delta 82668 [2023-12-31 09:11:23.555] [debug] [char.cpp:1282] DISCONNECT: [SA]Admin (DESC::~DESC) [2023-12-31 09:11:23.555] [debug] [char.cpp:1200] SAVE: [SA]Admin 962522x276219 ```
Exynox added the
bug
label 2023-12-31 09:13:28 +02:00
Author
Owner

This stems from a naive speed-hack check:

src/game/src/input_main.cpp Lines 1538 to 1564 in 5665bde225
//
// 스피드핵(SPEEDHACK) Check
//
DWORD dwCurTime = get_dword_time();
// 시간을 Sync하고 7초 후 부터 검사한다. (20090702 이전엔 5초였음)
bool CheckSpeedHack = (false == ch->GetDesc()->IsHandshaking() && dwCurTime - ch->GetDesc()->GetClientTime() > 7000);
if (CheckSpeedHack)
{
int iDelta = (int) (pinfo->dwTime - ch->GetDesc()->GetClientTime());
int iServerDelta = (int) (dwCurTime - ch->GetDesc()->GetClientTime());
iDelta = (int) (dwCurTime - pinfo->dwTime);
// 시간이 늦게간다. 일단 로그만 해둔다. 진짜 이런 사람들이 많은지 체크해야함. TODO
if (iDelta >= 30000)
{
SPDLOG_WARN("SPEEDHACK: slow timer name {} delta {}", ch->GetName(), iDelta);
ch->GetDesc()->DelayedDisconnect(3);
}
// 1초에 20msec 빨리 가는거 까지는 이해한다.
else if (iDelta < -(iServerDelta / 50))
{
SPDLOG_WARN("SPEEDHACK: DETECTED! {} (delta {} {})", ch->GetName(), iDelta, iServerDelta);
ch->GetDesc()->DelayedDisconnect(3);
}
}

With a bit of cleanup, the code above is de facto equivalent with the following:

//
// Clock skew-based SpeedHack check
//

// Start checking only 7 seconds after client-server time synchronisation
DWORD dwCurTime = get_dword_time();
int iServerDelta = abs(dwCurTime - ch->GetDesc()->GetClientTime());
bool CheckSpeedHack = (!ch->GetDesc()->IsHandshaking() && iServerDelta > 7000);

if (CheckSpeedHack)
{
	// Time drift between the server and client (in ms)
	int iDelta = abs(dwCurTime - pinfo->dwTime);

	// Client time is running slow
	if (iDelta >= 30000)
	{
		SPDLOG_WARN("SPEEDHACK: clock skew limit exceeded: name {}, delta {}", ch->GetName(), iDelta);
		ch->GetDesc()->DelayedDisconnect(3);
	}
	// Only allow for a clock skew rate up to 20ms/s
	else if (iDelta > (iServerDelta / 50))
	{
		SPDLOG_WARN("SPEEDHACK: clock skew rate limit exceeded: name {}, delta {}, server delta {}", ch->GetName(), iDelta, iServerDelta);
		ch->GetDesc()->DelayedDisconnect(3);
	}
}

Basically, this does three things:

  • Only starts the checks 7 seconds after the client-server handshake, when the server determines the clock skew between the client and server.
  • Ensures that when a MOVE packet is received, the clock skew (as reported by the client) is less than 30 seconds.
  • Ensures that when a MOVE packet is received, the clock (as reported by the client) can't skew for more than 20ms/s compared to wall clock time.

Should any of the latter two be true, the server decides that a speed-hack might be used and disconnects the player. This is stupid as trust is put into the time reported by the client, which could be spoofed.

The false positives are caused by the fact that the client's clock isn't strictly real-time, but is tied to the 3D render process, therefore being susceptible to skew when in debug mode or on a particularly GPU-heavy environment.

We don't even know, assuming the client's clock would be stable and trustworthy, whether this method of detecting a speed-hack is even reliable. Therefore it's nothing but trouble and it should be removed.

This is also true for the neighbouring combo-hack check, which also ties into the client's clock and speed-hack check.

The dwTime field in the MOVE packets could also be removed, as it doesn't seem to be used for any operations.

This stems from a naive speed-hack check: https://git.old-metin2.com/metin2/server/src/commit/5665bde225234b17cc48c0cc4cc1c5abe547778e/src/game/src/input_main.cpp#L1538-L1564 With a bit of cleanup, the code above is de facto equivalent with the following: ```cpp // // Clock skew-based SpeedHack check // // Start checking only 7 seconds after client-server time synchronisation DWORD dwCurTime = get_dword_time(); int iServerDelta = abs(dwCurTime - ch->GetDesc()->GetClientTime()); bool CheckSpeedHack = (!ch->GetDesc()->IsHandshaking() && iServerDelta > 7000); if (CheckSpeedHack) { // Time drift between the server and client (in ms) int iDelta = abs(dwCurTime - pinfo->dwTime); // Client time is running slow if (iDelta >= 30000) { SPDLOG_WARN("SPEEDHACK: clock skew limit exceeded: name {}, delta {}", ch->GetName(), iDelta); ch->GetDesc()->DelayedDisconnect(3); } // Only allow for a clock skew rate up to 20ms/s else if (iDelta > (iServerDelta / 50)) { SPDLOG_WARN("SPEEDHACK: clock skew rate limit exceeded: name {}, delta {}, server delta {}", ch->GetName(), iDelta, iServerDelta); ch->GetDesc()->DelayedDisconnect(3); } } ``` Basically, this does three things: - Only starts the checks 7 seconds after the client-server handshake, when the server determines the clock skew between the client and server. - Ensures that when a MOVE packet is received, the clock skew (as reported by the client) is less than 30 seconds. - Ensures that when a MOVE packet is received, the clock (as reported by the client) can't skew for more than 20ms/s compared to wall clock time. Should any of the latter two be true, the server decides that a speed-hack might be used and disconnects the player. This is stupid as trust is put into the time reported by the client, which could be spoofed. The false positives are caused by the fact that the client's clock isn't strictly real-time, but is tied to the 3D render process, therefore being susceptible to skew when in debug mode or on a particularly GPU-heavy environment. We don't even know, assuming the client's clock would be stable and trustworthy, whether this method of detecting a speed-hack is even reliable. Therefore it's nothing but trouble and it should be removed. This is also true for the neighbouring combo-hack check, which also ties into the client's clock and speed-hack check. The `dwTime` field in the MOVE packets could also be removed, as it doesn't seem to be used for any operations.
Author
Owner

Solved in 610c7e7020

Solved in 610c7e7020
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: metin2/server#10
No description provided.