Note: these exercises are in myUnix. Start the environment with ```sh sudo util/start ``` unless specified otherwise. bad0suid ======== This suid executable calls `system("mkdir ...")`. Since `"mkdir"` does not contain any slashes, the shell will use the `PATH` variable. The `PATH` variable is inherited from the parent processes and, ultimately, is controlled by the attacker: ```sh echo sh > mkdir chmod +x mkdir PATH=:/bin bad0suid ``` We create a `mkdir` script that invokes the shell, then call the `bad0suid` binary with a `PATH` that includes the current directory (the null string before the colon). The shell invoked by `system()` will execute our script instead of the `/bin/mkdir` program. The scripts just starts an interactive shell. bad1suid ======== This program uses a full path to invoke `mkdir`, so the shell spawned by `system()` is not going to use `PATH` and the above attack will not work. However, the program accepts an argument and does not sanitize it, so we can pass arbitrary commands to the shell: ```sh bad1suid 'x sh' ``` Note the newline inside the single quotes, to terminate the previous command. We could have also used a semicolon. In both cases, the shell would continue parsing the second command (i.e., `sh`) after processing the first one (i.e., `/bin/mkdir /etc/x`). bad2suid ======== Note: this must be started with `sudo util/start sh=badsh` to use the `badsh` shell instead of the normal myUnix shell. This command uses a full path and a constant string. Nonetheless, we can change the interpretation of the string by changing the value of `IFS` (Internal Field Separator): ```sh echo sh > bin chmod +x bin PATH=:/bin IFS=/ bad2suid ``` This example works because `/bin/sh` is `badsh`, a shell that does not follow the POSIX standard in the interpretation of `IFS`. Instead, it works like the original Bourne shell in Unix V7. In particular, `badsh` first skips all `IFS` characters at the beginning of the word, and then splits the word into fields using the `IFS` characters as separators. When `badsh` splits `/bin/cp` it obtains only two fields: `bin` and `cp`. The POSIX standard, instead, says that only *`IFS` whitespace* must be skipped, i.e., only the whitespace characters contained in `IFS`, if any. Since the initial `/` in `/bin/cp` is not whitespace, a POSIX shell would not skip it and would use it as a field separator, obtaining three fields: an empty string, `bin` and `cp`. The normal myUnix shell follows the POSIX standard in this regard, and therefore this exploit will not work if we start the environment without the `sh=badsh` option. In particular, when parsing `/bin/cp` with `IFS` set to `/`, the normal shell will look for a command with an empty name, which is not a legal file name. bad3suid ======== The `bad3suid` binary calls the (existing!) `/bin/shar` (SHell ARchive) command with a full path and constant options. The shell is the normal one, so `IFS=/` will not work. However, we can set `IFS=a`, causing the command to become ```sh /bin/sh r /bin -o /etc/b ackup/bin.sh r ``` i.e., execute `/bin/sh` on the `r` script passing it a bunch of other options we don't care about. Since `r` is a relative path, we can create an `r` script in the current directory: ```sh echo sh > r IFS=a bad3suid ``` Note 1: this time there is no need for `r` to be executable, since the shell will only try to use `read()` on the script. Note 2: we have set `IFS=a` only for the bad3suid command. What happens if we try ```sh IFS=a bad3suid ``` instead? How can we fix the second command while keeping the first one? --------- None of these examples work if we use a modern shell (e.g., `dash` or `bash`). What mitigations and/or behaviours implemented by these shells are effective against these attacks?