baermitumlaut 62 Posted May 29, 2015 (edited) It recently came to my attention how many addons use vulnerable userconfig files. Almost all addons that use userconfig files are able to get exploited to execute custom code, and I only found very few exceptions (don't worry, ACE is safe!). To help addon makers to fix their addons to stop such vulnerabilities in the future and to make it public so hacks that currently use these ways become useless, I decided to make a little guide on how to save and how to not save user settings for your mod. Below is a list with of methods to save user settings, each with a short list of pros and cons and a short example how it could be used and how it can be abused. What you need to know first If you didn't know yet, #include simply copies the content of a file into the #include line. It does not care what you include, it does not care about the file extension, it does not execute anything on it's own, it's a very "stupid" command if you want to say it like that. However, that makes it very abusable, too. profileNamespace Variables ProfileNamespace variables can be easily set with setVariable and are a great way to save settings for your addon. Because you can save raw datatypes such as numbers and booleans, these don't allow any possible attack points unless you save code in them which you want to execute. Don't do that and everything is fine. +fast and easy to use +can be set in game -need an interface to be set -cannot be changed on servers Example: _settingA = profileNamespace getVariable ["MyAddon_settingA", false]; Malicious example: _settingA = call (profileNamespace getVariable ["MyAddon_settingACode", {false}]); Parsing files Parsing files manually (that means, you open a file and interprete its content manually without executing anything) is a safe way to read user settings. These files can be stored in the userconfig without any risks. However, it depends on the implementation of the parsing function how secure and how user friendly it is. I have implemented a safe parsing function for userconfig files here: https://github.com/BaerMitUmlaut/Arma-script-snippets/blob/master/fn_readConfig.sqf CBA also includes a YAML parsing function, you can find an example on how to use it here: https://github.com/CBATeam/CBA_A3/blob/master/addons/common/test_parseYaml.sqf +settings can be stored in a file & can be used on servers -safety depends on implementation -might be buggy if the user feeds you useless data Example: _settingA = ["\userconfig\MyAddon\settings.hpp", "settingA", "BOOL"] call MyAddon_fnc_readConfig; Malicious example: - Executing SQF files This is a very critical method. Make very sure that you are only doing this on the server! With this method, you save the settings as SQF code in a userconfig file, load it dynamically on startup and read its values. If this does not happen only on the server, the user can simply append any code he wants and it will get executed by your addon, even using signature files won't help with this! +easy to use +settings can be stored in a file & can be used on servers -very dangerous if not used only on the server -allows execution of any code the user puts into the file Example: //Safe: if (isServer) then {[] call compile preprocessFile "\userconfig\MyAddon\settings.sqf";}; //Unsafe: [] call compile preprocessFile "\userconfig\MyAddon\settings.sqf"; Malicious example: settings.sqf: MyAddon_settingA = false; player allowDamage false; Including SQF files This method can be exploited, no matter what you do. Do not use it! By including a file into your code, you allow that code to run within your (signed) addon. It cannot be detected and can do whatever it would like to do. This means that your addon can be the hole that lets malicious code run on a server. -allows execution of any code the user puts into the file Example: if (isServer) then { #include "userconfig\MyAddon\settings.sqf" }; Malicious example: settings.sqf: MyAddon_settingA = false;}; //here we closed the if bracket and can now write code that will be executed clientside player allowDamage false; //By doing something completly useless, we can avoid an SQF error that would detect the bracket that is one too much now (because we closed the if one already) waitUntil {true Including config files This method can be exploited, no matter what you do. Do not use it! By including a userconfig file into your config.cpp you allow that any custom config from the userconfig will be loaded. This could be changes to CfgVehicles (init event handlers!), CfgAmmo, or even worse, Extended Event Handlers. Those can only be used with CBA running, but so many addons require CBA anyways, so don't rely on that. -allows injection of any config changes the user puts into the file Example: MyAddon_settings { #include "userconfig\MyAddon\settings.hpp" }; Malicious example: settings.sqf: MyAddon_settingA = false;}; //here we closed the MyAddon_settings bracket and can now include any config changes that we want class Extended_PostInit_EventHandlers { asdfghjklasdfhjkl_init = "call compile preProcessFileLineNumbers '\userconfig\hacks\hacks.sqf'"; //No need to close this since we already have a closing bracket in the config.cpp Why you should be concerned Barely any addon that uses a userconfig files is safe. That means: a ton of addons are unsafe! I know of a few VERY popular addons that can be abused this way! This is a major issue, and you should as a server owner double check what kind of addons you have whitelisted. Rather take one off the whitelist than leave it on there. Thank you for reading! Edited August 1, 2015 by BaerMitUmlaut 2 Share this post Link to post Share on other sites
das attorney 858 Posted May 29, 2015 Thanks for this interesting post - I will give it a good read through properly over the weekend. Hopefully some others find it useful :) Share this post Link to post Share on other sites
jonbons 13 Posted June 3, 2015 Another method you can use if you are using CBA is the CBA_fnc_parseYaml function which should give the same security level as parsing files like BaerMitUmlaut's script. Example script: https://github.com/CBATeam/CBA_A3/blob/master/addons/common/test_parseYaml.sqf Example config file: https://github.com/CBATeam/CBA_A3/blob/master/addons/common/test_parseYaml_config.yml I've also seen parsers for the ini format in the wild but I'm not sure if those have been public release as a easy to use lib. Share this post Link to post Share on other sites
baermitumlaut 62 Posted June 6, 2015 I took a quick look at the parseYaml function and it looks safe to me, thank you for the hint. I'll inlcude it in the OP. Share this post Link to post Share on other sites
Kerc Kasha 102 Posted June 6, 2015 Just a heads up, profilenamespace does work on a dedicated server. I've been using it to save data between server restarts without issue Share this post Link to post Share on other sites
baermitumlaut 62 Posted June 6, 2015 It does work, but there's no real way to set user defined values. Apart from that, you can of course store data in there. Share this post Link to post Share on other sites
flymaker 15 Posted August 12, 2016 Hello.I'am trying to use this method://Safe:if (isServer) then {[] call compile preprocessFile "\userconfig\MyAddon\settings.sqf";}; But its not working. I made some changes now i have that structure: \userconfig\MyAddon\settings.sqf : //Put desire CSAT Weapons/Ammo Classname to replace #define USERSETTING_replaceKatiba "hlc_rifle_ak12" #define USERSETTING_replaceKatibaGL "hlc_rifle_ak12GL" #define USERSETTING_replaceKatibaC "hlc_rifle_aku12" #define USERSETTING_replaceZafir "hlc_rifle_RPK12" fn_readConfig.SQF : #include "\UserConfig\myaddon\settings.hpp" _replacefor_Katiba = USERSETTING_replaceKatiba; _replacefor_KatibaGL = USERSETTING_replaceKatibaGL; _replacefor_KatibaC = USERSETTING_replaceKatibaC; _replacefor_Zafir = USERSETTING_replaceZafir; getVar.sqf : [] call compile preprocessFile "fn_readConfig.sqf"; hint format ["%1", _replacefor_Katiba]; Share this post Link to post Share on other sites