Her neyse biz devam edelim aşağıda ki tüm adımlarını detaylıca okuyup anlamaya çalışırsanız nasıl bir şey olduğunu anlayabilirsiniz ve neredeyse tüm altyapılarda bu bufferoverflow mevzusu mevcut.
Şimdi fixe geçelim malum yarın 16 sunucu açılıyormuş bir çok sunucu sahibi istiyor ;
Kısaca sorun neydi ; Lamer sunucuya 200 veya üzeri büyüklüğünde paket gönderiyor daha sonra buffer_new() fonksiyonunda abort tetikliyor ve sonuç game.core, ayrıca farklı iplerden sürekli handshake flood yaparak normal oyuncuların girişini vs engelliyor.
Peki fix ne işe yarıyor ? ;
1 = ip ban kontrol , bağlantı limiti , handshake timeout ekleyerek bağlantıyı reddediyorum ve sunucu çalışmaya devam ediyor.
2 = 64mb alloc limit 32 mb input limit ve write boyut limiti ve kontrolü koyduk ve sadece o saldırganın yaptığı client kesiliyor sunucu çökmüyor.
3 = Bilinmeyen paket , flood ban tetikletmek ve bağlantıyı kapatmak ve ipyi definede belirtilen zamana göre banlamak
Ekstra alabileceğiniz önlemler ;
- slowloris bunu bilen bilir ben kısaca özetliyorum ; her 9 saniyede 1 byte gönderirse gönderen kişi 10 saniye timeout tetiklemez gibi ( rakamları isteidğiniz gibi ayarlayabilirsiniz.
- Geçerli paket spam yapabilirsiniz ; oyuna girip geçerli paketleri bağırma sohbeti , yürümek atak yapmak vs vs.. bunlar binlerce kez gönderildiği için flood koruması tetiklenmez. ( Bu karmaşıktır kendi sourcemde bulunuyor fakat aynısını paylaşmak istemiyorum ilerleyen günlerde belki değiştirerek paylaşabilirim. Bunu yapmasanızda zaten aşamayacak çünkü bu yukarıda anlatılanlar anormal bir durum değildir yani yetenek gerektirmeden 3-5 bilgiyle lamer olabiliyorsunuz)
- ve tabiki yoğun trafik ve tamamen abartarak aşırı güvenliğe kaçmak istiyorsanız firewall + os seviyesinde çözmeniz gerekir bunuda sunucu sağlayıcınız yapabilir. Bunlar kod değil sunucuyla alakalıdır.
==== Yukarıdaki 3 adım kapsamlı geliştirmelerdir.. Sunucu sağlayıcınızla konuşmalısınız. ====
libthecore klasörü içerisinde buffer.c dosyasını aç dosya başı includelerden sonra ekle ;
libthecore/buffer.c:
buffer_manager.h:
buffer_manager.cpp:
desc.h:
desc.cpp:
main.cpp:
input.cpp:
input_auth.cpp:
input_login.cpp:
input_main.cpp:
input_p2p.cpp:
NOT : tüm değişiklikleri ifdef ile sarmalamadım koşulsuz olarak uyguladım çünkü güvenlik kodu isteğe bağlı olmamalıdır. İsteyen ifdefli yapsın.
NOT : mysql/mariadb server.cnf için ise yani ;
max_allowed_packet =
max_connections =
wait_timeout =
interactive_timeout =
net_read_timeout =
net_write_timeout =
buradaki değerleri sunucu sağlayıcınız ayarlasın.
Bu makalede sorunun teknik mantığını, nasıl oluştuğunu ve sunucu–istemci tarafında nasıl kalıcı şekilde fixlenebileceğini ele alıyoruz.
Sonuç olarak:
Mouse click veya skill event’lerinde:
if (current_time - last_click_time < MIN_DELAY)
return;
Bu basit kontrol bile %80 exploit’i keser.
UI event stack büyüyorsa:
Eski Metin2 client kodlarında:
Bunların yerine:
Aksi halde packet parsing sırasında overflow oluşabilir.
Her karakter için:
Örneğin:
Server tarafında:
Client’a asla güvenilmez.
Gerçek çözüm:
Eğer private server geliştiriyorsan, bu fix’i sadece crash önleme değil aynı zamanda exploit kapatma perspektifiyle düşünmelisin.
One of the technical problems that private server developers occasionally encounter in Metin2 is client-side triggered crashes or exploit vulnerabilities caused by buffer overflow. The issue commonly referred to as the “mouse spam lamer fix” is actually based on memory overflows caused by rapid and abnormal input spamming.
In this article, we will examine the technical logic behind the problem, how it occurs, and how it can be permanently fixed on both the server and client sides.
A buffer overflow occurs when more data is written to a memory space than it was allocated for. In some older Metin2 client versions:
could be processed without proper boundary checks.
As a result:
could occur.
Some users would:
If there is no rate limit on the server:
This is not about pressing the mouse hard; it is about uncontrolled input processing.
For mouse clicks or skill events:
Even this simple control prevents most exploit attempts.
If the UI event stack grows excessively:
This significantly reduces overflow risk.
Older Metin2 client code may contain unsafe functions such as:
These should be replaced with:
Otherwise, packet parsing may cause buffer overflows.
Client-side fixes alone are not enough. The real protection must be on the server side.
For each character:
For example:
Server-side checks must include:
Never trust the client.
A properly implemented buffer overflow fix:
The difference becomes significant at high online player counts.
The issue known as the “mouse spam lamer fix” is actually a combination of:
The real solution requires layered security:
If you are developing a private server, you should consider this fix not only as crash prevention but also from an exploit mitigation perspective.
Eines der technischen Probleme, mit denen Entwickler von Private-Servern in Metin2 gelegentlich konfrontiert werden, sind clientseitig ausgelöste Abstürze oder Exploit-Schwachstellen durch Buffer Overflow. Das sogenannte „Mouse-Spam-Lamer-Fix“-Problem basiert tatsächlich auf Speicherüberläufen, die durch schnelles und ungewöhnliches Input-Spamming entstehen.
In diesem Artikel erklären wir die technische Ursache, wie das Problem entsteht und wie es dauerhaft auf Client- und Serverseite behoben werden kann.
Ein Buffer Overflow entsteht, wenn mehr Daten in einen Speicherbereich geschrieben werden, als dafür reserviert wurde. In einigen älteren Metin2-Client-Versionen konnten:
ohne ausreichende Grenzprüfungen verarbeitet werden.
Dies führte zu:
Einige Nutzer:
Ohne Server-Rate-Limit:
Es geht nicht um starkes Klicken, sondern um unkontrollierte Input-Verarbeitung.
Das als „Mouse-Spam-Lamer-Fix“ bekannte Problem ist eine Kombination aus:
Die echte Lösung besteht aus:
Wenn du einen Private-Server entwickelst, solltest du dieses Fix nicht nur als Crash-Prävention betrachten, sondern auch als Schutz vor Exploits.
Una dintre problemele tehnice întâlnite de dezvoltatorii de servere private în Metin2 este reprezentată de crash-uri sau vulnerabilități de tip buffer overflow declanșate din client. Problema cunoscută ca „mouse spam lamer fix” este de fapt cauzată de overflow de memorie generat de input rapid și anormal.
În acest articol explicăm cauza tehnică, modul în care apare și cum poate fi rezolvată permanent atât pe partea de client, cât și pe partea de server.
Un buffer overflow apare atunci când se scriu mai multe date într-o zonă de memorie decât spațiul alocat. În unele versiuni vechi ale clientului Metin2:
erau procesate fără verificări adecvate.
Rezultatul putea fi:
Problema numită „mouse spam lamer fix” este combinația dintre:
Soluția reală necesită:
Dacă dezvolți un server privat, ar trebui să privești acest fix nu doar ca prevenție împotriva crash-urilor, ci și ca metodă de blocare a exploit-urilor.
Tamam kanka
Aşağıda makalenin, belirttiğin yere kadar olan kısmının Lehçe (Polski) çevirisi yer alıyor.
W tym artykule omawiamy techniczne podstawy problemu, sposób jego powstawania oraz to, jak można go trwale naprawić zarówno po stronie klienta, jak i serwera.
W rezultacie mogło to prowadzić do:
Dla kliknięć myszy lub zdarzeń skilli należy:
Jeśli kolejka zdarzeń UI rośnie zbyt mocno:
W starszym kodzie klienta Metin2 można znaleźć niebezpieczne funkcje, takie jak:
Dla każdej postaci należy określić:
Po stronie serwera należy sprawdzać:
Şimdi fixe geçelim malum yarın 16 sunucu açılıyormuş bir çok sunucu sahibi istiyor ;
Kısaca sorun neydi ; Lamer sunucuya 200 veya üzeri büyüklüğünde paket gönderiyor daha sonra buffer_new() fonksiyonunda abort tetikliyor ve sonuç game.core, ayrıca farklı iplerden sürekli handshake flood yaparak normal oyuncuların girişini vs engelliyor.
Peki fix ne işe yarıyor ? ;
1 = ip ban kontrol , bağlantı limiti , handshake timeout ekleyerek bağlantıyı reddediyorum ve sunucu çalışmaya devam ediyor.
2 = 64mb alloc limit 32 mb input limit ve write boyut limiti ve kontrolü koyduk ve sadece o saldırganın yaptığı client kesiliyor sunucu çökmüyor.
3 = Bilinmeyen paket , flood ban tetikletmek ve bağlantıyı kapatmak ve ipyi definede belirtilen zamana göre banlamak
Ekstra alabileceğiniz önlemler ;
- slowloris bunu bilen bilir ben kısaca özetliyorum ; her 9 saniyede 1 byte gönderirse gönderen kişi 10 saniye timeout tetiklemez gibi ( rakamları isteidğiniz gibi ayarlayabilirsiniz.
- Geçerli paket spam yapabilirsiniz ; oyuna girip geçerli paketleri bağırma sohbeti , yürümek atak yapmak vs vs.. bunlar binlerce kez gönderildiği için flood koruması tetiklenmez. ( Bu karmaşıktır kendi sourcemde bulunuyor fakat aynısını paylaşmak istemiyorum ilerleyen günlerde belki değiştirerek paylaşabilirim. Bunu yapmasanızda zaten aşamayacak çünkü bu yukarıda anlatılanlar anormal bir durum değildir yani yetenek gerektirmeden 3-5 bilgiyle lamer olabiliyorsunuz)
- ve tabiki yoğun trafik ve tamamen abartarak aşırı güvenliğe kaçmak istiyorsanız firewall + os seviyesinde çözmeniz gerekir bunuda sunucu sağlayıcınız yapabilir. Bunlar kod değil sunucuyla alakalıdır.
==== Yukarıdaki 3 adım kapsamlı geliştirmelerdir.. Sunucu sağlayıcınızla konuşmalısınız. ====
libthecore klasörü içerisinde buffer.c dosyasını aç dosya başı includelerden sonra ekle ;
libthecore/buffer.c:
Kod:
#define MAX_BUFFER_ALLOC_SIZE (64 * 1024 * 1024)
1- buffer_new() fonsksiyonunu bulun içinde if (size < 0) return NULL; kontrolü var bu kontrolün hemen altına LPBUFFER buffer = NULL; satırından önce ekle ;
LPBUFFER buffer_new(int size)
{
if (size < 0) {
return NULL;
}
// --- buradan itibaren ekleyin ---
if (size > MAX_BUFFER_ALLOC_SIZE) {
sys_err("buffer_new: size %d exceeds max %d", size, MAX_BUFFER_ALLOC_SIZE);
abort();
}
// --- BURAYA KADAR ---
LPBUFFER buffer = NULL; // -- bu satır zaten var, dokunma
// ... devamı aynı
```
2- buffer_realloc() fonksiyonunu bul dosyanın sonlarına doğru içinde assert(length >= 0 ...) satırı var Bu assertin hemen altına
if (buffer->mem_size >= length) satırından önce ekle ;
void buffer_realloc(LPBUFFER& buffer, int length)
{
assert(length >= 0 && "buffer_realloc: length is lower than zero");
// --- BURADAN ITIBAREN EKLEYIN ---
if (length >= MAX_BUFFER_ALLOC_SIZE) {
sys_err("buffer_realloc: length %d exceeds max %d", length, MAX_BUFFER_ALLOC_SIZE);
abort();
}
// --- BURAYA KADAR ---
if (buffer->mem_size >= length) // ---- bu satır zaten var dokunma
return;
// ... devamı aynı
3- buffer_read_proceed() okuma taşma kontrolü için buffer_read_proceed() fonksiyonunu bul içinde if (length < buffer->length) blogu var bu blogun içinde;
buffer->read_point += length; satırından önce şu kodu ekle ;
void buffer_read_proceed(LPBUFFER buffer, int length)
{
if (length == 0)
return;
// ... mevcut length kontrolu ...
if (length < buffer->length)
{
// --- BURADAN ITIBAREN EKLEYIN ---
if (buffer->read_point + length - buffer->mem_data > buffer->mem_size)
{
sys_err("buffer_read_proceed: buffer overflow! length %d read_point %d",
length, buffer->read_point - buffer->mem_data);
abort();
}
// ---BURAYA KADAR ---
buffer->read_point += length; // -- bu satır saten var
buffer->length -= length;
}
// devamı aynı
buffer_manager.h:
Kod:
1- #define __INC_METIN_II_GAME_BUFFER_MANAGER_H__ satirinin hemen altına
bu defineyi ekle ;
#define MAX_SAFE_TEMP_BUFFER_WRITE_SIZE (64 * 1024 * 1024)
2- TEMP_BUFFER sınıfında eski void write(...) satırını bul ve bool ile değiştir ;
bool write(const void* data, int size);
NOT : eski kodda void write idi artık bool dönecek false geçersiz boyut ve sadece o client kesilir.
NOT : Template overload ekleme aynı imzaya sahip iki template derlerken hata verir.
Değişiklik sonrası şöyle görünecek ;
#define MAX_SAFE_TEMP_BUFFER_WRITE_SIZE (64 * 1024 * 1024)
class TEMP_BUFFER
{
public:
TEMP_BUFFER(int Size = 8192, bool ForceDelete = false);
~TEMP_BUFFER();
const void * read_peek();
bool write(const void* data, int size);
int size();
void reset();
LPBUFFER getptr() { return buf; }
protected:
LPBUFFER buf;
bool forceDelete;
};
#endif
buffer_manager.cpp:
Kod:
buffer_manager.cpp içerisinde void TEMP_BUFFER::write(...) fonksiyonu bul ve tamamen aşağıdakiyle değiştir;
bool TEMP_BUFFER::write(const void* data, int size)
{
if (size < 0 || size >= MAX_SAFE_TEMP_BUFFER_WRITE_SIZE)
{
sys_err("TEMP_BUFFER::write: invalid size %d (max %d)", size, MAX_SAFE_TEMP_BUFFER_WRITE_SIZE);
return false;
}
buffer_write(buf, data, size);
return true;
}
[B]NOT : db/src/buffer_manager.h ve db/src/buffer_manager.cpp dosyalarına da aynı değişiklikleri uygulayın. Game tarafıyla birebir aynıdır.[/B]
desc.h:
Kod:
desc sınıfında değişkenleri bul ; m_dwClientTime ve m_bHandshaking
satirlarini arayın. m_bHandshaking satirinin hemen altına ekle:
DWORD m_dwClientTime; // ----var olan satır
bool m_bHandshaking; // ---- var olan satır
DWORD m_dwConnectTime; // --- Bunu ekle - timeout için bu
desc.cpp:
Kod:
Bu dosya çok önemli burayı dikkatlice okuyun en çok değişiklik burada yapıldı.
#include "shutdown_manager.h"
satırını veya son include satırını bul tüm includelardan sonra DESC::DESC() constructordan
önce ekle ;
#include <map>
#include <string>
extern int max_bytes_written;
extern int current_bytes_written;
extern int total_bytes_written;
// ========== flood koruma start ========== //
#define MAX_CONNECTIONS_PER_IP 10 // Ayni IP'den max eş zamanlı bağlantı //
#define HANDSHAKE_TIMEOUT_SEC 10 // Handshake icin max bekleme süresi //
#define BAD_PACKET_BAN_THRESHOLD 3 // 3 pakette geçici ban //
#define TEMP_BAN_DURATION_SEC 60 // Gecici ban suresi (saniye) //
Yukarıdakilerle sayılarla oynama yapabilirsiniz
static std::map<std::string, int> s_mapIPConnCount;
static std::map<std::string, int> s_mapIPBadPacketCount;
static std::map<std::string, DWORD> s_mapIPTempBan;
static bool IsIPTempBanned(const std::string& stIP)
{
auto it = s_mapIPTempBan.find(stIP);
if (it == s_mapIPTempBan.end())
return false;
if (get_global_time() - it->second > TEMP_BAN_DURATION_SEC)
{
s_mapIPTempBan.erase(it);
s_mapIPBadPacketCount.erase(stIP);
return false;
}
return true;
}
void FloodProtection_AddBadPacket(const std::string& stIP)
{
int& count = s_mapIPBadPacketCount[stIP];
++count;
if (count >= BAD_PACKET_BAN_THRESHOLD)
{
s_mapIPTempBan[stIP] = get_global_time();
sys_err("FLOOD: IP %s temp banned (%d bad packets)", stIP.c_str(), count);
}
}
void FloodProtection_Cleanup()
{
DWORD dwNow = get_global_time();
for (auto it = s_mapIPTempBan.begin(); it != s_mapIPTempBan.end(); )
{
if (dwNow - it->second > TEMP_BAN_DURATION_SEC * 2)
{
s_mapIPBadPacketCount.erase(it->first);
it = s_mapIPTempBan.erase(it);
}
else
++it;
}
for (auto it = s_mapIPBadPacketCount.begin(); it != s_mapIPBadPacketCount.end(); )
{
if (s_mapIPTempBan.find(it->first) == s_mapIPTempBan.end())
it = s_mapIPBadPacketCount.erase(it);
else
++it;
}
}
/* ========== -flood koruma son satır ========== */
-@ DESC::Initialize() içinde DESC::Initialize() fonksiyonu bul ve içinde;
_pkDisconnectEvent = NULL; satırını ara ve bu satırdan sonra ekle ;
m_pkDisconnectEvent = NULL; // var olan satır
m_dwConnectTime = 0; // >>> bunu ekle
-@ DESC::Destroy() içinde ; m_bDestroyed = true; satırı ara ve bu satırdan hemen sonra
if (m_pkLoginKey) satırından önce ekle ;
m_bDestroyed = true; // ---- var olan satır
// >>> buradan itibaren ekle >>>
// Baglanti sayaç to reduce //
if (!m_stHost.empty())
{
auto it = s_mapIPConnCount.find(m_stHost);
if (it != s_mapIPConnCount.end())
{
if (--it->second <= 0)
s_mapIPConnCount.erase(it);
}
}
// --- buraya kadar ---
if (m_pkLoginKey) // ---- var olan satır
// ... devami ayni
-@ DESCT::Setup() içinde ;
- m_dwHandle = _handle; SATIRINI ARA VE BU SATIRDAN HEMEN SONRA ;
m_lpOutputBuffer = buffer_new(...) satırından önce ekle
m_dwHandle = _handle; // ---- var olan satır
// --- BURADAN İTİBAREN EKLE---
// Geçici banned kontrol //
if (IsIPTempBanned(m_stHost))
{
sys_log(0, "FLOOD: connection rejected (temp banned) from %s", m_stHost.c_str());
return false;
}
// İp bağlantı limit //
int& connCount = s_mapIPConnCount[m_stHost];
if (connCount >= MAX_CONNECTIONS_PER_IP)
{
sys_err("FLOOD: too many connections (%d) from %s, rejecting", connCount, m_stHost.c_str());
FloodProtection_AddBadPacket(m_stHost);
return false;
}
++connCount;
// Handshake timeout //
m_dwConnectTime = get_global_time();
// --- BURAYA KADAR ---
m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2); //--- bu satir zaten var
// ... devamı aynı
-@ DESC::ProcessInput()` fonksiyonunu bulun. içinde ssize_t bytes_read; satırını ara.
Bu satırdan hemen sonra, if (!m_lpInputBuffer) satirindan önce ekle:
ssize_t bytes_read; // ---- var olan satır
// ---- buradan itibaren ekle --
// Handshake timeout //
if (m_iPhase == PHASE_HANDSHAKE && m_dwConnectTime > 0)
{
if (get_global_time() - m_dwConnectTime > HANDSHAKE_TIMEOUT_SEC)
{
sys_err("FLOOD: handshake timeout (%ds) from %s", HANDSHAKE_TIMEOUT_SEC, m_stHost.c_str());
FloodProtection_AddBadPacket(m_stHost);
return -1;
}
}
// ---- BURAYA KADAR ----
if (!m_lpInputBuffer) // -- var olan satır
// ... devamı aynı
-@ Aynı fonksiyonda buffer_write_proceed(m_lpInputBuffer, bytes_read); satırı bul.
Bu satırdan hemen sonra, if (!m_pInputProcessor) satırından ÖNCE ekleyin:
buffer_write_proceed(m_lpInputBuffer, bytes_read);
// EKLENDI - 32MB input buffer limti //
#define MAX_SAFE_INPUT_BUFFER_SIZE (32 * 1024 * 1024)
if (buffer_size(m_lpInputBuffer) > MAX_SAFE_INPUT_BUFFER_SIZE)
{
sys_err("DESC::ProcessInput: input buffer too large (%u bytes) from %s",
(unsigned)buffer_size(m_lpInputBuffer), m_stHost.c_str());
return -1;
}
#undef MAX_SAFE_INPUT_BUFFER_SIZE
if (!m_pInputProcessor)
// ... devamı anyı
-@ USE_IMPROVED_PACKET_DECRYPTED_BUFFER aktifse, ProcessInput() içinde aşağıdaki
while döngüyü bulun. döngünün açılış parantezinden hemen sonra,
processingPoint += iBytesProceed; satirindan ÖNCE ekleyin:
while (processingRemainSize > 0 &&
!m_pInputProcessor->Process(this, (const void*)processingPoint,
processingRemainSize, iBytesProceed))
{
// ---- buradan itibaren ekle ----
if (iBytesProceed == 0)
{
sys_err("DESC::ProcessInput: Process() returned 0 bytes from %s", m_stHost.c_str());
return -1;
}
// ---- BURAYA KADAR ----
processingPoint += iBytesProceed; // <-- zten var
// ... devami ayni
-@ USE_IMPROVED_PACKET_DECRYPTED_BUFFER aktifse, ProcessInput() içinde tum
temporary.write(...) ve m_lpInputDecryptedBuffer.write(...) çağrıları bukl.
Her birini if (!...) ile sarmalayip başarısızlıkta return -1; ekleyin:
// ÖNCESİ (eski kod): //
temporary.write(m_lpInputDecryptedBuffer.read_peek(), m_lpInputDecryptedBuffer.size());
// SONRASI (yeni kod) - ayni satırı asagidaki gibi değiştir: //
if (!temporary.write(m_lpInputDecryptedBuffer.read_peek(), m_lpInputDecryptedBuffer.size()))
return -1;
Not: ProcessInput() içindeki tüm .write() çağrılarına bunu yap
-@ DESC::ChatPacket() fonksiyonunu bul içinde TEMP_BUFFER buf; satırını ara.
Eski buf.write(...) cagrilarini if (!buf.write(...)) ile değiştirr:
TEMP_BUFFER buf;
// öncesi: buf.write(&pack_chat, ...); buf.write(chatbuf, len);
// sonrası:
if (!buf.write(&pack_chat, sizeof(struct packet_chat)) || !buf.write(chatbuf, len))
return;
Packet(buf.read_peek(), buf.size());
Buraya kadar desc.cpp bitti.
main.cpp:
Kod:
io_loop() fonksiyonunu bul. Fonksiyonun başındaki değişken tanımlarının hemen altına,
DESC_MANAGER::instance().DestroyClosed(); satırından önce ekleyin:
Ayrica dosyanin basina (veya io_loop` fonksiyonundan once) extern tanimini ekleyin:
extern void FloodProtection_Cleanup(); // ---- BUNU dosya başına ekleyin
int io_loop(LPFDWATCH fdw)
{
LPDESC d;
int num_events, event_idx; // bu satrlar zaten var
// ---- buradan itibaren ekle ----
{
static DWORD s_dwLastCleanup = 0;
DWORD dwNow = get_global_time();
if (dwNow - s_dwLastCleanup > 60)
{
FloodProtection_Cleanup();
s_dwLastCleanup = dwNow;
}
}
// ---- BURAYA KADAR ----
DESC_MANAGER::instance().DestroyClosed(); //
// ... devamı aynı kalsın
input.cpp:
Kod:
CInputHandshake::Analyze() (veya CInputHandshake) fonksiyonunu bulun. Icinde
if (d->GetHandshake() != p->dwHandshake) satırını ara. Eski sys_err'den sonra,
--kapanış parantezinden çönce-- şu iki satırı ekleyin:
if (d->GetHandshake() != p->dwHandshake)
{
sys_err("Invalid Handshake on %d", d->GetSocket()); // ---- var olan satır
// ---- Bbunları ekle ----
extern void FloodProtection_AddBadPacket(const std::string& stIP);
FloodProtection_AddBadPacket(d->GetHostName());
d->SetPhase(PHASE_CLOSE);
// ---
Ayni fonksiyonun switch/if yapısının en altindaki else (veya default) bloğunu bul.
Eski sys_err'den sonra şu sattrları ekle;
else
{
sys_err("Handshake phase does not handle packet %d (fd %d) ip : %s",
bHeader, d->GetSocket(), d->GetHostName()); // --- varolan satır
// >>> BUNLARI EKLEYIN >>>
extern void FloodProtection_AddBadPacket(const std::string& stIP);
FloodProtection_AddBadPacket(d->GetHostName());
d->SetPhase(PHASE_CLOSE);
// <<< <<<
return -1;
}
input_auth.cpp:
Kod:
CInputAuth::Analyze()`fonksiyonundaki switch'in default case'yi bul.
Eski sys_err'den sonra şunları ekle:
default:
sys_err("This phase does not handle this header %d (0x%x)(phase: AUTH ip : %s)",
bHeader, bHeader, d->GetHostName()); // <-- var olan satır
// >>> BUNLARI EKLEYIN >>>
{
extern void FloodProtection_AddBadPacket(const std::string& stIP);
FloodProtection_AddBadPacket(d->GetHostName());
d->SetPhase(PHASE_CLOSE);
}
// <<< <<<
return -1;
input_login.cpp:
Kod:
CInputLogin::Analyze() fonksiyonundaki switch'in default: case'ii bulun.
default:
sys_err("login phase does not handle this packet! header %d login cpp ip : %s",
bHeader, d->GetHostName()); // <-- var olan satır
// >>> BUNLARI EKLEYIN >>>
{
extern void FloodProtection_AddBadPacket(const std::string& stIP);
FloodProtection_AddBadPacket(d->GetHostName());
d->SetPhase(PHASE_CLOSE);
}
// <<< <<<
return -1;
input_main.cpp:
Kod:
CInputMain::Analyze() fonksiyonundaki switch'in default: case'i bul Eger default: case yoksa ekleyin.
default:
sys_err("game phase does not handle this packet! header %d ip : %s",
bHeader, d->GetHostName());
// >>> BUNLARI EKLEYIN >>>
{
extern void FloodProtection_AddBadPacket(const std::string& stIP);
FloodProtection_AddBadPacket(d->GetHostName());
d->SetPhase(PHASE_CLOSE);
}
// <<< <<<
return -1;
input_p2p.cpp:
Kod:
CInputP2P::Analyze() fonksiyonundaki switch'in default: case'ini bulun.
Eger default: case yoksa ekleyin:
default:
sys_err("P2P phase does not handle this packet! header %d ip : %s",
bHeader, d->GetHostName());
return -1; // bağlantı kesilir, flood ban yetki yok dahili
NOT : tüm değişiklikleri ifdef ile sarmalamadım koşulsuz olarak uyguladım çünkü güvenlik kodu isteğe bağlı olmamalıdır. İsteyen ifdefli yapsın.
NOT : mysql/mariadb server.cnf için ise yani ;
max_allowed_packet =
max_connections =
wait_timeout =
interactive_timeout =
net_read_timeout =
net_write_timeout =
buradaki değerleri sunucu sağlayıcınız ayarlasın.
Metin2 Bufferoverflow Fix – “Mouse’ye Sert Basan Lamer” Sorunu ve Çözümü
Metin2 private server geliştirenlerin dönem dönem karşılaştığı teknik problemlerden biri de istemci taraflı tetiklenen buffer overflow kaynaklı çökme veya exploit açıklarıdır. Özellikle halk arasında “mouse’ye sert basan lamer fixi” diye anılan durum, aslında hızlı ve anormal input spam’i sonucu oluşan bellek taşmalarına dayanır.Bu makalede sorunun teknik mantığını, nasıl oluştuğunu ve sunucu–istemci tarafında nasıl kalıcı şekilde fixlenebileceğini ele alıyoruz.
Sorun Nedir?
Buffer overflow (bellek taşması), bir değişkene ayrılan bellek alanından daha fazla veri yazılmaya çalışıldığında ortaya çıkar. Metin2 istemcisinde bazı eski sürümlerde:- Hızlı mouse click spam
- Skill butonuna milisaniyelik aralıklarla tekrar basma
- Packet flood (input flood)
- UI event queue overflow
Sonuç olarak:
- Client crash
- Sunucuya bozuk packet gönderimi
- Hile exploit girişimleri
- Syserr spam
- Channel kapanmaları
Bu Açık Nasıl Kullanılıyordu?
Bazı “lamer” diye tabir edilen kullanıcılar:- Auto clicker kullanarak saniyede yüzlerce input üretir
- Skill kullanımını flood eder
- Attack komutunu abnormal hızda tetikler
- Character state bozulabilir
- Combat queue taşabilir
- Sunucu taraflı crash tetiklenebilir
Client Tarafı Fix Önerileri
Input Rate Limiter Eklemek
Mouse click veya skill event’lerinde:- Son işlem zamanı tutulmalı
- Minimum 50–100 ms cooldown kontrolü yapılmalı
if (current_time - last_click_time < MIN_DELAY)
return;
Bu basit kontrol bile %80 exploit’i keser.
Event Queue Sınırı Koymak
UI event stack büyüyorsa:- Maksimum event sayısı belirlenmeli
- Limit aşılırsa eski event’ler drop edilmeli
Güvenli String ve Buffer Kullanımı
Eski Metin2 client kodlarında:- strcpy
- sprintf
Bunların yerine:
- strncpy
- snprintf
Aksi halde packet parsing sırasında overflow oluşabilir.
Server Tarafı Asıl Önemli Fix
Client fix tek başına yeterli değildir. Asıl koruma server tarafında olmalıdır.
Packet Rate Limit
Her karakter için:- Saniyelik maksimum attack packet sayısı
- Skill kullanım limiti
- Hareket komutu limiti
Örneğin:
- 1 saniyede 15’ten fazla attack packet → ignore
- 1 saniyede 5’ten fazla skill → reject
Packet Validation
Server tarafında:- Skill cooldown kontrolü
- Attack speed doğrulaması
- Position check
Client’a asla güvenilmez.
Crash Koruma
- Exception handling eklenmeli
- Invalid packet geldiğinde connection drop edilmeli
- Core dump analiz edilip stack trace incelenmeli
Performans ve Stabiliteye Etkisi
Doğru uygulanmış bir bufferoverflow fix:- Sunucu stabilitesini artırır
- PvP exploitlerini azaltır
- Syserr spam’i düşürür
- Channel crash riskini minimize eder
Sonuç
“Mouse’ye sert basan lamer fixi” olarak bilinen problem aslında:kombinasyonudur.Input spam + yetersiz sınır kontrolü + güvensiz bellek yönetimi
Gerçek çözüm:
- Client tarafında rate limit
- Server tarafında packet doğrulama
- Güvenli buffer kullanımı
- Flood koruması
Eğer private server geliştiriyorsan, bu fix’i sadece crash önleme değil aynı zamanda exploit kapatma perspektifiyle düşünmelisin.
En
Metin2 Buffer Overflow Fix – The “Mouse Spam Lamer” Issue and Its Solution
One of the technical problems that private server developers occasionally encounter in Metin2 is client-side triggered crashes or exploit vulnerabilities caused by buffer overflow. The issue commonly referred to as the “mouse spam lamer fix” is actually based on memory overflows caused by rapid and abnormal input spamming.
In this article, we will examine the technical logic behind the problem, how it occurs, and how it can be permanently fixed on both the server and client sides.
What Is the Problem?
A buffer overflow occurs when more data is written to a memory space than it was allocated for. In some older Metin2 client versions:
- Rapid mouse click spam
- Repeated skill button presses within milliseconds
- Packet flood (input flood)
- UI event queue overflow
could be processed without proper boundary checks.
As a result:
- Client crashes
- Corrupted packet transmission to the server
- Exploit attempts
- Syserr spam
- Channel shutdowns
could occur.
How Was This Exploit Used?
Some users would:
- Use auto-clickers to generate hundreds of inputs per second
- Flood skill usage
- Trigger attack commands at abnormal speeds
If there is no rate limit on the server:
- Character state may become corrupted
- Combat queues may overflow
- Server-side crashes may occur
This is not about pressing the mouse hard; it is about uncontrolled input processing.
Client-Side Fix Suggestions
Add an Input Rate Limiter
For mouse clicks or skill events:
- Store the last processing time
- Apply a minimum 50–100 ms cooldown check
Even this simple control prevents most exploit attempts.
Limit the Event Queue
If the UI event stack grows excessively:
- Define a maximum event count
- Drop older events if the limit is exceeded
This significantly reduces overflow risk.
Use Safe String and Buffer Functions
Older Metin2 client code may contain unsafe functions such as:
- strcpy
- sprintf
These should be replaced with:
- strncpy
- snprintf
Otherwise, packet parsing may cause buffer overflows.
Server-Side – The Critical Fix
Client-side fixes alone are not enough. The real protection must be on the server side.
Packet Rate Limiting
For each character:
- Maximum attack packets per second
- Skill usage limits
- Movement command limits
For example:
- More than 15 attack packets per second → ignore
- More than 5 skills per second → reject
Packet Validation
Server-side checks must include:
- Skill cooldown validation
- Attack speed verification
- Position checks
Never trust the client.
Crash Protection
- Add exception handling
- Drop connections when invalid packets are received
- Analyze core dumps and stack traces
Performance and Stability Impact
A properly implemented buffer overflow fix:
- Increases server stability
- Reduces PvP exploits
- Lowers syserr spam
- Minimizes channel crash risk
The difference becomes significant at high online player counts.
Conclusion
The issue known as the “mouse spam lamer fix” is actually a combination of:
Input spam + insufficient boundary checks + unsafe memory management
The real solution requires layered security:
- Client-side rate limiting
- Server-side packet validation
- Safe buffer usage
- Flood protection
If you are developing a private server, you should consider this fix not only as crash prevention but also from an exploit mitigation perspective.
De
Metin2 Buffer-Overflow-Fix – Das „Mouse-Spam-Lamer“-Problem und seine Lösung
Eines der technischen Probleme, mit denen Entwickler von Private-Servern in Metin2 gelegentlich konfrontiert werden, sind clientseitig ausgelöste Abstürze oder Exploit-Schwachstellen durch Buffer Overflow. Das sogenannte „Mouse-Spam-Lamer-Fix“-Problem basiert tatsächlich auf Speicherüberläufen, die durch schnelles und ungewöhnliches Input-Spamming entstehen.
In diesem Artikel erklären wir die technische Ursache, wie das Problem entsteht und wie es dauerhaft auf Client- und Serverseite behoben werden kann.
Was ist das Problem?
Ein Buffer Overflow entsteht, wenn mehr Daten in einen Speicherbereich geschrieben werden, als dafür reserviert wurde. In einigen älteren Metin2-Client-Versionen konnten:
- Schnelles Mausklick-Spamming
- Mehrfaches Drücken von Skills in Millisekunden
- Packet-Flood (Input-Flood)
- UI-Event-Queue-Überlauf
ohne ausreichende Grenzprüfungen verarbeitet werden.
Dies führte zu:
- Client-Abstürzen
- Beschädigten Paketen
- Exploit-Versuchen
- Syserr-Spam
- Channel-Abstürzen
Wie wurde dies ausgenutzt?
Einige Nutzer:
- Verwendeten Auto-Clicker
- Floodeten Skills
- Sendeten Angriffs-Befehle mit abnormaler Geschwindigkeit
Ohne Server-Rate-Limit:
- Kann der Charakterstatus beschädigt werden
- Kann die Combat-Queue überlaufen
- Können Server-Abstürze auftreten
Es geht nicht um starkes Klicken, sondern um unkontrollierte Input-Verarbeitung.
Fazit
Das als „Mouse-Spam-Lamer-Fix“ bekannte Problem ist eine Kombination aus:
Input-Spam + fehlende Grenzprüfungen + unsichere Speicherverwaltung
Die echte Lösung besteht aus:
- Clientseitigem Rate-Limit
- Serverseitiger Paketvalidierung
- Sicherer Buffer-Nutzung
- Flood-Schutz
Wenn du einen Private-Server entwickelst, solltest du dieses Fix nicht nur als Crash-Prävention betrachten, sondern auch als Schutz vor Exploits.
Metin2 Fix Buffer Overflow – Problema „Mouse Spam Lamer” și Soluția
Una dintre problemele tehnice întâlnite de dezvoltatorii de servere private în Metin2 este reprezentată de crash-uri sau vulnerabilități de tip buffer overflow declanșate din client. Problema cunoscută ca „mouse spam lamer fix” este de fapt cauzată de overflow de memorie generat de input rapid și anormal.
În acest articol explicăm cauza tehnică, modul în care apare și cum poate fi rezolvată permanent atât pe partea de client, cât și pe partea de server.
Care este problema?
Un buffer overflow apare atunci când se scriu mai multe date într-o zonă de memorie decât spațiul alocat. În unele versiuni vechi ale clientului Metin2:
- Spam rapid de click-uri
- Apăsarea repetată a skill-urilor în milisecunde
- Packet flood
- Overflow în coada de evenimente UI
erau procesate fără verificări adecvate.
Rezultatul putea fi:
- Crash client
- Pachete corupte
- Tentative de exploit
- Spam în syserr
- Căderi de channel
Concluzie
Problema numită „mouse spam lamer fix” este combinația dintre:
Spam de input + lipsa verificărilor de limită + management nesigur al memoriei
Soluția reală necesită:
- Limitare de input pe client
- Validare de pachete pe server
- Utilizarea bufferelor sigure
- Protecție anti-flood
Dacă dezvolți un server privat, ar trebui să privești acest fix nu doar ca prevenție împotriva crash-urilor, ci și ca metodă de blocare a exploit-urilor.
Tamam kanka
Aşağıda makalenin, belirttiğin yere kadar olan kısmının Lehçe (Polski) çevirisi yer alıyor.
Metin2 Buffer Overflow Fix – Problem „Mouse Spam Lamer” i jego rozwiązanie
Jednym z problemów technicznych, z którymi od czasu do czasu spotykają się twórcy prywatnych serwerów Metin2, są crashe klienta lub luki typu buffer overflow wywoływane po stronie klienta. Problem znany jako „mouse spam lamer fix” w rzeczywistości wynika z przepełnienia pamięci spowodowanego szybkim i nienaturalnym spamowaniem inputów.W tym artykule omawiamy techniczne podstawy problemu, sposób jego powstawania oraz to, jak można go trwale naprawić zarówno po stronie klienta, jak i serwera.
Na czym polega problem?
Buffer overflow (przepełnienie bufora) występuje wtedy, gdy do obszaru pamięci zapisuje się więcej danych, niż zostało dla niego przydzielone. W niektórych starszych wersjach klienta Metin2:- Szybkie spamowanie kliknięć myszą
- Wielokrotne naciskanie skilli w odstępach milisekund
- Packet flood (spam pakietów)
- Przepełnienie kolejki zdarzeń UI
W rezultacie mogło to prowadzić do:
- Crashy klienta
- Wysyłania uszkodzonych pakietów do serwera
- Prób wykorzystania exploitów
- Spamu w plikach syserr
- Wyłączania channeli
Jak był wykorzystywany ten exploit?
Niektórzy użytkownicy:- Używali auto-clickerów generujących setki inputów na sekundę
- Floodowali użycie skilli
- Wywoływali komendy ataku z nienaturalną prędkością
- Stan postaci mógł ulec uszkodzeniu
- Kolejka walki mogła się przepełnić
- Mogło dojść do crasha serwera
Propozycje poprawek po stronie klienta
Dodanie ograniczenia częstotliwości inputów (Rate Limiter)
Dla kliknięć myszy lub zdarzeń skilli należy:- Zapisywać czas ostatniego przetworzenia
- Wprowadzić minimalny odstęp 50–100 ms
Ograniczenie kolejki zdarzeń
Jeśli kolejka zdarzeń UI rośnie zbyt mocno:- Należy ustalić maksymalną liczbę zdarzeń
- Po przekroczeniu limitu usuwać najstarsze zdarzenia
Używanie bezpiecznych funkcji dla stringów i buforów
W starszym kodzie klienta Metin2 można znaleźć niebezpieczne funkcje, takie jak:- strcpy
- sprintf
- strncpy
- snprintf
Strona serwera – kluczowa poprawka
Poprawki po stronie klienta nie są wystarczające. Prawdziwa ochrona musi znajdować się po stronie serwera.
Ograniczenie liczby pakietów (Packet Rate Limit)
Dla każdej postaci należy określić:- Maksymalną liczbę pakietów ataku na sekundę
- Limit użycia skilli
- Limit komend ruchu
- Więcej niż 15 pakietów ataku na sekundę → ignoruj
- Więcej niż 5 skilli na sekundę → odrzuć
Walidacja pakietów
Po stronie serwera należy sprawdzać:- Cooldown skilli
- Rzeczywistą prędkość ataku
- Pozycję postaci
Ochrona przed crashami
- Dodać obsługę wyjątków (exception handling)
- Zamykać połączenie przy otrzymaniu nieprawidłowych pakietów
- Analizować core dump i stack trace
Wpływ na wydajność i stabilność
Poprawnie wdrożony fix buffer overflow:- Zwiększa stabilność serwera
- Ogranicza exploity PvP
- Zmniejsza spam w syserr
- Minimalizuje ryzyko crashy channeli
Podsumowanie
Problem znany jako „mouse spam lamer fix” to w rzeczywistości połączenie:Prawdziwe rozwiązanie wymaga wielowarstwowego podejścia:Spam inputów + brak kontroli granic + niebezpieczne zarządzanie pamięcią
- Ograniczenie inputów po stronie klienta
- Walidacja pakietów po stronie serwera
- Używanie bezpiecznych buforów
- Ochrona przed floodem
