FreedroidRPG is an open source hack and slash game. In other words, it’s a Diablo clone available on Linux.
I became interested in how the game handles untrusted user input, but as it’s a single player game supplying malicious input is limited. So I decided to analyze the parser of saved games and whether it may be somehow abused. I found a few memory corruption vulnerabilities and a way to execute arbitrary code.
A single save consists of two files: NAME.shp and NAME.sav.gz.
Let’s look into the first one.
NAME.shp is a gzipped text file, so we can get its content using following commands:
It contains many parameters describing the played level. This kind of file is parsed by functions: LoadShip, decode_level, decode_level in https://gitlab.com/freedroid/freedroid-src/blob/master/src/map.c.
Some of the parsed values coming from the file are used to calculate offsets to memory. The parsing functions lack validation of read values and do not expect that someone may alter data. Usually, users do not edit their own save files (unless they want to cheat, but it’s a different subject), but in some game communities, it is quite common to exchange save game files with other players. So unaware users may download or receive manipulated files leading to some undesired behavior.
The first problem I found in following code:
At line 825 we can see that this_line has a fixed size of 4096 bytes. Then, at line 850 this memory is accessed, but offset is calculated using values loadlevel->xlen and loadlevel->floor_layers. Both of these values come from the file and loadlevel is a structure representing it. So if user edits the NAME.shp file and sets big enough values, for example: floor layers: 48 or xlen of this level: 2048, the function will read outside memory buffer.
The second problem is related to two similar fragments of code parsing two fragments of the file that don’t have a fixed size.
In the save game we can find:
and code responsible for parsing it:
Again we meet fixed buffer this_line. This part of code tries to copy data resisting between beginning_of_map tag and newline character announcing the end of the value. The function assumes that data between the tag and newline character will fit to the this_line buffer. It’s not true as malicious user can modify the save and put more than 4096 characters in that place. If a such modified save is loaded the game will write data outside the buffer.
Second crash, part 2
The problem is exactly the same for parsing this part of the save.
However, it occurs in another function:
If data between wp and newline character is longer than 4096 bytes, than the same vulnerability occurs - data is written outside the buffer.
The second file is also a gzipped text file, but its content is quite different.
If we look into the code parsing we will notice that it’s Lua code being interpreted while loading the save.
So, in this case, the attacker has a much easier job. It’s possible to put any Lua code we want, for example os.execute("xcalc").
Even single player games are susceptible to malicious input. Every kind of data we deliver to our games (save games, mods, additional maps, etc.) can be a way of triggering potential vulnerabilities in code. In the case of FreedroidRPG, it was possible to cause some (but I don’t know if exploitable in practice) memory corruption and what is worse, execute arbitrary code.
According to art. 13 of the General Regulation on the Protection of Personal Data of 27 April 2016 (Official Journal EU L 119 of 04.05.2016) I inform that:
1) the administrator of your personal data is Logicaltrust Sp. z o.o. Sp. k. - al. Aleksandra Brücknera 25-43, 51-411 Wrocław,
2) contact with the Personal Data Administrator - email@example.com,
3) Your personal data will be processed for marketing purposes on the basis of Art. 6(1)(a) of the general regulation on the protection of personal data of April 27, 2016..
4) Your personal data will be stored until you withdraw your consent
5) You have the right to request from the administrator access to personal data, the right to rectify their removal or limit processing, the right to withdraw consent and the right to transfer data
6) You have the right to lodge a complaint with the supervisory authority
7) Your data will be processed in an automated manner, including in the form of profiling. Automated decision-making will take place on the principles set out in the regulations (options: subscription, competition, etc.) and the consequence of such processing will be receiving selected marketing information
8) providing personal data is voluntary, however failure to provide data may result in the inability to participate in the newsletter subscription, participate in contests, receive marketing offers, participate in surveys
At the same time, pursuant to Art.6(1)(a) of the general regulation on the protection of personal data of 27 April 2016, I agree to the processing of my personal data for the purpose of subscribing to the newsletter, participation in competitions, receiving marketing offers, participation in surveys