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:
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.