STLDoctor ========= STLDoctor is a plain-text protocol service, that allows users to upload STL files and generate reports that include information on the files.. - model name - binary header - file type (bin vs ascii) - file size - triangle count - bounding box size and position Uploaded models and generated reports are stored in a directory structure. Unregistered users have their files saved in a collective directory, which allows users to query for public models via model name. Registered users have their uploads saved to a private directory. This (theoretically) prevents other users from accessing their files. The service is hosted with socat, one process per client. A cron job is used to periodically clean up models by using their *last modified* date. RCE Countermeasures =================== 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: `CFLAGS = "-fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2"` - `-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` section 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 - Check upload ordering and accessing indeces != 0: - Open a session - Upload a file of random, valid contents with random model and solid name - Upload a different file of random, valid contents with same model name but different solid name - Open a new session - Query for same model name and pick 1st entry - Compare returned solid name with expected (1st upload) - Query for same model name and pick 2nd entry - Compare returned solid name with expected (2nd upload) The checker tenets: - A checker SHOULD not be easily identified by the examination of network traffic satisfied, because checker uses regular user interface and picks strings from a wordlist to appear more human (TODO) - A checker SHOULD use unusual, incorrect or pseudomalicious input to detect network filters satisfied, send various garbage bytes for model name and file contents (TODO) 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 - Register as a premium user - Use `submit` to upload a binary STL with the flag as its solidname and 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 ---------- TODO.. Patching -------- For an example fix, see the unified patch `patches/flagstore2.diff`.