enowars5-service-stldoctor

STL-Analyzing A/D Service for ENOWARS5 in 2021
git clone https://git.sinitax.com/sinitax/enowars5-service-stldoctor
Log | Files | Refs | README | LICENSE | sfeed.txt

commit b064de1ea6aa1f4692ca77af46d5d1121ee7aaa8
parent 484434350c29a7c01f0ca52cf61d8cf3d6de6ec3
Author: Louis Burda <quent.burda@gmail.com>
Date:   Mon, 17 May 2021 19:01:30 +0200

greatly improved information in documentation on service and exploits

Diffstat:
Mdocumentation/README.md | 220++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 178 insertions(+), 42 deletions(-)

diff --git a/documentation/README.md b/documentation/README.md @@ -1,68 +1,204 @@ PrintDoc ======== -Setup ------ +PrintDoc is a plain-text protocol service, that allows users to upload files +and generate reports that include information on the files.. -The service is hosted with ynetd or similar, one process per client. +- model name +- binary header +- file type (bin vs ascii) +- file size +- triangle count +- bounding box size and position -You submit an stl file and the service gives you details about the file: +Uploaded models and generated reports are stored in a directory structure. -- how many triangles -- file type (bin/ascii) -- name -- attributes (binary header parsing) +Unregistered users have their files saved in a collective directory, which +allows users to query for public models by using their model name. +Registered users have their uploads saved to a private directory. +This (theoretically) prevents other users from accessing their files. -The file upload size has to be below a certain limit (4kB?). +The service is hosted with socat, one process per client. -The files are simply stored in a directory and cleaned up -via a crontab which checks their *last modified* date. +A cron job is used to periodically clean up models by using their *last modified* date. -The model name is used to create hash / id which also -acts as directory name for the actual stl and parsed info. -Error msg if too many verticies for one loop.. see vulnerability. +RCE Countermeasures +=================== -Error msg if invalid format. +It is good practice to take preventitive measures against unintentional RCE, +which can be used to cause havoc on vulnboxes and make services go mumble. +1. Enable additional security features via flags during compilation: -Countermeasures ---------------- + `CFLAGS="-fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2"` -Countermeasures against malicious players, who via an -unintended vulnerability gain remote code execution: + - `-fPIE`: enable position independent executable section + - `-fstack-protector-strong`: enable stack canaries in functions with local variables that are prone to overflow + - `-D_FORTIFY_SOURCE=2`: gcc buffer overflow detection + + `LDFLAGS="-Wl,-z,now -Wl,-z,relro"` + + - `-Wl,-z,now`: tell dynamic linker to resolve symbols ASAP instead of lazy loading + - `-Wl,-z,relro`: tell dynamic linker to make got read only after resolving symbols + +2. Chroot each service instance via socat so it can only access + uploaded files and not corrupt the system. + +3. Prevent the service binary from creating child processes. Checker -------- +======= + +The checker checks the following behavior: + +- File upload and query (for both bin and ascii): + - Open a session + - Upload a file of random, valid contents with random model name + - Ensure file is listed in query + - Open a new session + - Ensure file is listed in query + - Ensure file is not listed in query for different model name +- Registering and private files (for both bin and ascii): + - Open a session + - Register with a random password + - Upload a file of random, valid contents with random model name + - Open a new session + - Ensure file is not listed in query + - Register with previous password + - Ensure file is listed in query + +The checker does the following to submit the first flagstore's flag: + +- Open a session +- Use `submit` to upload a file of random, valid contents with a + the flag as the model name + +The checker does the following to submit the second flagstore's flag: + +- Open a session +- Use `submit` to upload a file of the encoded, binary STL flag with + a random model name chosen from a wordlist with numbers for + collision resistance + +The checker should not be easily identifiable, since this could allow +players to only enable certain service functions when the checker is +detected. + +Notes on evading detection of the checker through traffic analysis: + +- File upload contents are randomly generated valid STLs and the model name is + picked randomly from a wordlist to blend in with regular requests +- The username used for premium user registration is chosen at random from + a wordlist (with numbers appended for collision resistance) to blend + in with other requests +- The STL file which belongs to the second flagstore is not easily identifiable + since the binary file format is used and viewing the file contents does not + help identify the 3d model encoded +- The first flagstore's flag IS easily identifiable, since it is sent in cleartext + to the service, however, the checker makes sure to test upload and querying + functionality of files with other model names in another session as well + + +Vuln 1: Value Collision +======================= + +Discovery +--------- + +This vulnerability can be found by reading the source code. + +The internal utility function `void freadstr(FILE *f, char **dst)` reads a +null-terminated string from the given file, allocates space for it and saves the +pointer to its contents in `dst`. + +```C +void +freadstr(FILE *f, char **dst) +{ + size_t start, len; + char c; + + start = ftell(f); + for (len = 0; (c = fgetc(f)) != EOF && c; len++); + fseek(f, start, SEEK_SET); + + *dst = checkp(calloc(1, len + 1)); + fread(*dst, len, 1, f); + fgetc(f); +} + +``` + +To determine whether the end-of-file was reached, the return value of `int +fgetc(FILE *f)` is compared to the constant `EOF`, which has a value of `-1`. +The problem lies in the fact, that this comparison is done following a demotion +of the return value to `char` through the assignment and a subsequent promotion +to `int`, which results in an arithmetic extension. As a result, reading the +value char `0xff` would promote it to `0xffffffff` with a value of `-1`, +preventing the function from reading the complete string. + +This allows an attacker to cleverly truncate a string before it has ended to +manipulate the content of strings which follow it. In this case, the model name +is saved before the model hash in the information file. By adding a `0xff` to +the end of our uploaded model's name, the model hash is read as an empty string +following a `query` of the file's contents. Since any following `query` will use +the previously loaded models hash to find the file via prefix match, any files +uploaded by unregistered users may be accessed by a user. + +The flag is saved in the model name. + + +Exploiting +---------- + +1. Open a session +2. Use `submit` to upload an STL file and specify a model name ending in `0xff` +3. Open a new session +4. Use `query` with the same model name from **step 1** to retrieve to load the + parsed information of the file you just uploaded +5. Use `query` again.. this will now use the cached hash which should be empty, + allowing you to accesss any of the files uploaded by unregistered users + + +Patching +-------- + +For an example fix, see the unified patch `patches/flagstore1.diff`. + + +Vuln 2: Invalid Format String +============================= + +Discovery +--------- + +This vulnerability can be found by reading the source code. + +TODO.. + +The flag is saved in a binary STL as a 3d model. Each character is constructed +in the XY-Plane via a minimal number of triangles. The positions and triangles +per character do not change, which should help automation. Additionaly, drawing +the triangles into a 2d buffer and running a text-detection over it should be +possible. + + +Exploiting +---------- -The flag is saved as a 3d model of the flag text. One needs -to orient it, take a screenshot and decode the text from the -image for automated exploitation. +TODO.. -Vulnerability -------------- +Patching +-------- -If there are > 3 verticies in a `loop` in the stl, a warning -message is returned by preparing and `printf`ing a buffer, -however, WITHOUT a terminating null byte. As such, when -processing the string, we read into the stack-adjacent integer -that holds the file's attribute byte count. This value -is zero by default so the buffer overflow will go unnoticed. +For an example fix, see the unified patch `patches/flagstore2.diff`. -We can set this value to 0x6e25 (= 28197), which corresponds -to the string '%n' on a little endian system. -When the warning prints, it will write the size of the -format string (which can be controlled via the model name) -to the address of the next value on the stack: the hash str. -By varying this value to write 256 aka 0x100 we terminate -the string with a null byte, making it an empty. +Traffic Analysis Evasion +======================== -Next, the program will return the info of all scans that match -the hash prefix (files are saved in a directory <hash>-<timestamp>). -Since the hash is not empty the information for each scan will be -returned, including the id, which can be used to request the flag file.