-
Posts
145 -
Joined
-
Last visited
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
Changes to the behaviour of net.dostring_in()
Actium replied to BIGNEWY's topic in Scripting Tips, Tricks & Issues
Thank you and the team for the quick revert! Unfortunately, that leaves the DCS client and server vulnerable to arbitrary code execution via maliciously crafted mission files. I believe a temporary mitigation should be applied until a more permanent solution has been found. The net.dostring_in() wrapper I suggested above limits the availability of net.dostring_in() from within mission scripting to the "mission" Lua state. I presume that is the primary use of net.dostring_in() to access the a_*() functions from mission scripts. IIRC, there are mission scripts out there that use net.dostring_in("gui", ...) to change/restart missions via the F10 menu. These would be collateral damage of that fix. Please do chime in if anyone has any concerns regarding that mitigation approach. As the dedicated server is also vulnerable, a suitable configuration method for both client and server (no GUI) should be found. Suggestion for a Permanent Fix IMHO, restricting net.dostring_in() use would be a too radical change in terms of API breakage. Given an option to bypass these restrictions, there will always be countless videos and posts suggesting to enable the bypass. I know quite a few people who simply remove the sanitization from MissionScripting.lua without understanding the security implications of that action. Instead, this should be fixed at the root of the vulnerability, most importantly io.open(), os.execute(), and similar functions in the io, lfs, os modules. Arbitrary read/write file system access and executing arbitrary commands are trivially exploitable vulnerabilities. File system read access should be restricted to the relevant DCS directories, i.e., lfs.currentdir(), lfs.tempdir(), and lfs.writedir(). Write permissions should be restricted even further to prevent shenanigans like changing configuration files (fundamental flaw of the now revoked security option). This is similar to what @cfrag suggested in terms of a sandboxed 'writeString()' method. Mods that require deeper file system access could accomplish that thru a self-compiled Lua .dll module (and take responsibility for whatever vulnerabilites that results in). Access to os.execute() should probably be prohibited unless explicitly enabled. Not sure how to do that securely. The only way I've seen it used is by the SRS scripts to launch the SRS client when connecting to an SRS-enabled server. As above, I'd appreciate feedback on whether any mission/mod makers believe it would break their content. @BIGNEWY Are you and the team interested in concrete implementation suggestions from the community? If so, we could discuss sth. here. If not, I'll save myself the effort. -
The issue described in this post has been resolved with today's hotfix (2.9.18.12899). Hiding the original post in the following spoiler to prevent confusing users with obsolete information: On a side note, the a_do_script() return value pass-thru has returned with 2.9.18.12722. It was initially added with 2.9.13.6818 and silently removed in 2.9.15.9408 to fix a segmentation fault. Following in its first incarnation's footsteps, the reincarnation of a_do_script() return value pass-thru is also broken, so we'll have to stick with the temporary file workaround for now.
-
Changes to the behaviour of net.dostring_in()
Actium replied to BIGNEWY's topic in Scripting Tips, Tricks & Issues
@BIGNEWY As you are soliciting feedback, here's mine. Please forward this to your developers. I've reported an arbitrary code execution vulnerability, initially in December '24, which I presume may be related to this API change. Recently, I've also suggested a straightforward mitigation method that would incur far less collateral damage than the current approach. TL;DR The new net.dostring_in() security option is conceptually flawed: It only mitigates the vulnerability in a basic configuration, its configuration can be easily changed from privileged scripts (rendering it useless), and, most importantly, it cannot be configured to allow required, legitimate use of net.dostring_in(), while simultaneously preventing potential exploits. The changes cause a lot of collateral damage, while not fixing the root cause of the vulnerability. IMHO, this change should be reverted and ultimately substituted with a superior alternative. This alternative should be co-developed with community contributors that rely on the scripting API to find a proper solution. Inofficial Security Advisory What this fails to mention is that DCS versions from at least 2.9.10 (probably sooner) thru 2.9.17 are vulnerable to arbitrary code execution via specially crafted mission files. I'll responsibly refrain from divulging any further information. Suffice it to say that I figured out how to exploit the vulnerability from information that I gleaned from this forum, so the required knowledge is already out there. The exploit does not require the now added return value pass-thru of net.dostring_in(), which is apparently broken anyway. Beware of untrusted mission files in combination with exemplary autoexec.cfg files out there! As predicted by many previous posters, I've already seen a few autoexec.cfg incarnations with potentially unsafe settings. Anything that includes "scripting" in net.allow_unsafe_api is presumably dangerous. Kudos to ED for clearly pointing this out in %DCS_INSTALL_DIR%/API/Sim_ControlAPI.html: net.allow_unsafe_api = { "userhooks", -- will make the API visible in _$WRITE_DIR/Scripts/Hooks/*.lua_ scripts "scripting", -- enables the API in the mission scripting state. DANGEROUS!!! "gui", -- system hooks and GUI state } @BIGNEWY This very important detail is hidden away. I'd suggest to add it to your first post in this thread. Technical Background To comprehensively address the efficacy of the security option, I first have to outline my understanding of the technical background of net.dostring_in(). @Experts: Please correct me if I'm wrong with anything! DCS relies on multiple Lua interpreter instances to isolate different scripting zones/environments/namespaces from each other. They contain entirely separate global environments (_G variable). These are called lua_State in the Lua documentation and are also referred to as states in DCS' documentation. The states are isolated from each other, but some applications require to run code and get return values from other states. That is where net.dostring_in() comes in: AFAIK, the following Lua states exist: "config", "export", "gui", "mission", "server", "scripting" (new since DCS 2.9.18; separate from a_do_script()), and "userhooks" (new since DCS 2.9.18). Some of these states are trusted and privileged, e.g., "gui", "server", and "userhooks". These are allowed to read and write arbitrary files and call external programs, which is how SRS launches the client automatically on SRS-enabled servers. Other, unprivileged states run untrusted code from mission files, e.g., the "mission" state. Potentially dangerous Lua functions, e.g., for writing files and calling executables, are sanitized from these unprivileged states. @BIGNEWY What's the purpose of the new "scripting" state? It appears to be a separate Lua state from both "mission" and a_do_script(). Benefit / Efficacy The implemented security option restricts the use of net.dostring_in() within privileged, trusted Lua states, too. As these states already have access to privileged Lua functions, using net.dostring_in() to access a different state will not result in privilege escalation. Also, if the respective state can write files, it can modify autoexec.cfg and edit net.allow_* to change the security options to more permissible ones (after a game restart). Hence, attempting to restrict these privileged states is entirely useless. Unfortunately, that design choice has an unpleasant side effect: To permit the already privileged states to access all other states, implies permitting the non-privileged states to access all other states, too, because there's only one global net.allow_dostring_in setting shared between all source states (where net.dostring_in() is called from). A real-world example would be the need to let "userhooks" access "server" (e.g., Olympus) and let the mission scripting state ("scripting"?) access the "mission" (triggers) state, e.g., to access functions like a_unit_set_life_percentage(). That would result in the exploitable situation, where mission scripting can access the "server" state. The breaking changes do not fix the root cause of the vulnerability, which is the availability of potentially dangerous functions that allow unrestricted read/write file access and the execution of arbitrary programs. How to deal with these potentially dangerous functions should be the subject of a future discussion. Which missions/mods/scripts need them and how they could be made safe. Cost / Breakage Scripting in DCS is already not trivial due to the fragmented Lua states, requiring workarounds that rely on net.dostring_in("mission", ...) [1, 2] and a general lack of documentation. Incompatible API changes that break these workarounds frustrate the mission makers that desperately rely on them. The alleged obsolescence of net.dostring_in() (see above quote) adds to the feeling that the developers are not fully aware of what their API users actually need. There are many uses for net.dostring_in(), e.g., Olympus, Lua consoles, etc., for which a_do_script() is not an alternative. I'd highly recommend to discuss such drastic API changes with the community well in advance. Breaking changes must always be thoroughly studied and it is painfully obvious that these changes have not received the amount of thought they deserve. Conclusion The design of this new security option is fundametally flawed: It is inherently insecure, i.e., vulnerable to arbitrary code execution, when configured for standard use cases, e.g., Olympus + access to "mission" state from a_do_script(). It adds unnecessary complexity by restricting already privileged Lua states, where the availability of net.dostring_in() does not enable privilege escalation. Hence, this does not improve security. The security option configuration is not tamper-proof. Privileged Lua states can modify autoexec.cfg arbitrarily to bypass all previously configured restrictions after a DCS restart. This design issue renders the security option useless. Above issues illustrate how the security option design is ill-conceived. These issues alone are sufficient to revoke these changes and to restore the scripting system to the behavior of DCS 2.9.17. What makes matters worse, however, is the collateral damage in terms of API incompatibility, which breaks community content. Alternative To alternatively mitigate the arbitrary code execution vulnerability, while simultaneous permitting legitimate use of net.dostring_in() from mission scripting, the following wrapper function could be placed within %DCS_INSTALL_DIR%/Scripts/MissionScripting.lua: ---BEGIN-MISSION-SCRIPTING-EXPLOIT-MITIGATION--- -- insert this block into %DCS_INSTALL%/Scripts/MissionScripting.lua above: -- --Sanitize Mission Scripting environment -- mitigate arbitrary code execution vulnerability with a wrapper for -- `net.dostring_in()` that restricts its access to the "mission" Lua state. -- accessing the "mission" Lua state is required for some advanced scripting: -- * https://forum.dcs.world/topic/354648-add-setlife-function-to-lua-api/ -- * https://forum.dcs.world/topic/358877-lua-function-unitsetlife/ -- * https://forum.dcs.world/topic/371036-outpicturefor-lua-mission-scripting-functions/#findComment-5672179 -- this copies `net.dostring_in()` into a lexically scoped local variable and -- then overwrites the original function with a wrapper, which captures the -- local exclusively, because Lua is scoped lexically: -- https://www.lua.org/pil/6.1.html local _dostring_in = net.dostring_in function net.dostring_in(lua_state, code) if lua_state == "mission" then local _result, _success = _dostring_in("mission", code) return _result, _success else -- TODO: add error logging return "Invalid state name", false end end ---END-MISSION-SCRIPTING-EXPLOIT-MITIGATION--- Obviously, this is provided as is, without any warranty of any kind (as per the stipulations of the MIT license). You should know your code better than me to figure out whether this is safe or not. Regardless, I hope this helps make DCS safer, while keeping mission makers happy. -
Changes to the behaviour of net.dostring_in()
Actium replied to BIGNEWY's topic in Scripting Tips, Tricks & Issues
I can confirm that this does indeed not work as advertised. Running the following code from DCS.openbeta/Scripts/Hooks return {net.dostring_in("mission", "return 1,2,3")} will yield the following return value: [ "1", true ] Maybe there's a mixup with a_do_script() available from the mission environment/zone? See the recently updated %DCS_INSTALL_DIR%/API/Sim_ControlAPI.html: The a_do_script() change is also part of the 2.9.18.12722 changelog. However, it is also broken, despite being the second attempt [1, 2]. -
DCS 2.9.18.12722 re-introduces a_do_script() and a_do_file() return value pass-thru, after a previously failed attempt: Unfortunately, return values are only partially passed thru. Specifically, the last return value is always dropped. That results in no return value being passed thru if a single return value is used: return a_do_script("return 42") Yields a nil return value. %DCS_INSTALL_DIR%/API/Sim_ControlAPI.html gives a more complex example with multiple return values being passed thru: -- original example in Sim_ControlAPI.html local a, b, c = a_do_script("return 1,2,3") -- added return code for illustration return {a = a, b = b, c = c} It results in the following return value (instead of a=1,b=2,c=3): { ["a"] = nil, -- added for illustration purposes ["b"] = 1, ["c"] = 2 } Steps to Reproduce Run the above code snippets in the mission Lua state via a DCS Lua console of your choice, e.g., my WebConsole.lua. Note that this will require modification of autoexec.cfg to provide access to the mission state via net.dostring_in() from the userhooks state. P.S.: This could have been easily caught automatically by a very simple unit test. I'd like to encourage ED to start using these tests to avoid delivering broken releases. As this is not the first occurrence of broken a_do_script() code, it is apparent that your current testing strategies are insufficient.
-
- 1
-
-
Actium started following Game Crash "Login session has Expired" , Changes to the behaviour of net.dostring_in() , DCS Server Memory Tickup and 1 other
-
No connection issues in the log. Master server just opted to terminate the session for no apparent reason: 2025-05-28 19:12:57.649 INFO ASYNCNET (4100): Login success. 2025-05-28 19:13:02.135 INFO ASYNCNET (4100): Got auth data. 2025-05-28 19:13:02.580 INFO ASYNCNET (Main): ProtocolVersion: 402 2025-05-28 19:13:02.580 INFO ASYNCNET (Main): Adding LAN search interface 0: 127.0.0.1 "IPv4 Loopback" 2025-05-28 19:13:02.580 INFO ASYNCNET (Main): Adding LAN search interface 0: 255.255.255.255 "IPv4 Broadcast" 2025-05-28 19:24:59.022 ERROR ASYNCNET (4100): The session has expired (401). Exiting...
-
In a simple BVR scenario with a flight of 4 MiG-29 air-starting in a line abreast formation, the flight presumably attempts to switch to a grind formation. That typically results in some of the wingmen (usually trailing pair) stalling at 130 kts IAS and 21° AoA on full burn until they snap out of it minutes later when a plane finally gets hit. This is not limited to the Fulcrum, but also occurs with the Flanker. Starting with a trailing formation may result in fewer stalled planes. This has been previously reported for the F/A-18. I've attached a track and a tacview: AI_stall.trkAI_stall.acmi Screenshot of starting position: Screenshot of trailing element stalling after switching to grind:
-
- 1
-
-
Failure to resolve api.digitalcombatsimulator.com will be logged as ASYNCNET errors/warnings in dcs.log (likely sth. to the tune of error 6: Could not resolve hostname). If your dcs.log does not contain such messages, it's definitely not DNS.
-
@Roughneck Have you had a look at your dcs.log for sessions that got terminated? Here's a quick way to grep the relevant ASYNCNET messages from dcs.log via PowerShell: Get-Content "$env:USERPROFILE\Saved Games\DCS.openbeta\Logs\dcs.log" | Select-String ASYNCNET Wondering whether it includes any session check errors/warnings or the The session has expired (401). Exiting... message comes entirely out of the blue.
-
@Hempstead Thanks for sharing. I've had a look. These are all occurrences of ASYNCNET within the log file: 2025-07-03 18:48:27.090 INFO ASYNCNET (34508): Login success. 2025-07-03 18:48:29.799 INFO ASYNCNET (34508): Got auth data. 2025-07-03 18:48:29.854 INFO ASYNCNET (Main): ProtocolVersion: 404 2025-07-03 18:48:29.854 INFO ASYNCNET (Main): Adding LAN search interface 0: 127.0.0.1 "IPv4 Loopback" 2025-07-03 18:48:29.854 INFO ASYNCNET (Main): Adding LAN search interface 0: 255.255.255.255 "IPv4 Broadcast" 2025-07-03 19:00:30.957 ERROR ASYNCNET (34508): The session has expired (401). Exiting... So far, I've only observed and been able to reproduce this issue when the client reconnects to the master server after a 30ish minute connection interruption as I've reported here. That would result in many more ASYNCNET error/warning messages like this: 0000-00-00 00:00:00.000 ERROR ASYNCNET (192): HTTP request dcs:checksession failed with error 7: Could not connect to server 0000-00-00 00:00:00.000 WARNING ASYNCNET (192): Session check failed: -7 However, your occurrence of this issue appears to have happened entirely out of the blue without any prior connection issues. Presumably, the master server decided to just expire your session. Based on a previous post from BN, I've had a hunch that changing your IP address while logged in may cause the master server to terminate your session: I've tried to reproduce this, but changing my public IP address (have the router reconnect) twice for 3 consecutive session checks from 3 different IPs didn't trigger the issue for me. Unfortunately, the master server does not give any reason why it expires your session. Is there anything else on your side that could have caused it? It'd probably be best to open a support ticket, hoping that ED have a server-side master server log with more debug information.
-
There have been issues with memory leaks in the past. Not necessarily related, but probably worth a read:
-
@Simpit While you're in singleplayer, using the offline mode is a workaround for this issue. Would you mind sharing a dcs.log of the session to help figure out what caused the termination?
-
Would you mind sharing a dcs.log for that session? If it kicked you out within 10 minutes of starting the game, there must be more ways this issue is caused than I described here. I doubt you started a second DCS instance while busy bombing those T-72s.