With the "Old Man" update out now, I decided to take another look at the Functions and UI scripts to see what fixes they implemented, and to look for a new exploit for SQF execution.
To my surprise, I was greeted with BIS_fnc_parseNumberSafe. This neat little function is a "fix" for their previously broken BIS_fnc_parseNumber. They implemented a smart little trick to prevent unwanted code execution while parsing string types.
Just to refresh you on BIS_fnc_parseNumber & why it was truly awful. Here is a small snippet from it:
_number is just executed with no checks!
Here is the same snippet from the new BIS_fnc_parseNumberSafe:
This is a bit more complex. It is using some SQF functionality that I rarely use. Breaking it down, the string stored in _this is first checked if it contains any contents not allowed. If any content is found that is not allowed, _res gets the value of 0. If _res has a value, it will not execute the text. First, let's figure out what is and is not allowed:
So, in theory, if the text contains any code not defined in this list, it will not execute. Testing that out with ["hint 'test';0"] call BIS_fnc_parseNumberSafe; we can see that it does do it's job. It does that job well.
Continuing with our analysis, we can find other locations in BIS_fnc_parseNumberSafe that also executes call compile:
Looking at these, if the text value comes from a config entry, it will execute it without question.
This begs us to ask, can we find a config entry to execute, that is also exploitable. To find this config entry it needs to satisfy all the following:
- The config is Text or an Array of Text
- The text is compilable SQF
- The sqf code executed contains some method of arbitrary execution
I quickly created a script to scan the config for entries that could satisfy these items. Sadly, I lost the code, but I saved the data I dumped. Here is the raw dump from the config of possible exploitable config entries: https://haste.lystic.dev/tasilatiku.pl.
All of these options execute some function or variable. Now, I need to see if any of these functions have exploits, or if any of these variables are undefined. Luckily, there is one that stand out due to the large number of config entries it was contained in.
BIS_HC_path_menu
configFile >> "RscHCWPSpeedMode" >> "items" >> "Full" >> "Params" >> "expression"
This config entry contains an arbitrary execution, BIS_HC_path_menu is not defined.
Okay, now we have our arbitrary execution entry in the config file. We need to test our exploit on BIS_fnc_parseNumberSafe. Here is the quick test I ran:
This worked! Our code is executed! Sweet. Now we need to find a way to use this vulnerability to execute SQF code.
There is a nice old exploit that I never made a post about. This is the Layout exploit. When the player modifies their Layout through the game options, there is a nice little execution opportunity. The position of the HUD elements need to be saved into the profile, and are often parsed with parseNumber. I checked the script RscDisplayOptionsLayout.sqf found in the UI_F.pbo
Here is the code I found that was interesting:
If the variables for posX, Y, W, H are non-nil and the presetName is not an empty string, the values of posX, Y, W, H are all run through parseNumberSafe. This is good. If we can set the value of these in the UINamespace, we could use this section of code to trigger parseNumberSafe. Digging deeper, this code is executed when the layout is "applied" through the Okay button.
So easy enough, but what should the preset name be? To figure this out, I dug through CfgUIGrids. You can do so yourself, but I will tell you, the only preset name that is valid is "Arma3" for both categories "IGUI" and "GUI". With this knowledge, we should set the variable for both of these categories to the value Arma3.
With that done, we can recreate the foreach loops above, and instead of reading from the uiNamespace variables, we can write to them. We write our exploitable config path, and the parseNumberSafe function should run our code.
To test this, we run this in the 3DEN editor and click "Options->Game->Layout->Okay->Okay" to trigger it. Tada! We have just created another SQF execution exploit in Arma 3!
Here is the complete exploit source: https://haste.lystic.dev/oraqabuwiv.cs
On a more serious note, I have been finding exploits like this since Arma 3 Apex was released. Before then, I never really looked into them. The way BI handles UI positioning, requiring code execution to parse their position properly, is a very insecure way of handling it. The engine should have been provided native capabilities for these math calculations, and not some simple scripted system. It also seemed to be kind of arrogant of them to think that their new parseNumber function was so safe as to actually call the function parseNumberSafe. Honestly, I am willing to bet any SQF developer who is told "Hey there is an exploit in parseNumberSafe" would find this issue in under 10 minutes.
For server owners, I went ahead and created a patch. You should include this inside the client init of your server. As long as this code executes on the client before they can interact with the UI, you will catch anyone abusing the layout exploit. Here is the source code: Download: https://haste.lystic.dev/baxuloqamu.rb
For simplicity, banning could be a simple remoteExec call that you have filtered in remoteExec.txt
Note: this exploit has been patched as of SPOTREP #00094.