GİRİŞ & PROBLEM
Merhaba, bugün komutlarda beklenmeyen negatif (-) bir arg (sayı) vererek (Örnek; /mob 101 -1) core düşmesine sebep olan hata başta olmak üzere bir kaç hatayı fixleyeceğiz ayrıca fonksiyonların ChatPacket kullanımlarını da düzenleyeceğiz.
NEDEN ?
GM'lar zaten ekibin bir parçası buna neden gerek duyalım diyebilirsiniz, haklısınız fakat bunu kodlama bilgisi olmayan GM'ın yanlışlıkla tetikleyebileceğini de unutmayın, işimizi şansa bırakmayalım.
ÇÖZÜM
Yapacağımız işlem basit, verilen arg değerinin istediğimiz aralıkta olduğuna emin olmamız yeterli olacaktır, başlayalım.
Merhaba, bugün komutlarda beklenmeyen negatif (-) bir arg (sayı) vererek (Örnek; /mob 101 -1) core düşmesine sebep olan hata başta olmak üzere bir kaç hatayı fixleyeceğiz ayrıca fonksiyonların ChatPacket kullanımlarını da düzenleyeceğiz.
NEDEN ?
GM'lar zaten ekibin bir parçası buna neden gerek duyalım diyebilirsiniz, haklısınız fakat bunu kodlama bilgisi olmayan GM'ın yanlışlıkla tetikleyebileceğini de unutmayın, işimizi şansa bırakmayalım.
ÇÖZÜM
Yapacağımız işlem basit, verilen arg değerinin istediğimiz aralıkta olduğuna emin olmamız yeterli olacaktır, başlayalım.
Kod:
// (cmd_gm.cpp) BULUNUR; ACMD (do_mob) // KOMPLE DEGISTIRILIR; ACMD (do_mob) { char arg1[256], arg2[256]; DWORD vnum = 0; two_arguments (argument, arg1, sizeof (arg1), arg2, sizeof (arg2)); if (!*arg1) { ch->ChatPacket (CHAT_TYPE_INFO, "Usage: /mob <mob vnum> <mob count>"); // Now it's correct.. - [MT2Dev Note] - 14/04/2024 return; } const CMob* pkMob = NULL; if (isnhdigit (*arg1)) { str_to_number (vnum, arg1); if ((pkMob = CMobManager::instance().Get (vnum)) == NULL) { vnum = 0; } } else { pkMob = CMobManager::Instance().Get (arg1, true); if (pkMob) { vnum = pkMob->m_table.dwVnum; } } if (vnum == 0) { ch->ChatPacket (CHAT_TYPE_INFO, "No such mob(%s) by that vnum", arg1); // I'm added info about vnum. - [MT2Dev Note] - 14/04/2024 return; } int iCount = 1; if (*arg2) { str_to_number (iCount, arg2); iCount = MINMAX (1, iCount, 40); // DevFix 121 } if (test_server) { iCount = MIN (40, iCount); } else { iCount = MIN (20, iCount); } while (iCount--) { CHARACTER_MANAGER::instance().SpawnMobRange (vnum, ch->GetMapIndex(), ch->GetX() - number (200, 750), ch->GetY() - number (200, 750), ch->GetX() + number (200, 750), ch->GetY() + number (200, 750), true, pkMob->m_table.bType == CHAR_TYPE_STONE); } } // (cmd_gm.cpp) BULUNUR; ACMD (do_mob_aggresive) // KOMPLE DEGISTIRILIR; ACMD (do_mob_aggresive) { char arg1[256], arg2[256]; DWORD vnum = 0; LPCHARACTER tch; two_arguments (argument, arg1, sizeof (arg1), arg2, sizeof (arg2)); if (!*arg1) { ch->ChatPacket (CHAT_TYPE_INFO, "Usage: /ma <mob vnum> <mob count>"); // Now it's correct.. - [MT2Dev Note] - 14/04/2024 return; } const CMob* pkMob; if (isdigit (*arg1)) { str_to_number (vnum, arg1); if ((pkMob = CMobManager::instance().Get (vnum)) == NULL) { vnum = 0; } } else { pkMob = CMobManager::Instance().Get (arg1, true); if (pkMob) { vnum = pkMob->m_table.dwVnum; } } if (vnum == 0) { ch->ChatPacket (CHAT_TYPE_INFO, "No such mob(%s) by that vnum", arg1); // I'm added info about vnum. - [MT2Dev Note] - 14/04/2024 return; } int iCount = 1; if (*arg2) { str_to_number (iCount, arg2); iCount = MINMAX (1, iCount, 40); // DevFix 121 } if (test_server) { iCount = MIN (40, iCount); } else { iCount = MIN (20, iCount); } while (iCount--) { tch = CHARACTER_MANAGER::instance().SpawnMobRange (vnum, ch->GetMapIndex(), ch->GetX() - number (200, 750), ch->GetY() - number (200, 750), ch->GetX() + number (200, 750), ch->GetY() + number (200, 750), true, pkMob->m_table.bType == CHAR_TYPE_STONE); if (tch) { tch->SetAggressive(); } } } // (cmd_gm.cpp) BULUNUR; ACMD (do_mob_coward) // KOMPLE DEGISTIRILIR; ACMD (do_mob_coward) { char arg1[256], arg2[256]; DWORD vnum = 0; LPCHARACTER tch; two_arguments (argument, arg1, sizeof (arg1), arg2, sizeof (arg2)); if (!*arg1) { ch->ChatPacket (CHAT_TYPE_INFO, "Usage: /mc <mob vnum> <mob count>"); // Now it's correct.. - [MT2Dev Note] - 14/04/2024 return; } const CMob* pkMob; if (isdigit (*arg1)) { str_to_number (vnum, arg1); if ((pkMob = CMobManager::instance().Get (vnum)) == NULL) { vnum = 0; } } else { pkMob = CMobManager::Instance().Get (arg1, true); if (pkMob) { vnum = pkMob->m_table.dwVnum; } } if (vnum == 0) { ch->ChatPacket (CHAT_TYPE_INFO, "No such mob(%s) by that vnum", arg1); // I'm added info about vnum. - [MT2Dev Note] - 14/04/2024 return; } int iCount = 1; if (*arg2) { str_to_number (iCount, arg2); iCount = MINMAX (1, iCount, 40); // DevFix 121 } if (test_server) { iCount = MIN (40, iCount); } else { iCount = MIN (20, iCount); } while (iCount--) { tch = CHARACTER_MANAGER::instance().SpawnMobRange (vnum, ch->GetMapIndex(), ch->GetX() - number (200, 750), ch->GetY() - number (200, 750), ch->GetX() + number (200, 750), ch->GetY() + number (200, 750), true, pkMob->m_table.bType == CHAR_TYPE_STONE); if (tch) { tch->SetCoward(); } } } // (cmd_gm.cpp) BULUNUR; ACMD (do_fishing_simul) // KOMPLE DEGISTIRILIR; ACMD (do_fishing_simul) // DevFix 121 { char arg1[256]; char arg2[256]; char arg3[256]; argument = one_argument (argument, arg1, sizeof (arg1)); two_arguments (argument, arg2, sizeof (arg2), arg3, sizeof (arg3)); unsigned char level = 100; unsigned char prob_idx = 0; int count = 1000; ch->ChatPacket (CHAT_TYPE_INFO, "Usage: /fishing_simul <level> <prob index> <count>"); ch->ChatPacket (CHAT_TYPE_INFO, "Limit: <level 0-100> <prob 0-100> <count 0-100000>"); if (*arg1) { if (level > 100) { return; } else { str_to_number (level, arg1); } } if (*arg2) { if (prob_idx > 100) { return; } else { str_to_number (prob_idx, arg2); } } if (*arg3) { if (count < 0 || count > 100000) { return; } else { str_to_number (count, arg3); } } fishing::Simulation (level, count, prob_idx, ch); } /* BİLGİ: */ Sıradaki yapacağımız işlem aslında bir core düşmesine sebebiyet vermeyebilir fakat eklenmesi gereken bir kontrol olduğu için onu da bunların arasında vermiş olayım. GM tarafından yang miktarı değiştirilen karakterin istemediğimiz bir miktarda yanga sahip olmasını engelleyelim; /* ÖNEMLİ NOT: */ Eğer "Extended Max Yang" sistemini kullanıyorsanız, yani "maksimum yang miktarını arttırdıysanız" aşağıdaki kodda yer alan tüm int olan bölümleri long long int ile DEĞİŞTİRİN! // (cmd_gm.cpp) BULUNUR; ACMD (do_set) // ICINDE BULUNUR; case 0: // KOMPLE DEGISTIRILIR; case 0: // Gold { int gold = 0; // If you use extended yang limit, change this int with long long int!!! - [MT2Dev Note] - 19/04/2024 str_to_number (gold, arg3); DBManager::instance().SendMoneyLog (MONEY_LOG_MISC, 3, gold); tch->PointChange (POINT_GOLD, gold, true); int after_gold = tch->GetGold(); // If you use extended yang limit, change this int with long long int!!!- [MT2Dev Note] - 19/04/2024 if (after_gold < 0) // DevFix 121 { tch->PointChange (POINT_GOLD, -after_gold, true); after_gold = 0; } if (after_gold > GOLD_MAX) // DevFix 121 { int difference = after_gold - GOLD_MAX; // If you use extended yang limit, change this int with long long int!!! - [MT2Dev Note] - 19/04/2024 tch->PointChange (POINT_GOLD, -difference, true); after_gold = GOLD_MAX; } } // Also useless log removed by me. - [MT2Dev Note] - 19/04/2024 break;
C++ GM Kodlarında Negatif Sayı Kullanarak Core Düşürme Fix
Metin2 özel sunucularında geliştirme yaparken genellikle yetkililer için özel komutlar (GM kodları) tanımlanır. Bu komutlar sayesinde yetkililer hızlıca belirli işlemleri gerçekleştirebilir. Ancak bazen bu komutların hatalı kullanımından veya kötü niyetli kullanıcıların istismarından dolayı sistemsel sorunlar ortaya çıkabilir. Bunlardan birisi de negatif sayı kullanımıyla sunucu core dosyasının düşmesidir.
Negatif Sayı Kullanımı ve Core Düşürme Tehlikesi
Bazı GM komutları, örneğin bir karaktere belirli miktarda altın eklemek, level yükseltmek ya da item vermek gibi işlemler yapılırken kullanıcıdan gelen değer doğrudan işlenirse, bu değer negatif olursa ciddi güvenlik açıklarına yol açabilir. Özellikle signed integer türlerinde yapılan işlemlerde negatif değerler doğrudan sistem üzerinde manipülasyona neden olabilir. Örneğin bir GM komutu ile oyuncuya -1000000 altın verildiğinde, oyuncunun altın bakiyesi beklenmedik şekilde artabilir ya da azalabilir. Bu durum core dosyasının çökmesine sebep olabilir.
Fix Uygulamaları
Bu tür güvenlik açıklarını engellemek için kodlarda bazı kontroller yapılması gerekir. Öncelikle tüm GM komutları için gelen parametrelerin kontrol edilmesi şarttır. Negatif değer alması istenmeyen işlemler için kontrol yapılmadan işlem yapılmamalıdır. Aşağıda örnek bir C++ kontrolü görebilirsiniz:
if (value < 0) {
LogError('Invalid value received: %d', value);
return false;
}
Bu şekilde, negatif değerler karşılaştığında işlem durdurulabilir ve loglama yapılabilir. Ayrıca değerlerin unsigned int olarak alınması da önerilir. Bu sayede doğal olarak negatif değer girişlerine izin verilmez.
Güvenlik Katmanları
Metin2 özel sunucularında güvenlik için sadece kod seviyesinde değil, aynı zamanda sunucu tarafında da ek kontroller yapılmalıdır. Örneğin, GM komutları sadece belirli IP adreslerinden çalıştırılabilir veya komutların loglanması sağlanabilir. Bu sayede olası istismarlar daha kolay takip edilebilir. Ayrıca, komutları kullanacak kişilerin güvenilir olması da büyük önem taşır. Güvenilmeyen kişilerin GM komutlarına erişimi kesinlikle olmamalıdır.
Sonuç
Metin2 özel sunucularında C++ seviyesinde yapılan GM kodlarında negatif sayı kullanımı, core dosyalarının çökmesine neden olabilir. Bu tür güvenlik açıklarını kapatmak için değer kontrolleri, tür dönüşümleri ve loglama gibi önlemler alınmalıdır. Bu şekilde hem sistem stabil kalır hem de yetkililerin komutları güvenli bir şekilde kullanılabilir. Daha fazla Metin2 geliştirme kaynağı için Metin2Lobby sitesini ziyaret edebilirsiniz.
Fixing Core Crashes in C++ GM Commands by Using Negative Numbers
While developing Metin2 private servers, special commands (GM codes) are often defined for administrators. These commands allow admins to perform certain operations quickly. However, misuse of these commands or abuse by malicious users can sometimes lead to system issues. One such issue is causing the server's core file to crash by using negative numbers.
Negative Number Usage and Core Crash Risk
Some GM commands, such as adding gold to a character, increasing levels, or giving items, can lead to serious security vulnerabilities if the values entered by the user are processed directly without validation. Especially in operations involving signed integer types, negative values can cause unexpected manipulations within the system. For example, if -1000000 gold is given to a player via a GM command, the player's gold balance may unexpectedly increase or decrease, potentially crashing the core file.
Fix Implementation
To prevent such security flaws, validations must be implemented in the code. All parameters received from GM commands should be checked. Operations that should not accept negative values must not proceed without validation. Here is an example of a C++ check:
if (value < 0) {
LogError('Invalid value received: %d', value);
return false;
}
In this way, if negative values are encountered, the process can be stopped and logged. Additionally, it is recommended to use unsigned int for values so that negative inputs are naturally rejected.
Security Layers
In addition to code-level fixes, further checks should also be implemented on the server side for Metin2 private servers. For instance, GM commands could be restricted to run only from specific IP addresses, or their usage could be logged. This allows easier tracking of potential abuses. Moreover, it is crucial that the individuals using these commands are trustworthy. Unauthorized access to GM commands must be avoided at all costs.
Conclusion
Using negative numbers in C++ GM commands on Metin2 private servers can cause core files to crash. To close such security gaps, input validations, type conversions, and logging measures should be implemented. This ensures both system stability and secure usage of admin commands. For more resources on Metin2 development, visit Metin2Lobby.
