Squirrel Lang is an interrupted language used by video games and cloud services that allows for custom programming. In CS:GO it is used to enable custom game modes and maps. This language runs in a sandbox in order to prevent the exploitation on hosted machines playing games.
The main SquirrelLang implementation is written in C. As a result, a series of memory corruption vulnerabilities could be used to break out of the system. This is also an object- oriented programming language (OOP) and looks similar to PHP.
When creating a class, there are two dynamic arrays: values and methods. Additionally, the _members field is used that maps the name of an attribute to their index in one of these arrays.
To know which array to go into, a bitflag within the index of the _members field is used. This bitflag is set at 0x02000000. Bitflags being held in a used value is similar to the size in the chunks in glibc malloc. Is the usage of the bitflag done securely?
Since the bitflag is at 0x02000000, could we create a class definition with 0x02000000 methods or variables? If we add 0x02000000 methods, then try to get this as a variable, the program will immediately crash! We have got a type confusion vulnerability.
Here's an example flow:
- Create 0x02000005 methods and 1 field.
- The attacker accesses the method with the corresponding index 0x02000005.
- The _isfield() macro returns true for this index as the bitflag 0x02000000 is set
.
- The _defaultvalues array is accessed with index 0x5. However, it only contains 0x1 entries and thus the attacker has accessed out of bounds.
Using the type confusion vulnerability, we can use the value accessor to write and read values IF we can create a proper fake object (lots of misdirection).
A good usage of this misdirection was setting the _value to retrieve an array type. By using a OOB access, we could control the base address and the amount of entries in the array. Now, by reading or writing to this, we have a beautiful arbitrary read/arbitrary write primitive.
Mixing real values and metadata bits can be very dangerous. In this case, the lack of validation of overflows allowed for a bad type confusion eventually leading to code execution.