Analysis of the bug =================== The `do_addkey()` function doesn't set `keys[i]` to `NULL` after freeing an invalid key. This will cause a use-after-free in `do_grep()`. Attack plan =========== The idea is to set a password that will be used as a key. Since the password, as opposed to the keys, can contain any character, we can control the command passed to `system()` in `do_grep()`. Note that, because of the `set -e`, the shell will exit as soon as any command returns an error. Therefore, we must make sure that `/bin/grep` terminates successfully. Note that `grep` returns error even if it doesn't find the pattern in its input files. Attack implementation ===================== First, we send an invalid key to trigger the use-after-free bug. We must arrange for the `malloc()` in `do_setpassword()` to reuse the chunk allocated and released by `do_addkey()`. Since the password, plus the terminating zero, is 24 bytes and `malloc` allocates at least 32 bytes for each chunk (including the 8 bytes header) we can use an invalid key of any length less than 23: ``` sh k;; ``` We can check with `l` that the key number 0 is non-null and points to garbage. Now we set a password. The `malloc(24)` in `do_setpassword()` will reuse the free'd chunk still referenced by `keys[0]`. For example: ``` sh p. public0; cat secret; ``` This will let `grep` look for any character in the existing `public0` file, then send us the `secret`. Another option is, for example: ``` sh p._secret_______________ ``` (replace underscores with spaces) to add `secret` to the input files of `grep`, while looking for any character. And so on. We can check with `l` to confirm that `keys[0]` is now pointing to our password, then trigger the payload with `g0`. Suggested Fix ============= The `do_addkey()` function should set `key[i]` to `NULL` in case of error, or the validity of the key should be checked before assigning to `key[i]`. As a preventive measure, the `system()` function should be avoided.