As initial guess, this apparently simple service seems to be related to buffer overflows and ASLR.
As for most pwnables, the challenge provides the binary executable of the service. The mitigation techniques being used are:
To run (and debug) the service locally, a quick look at the disassembled code reveals that it is necessary:
to pass as a command line argument the port number on which to listen for connections
to create a linux user account named tutorial along with its home directory
to run the executable as super-user (to ensure sufficient privileges for setgroups() used by the function priv)
Further analysis of the disassembled service uncovers what happens for the two relevant menu choices:
1.Manual (function func1): the program prints the address of libc’s puts incremented by 0x500
2.Practice (function func2): the program read()s from the user 0x1CC bytes, stores them in a local buffer of size 0x12C, and finally write()s back to the user 0x144 bytes read starting from the same local buffer. Notably, the distance from the local buffer stack address to the function return address is 0x148 bytes (0x12C bytes for the local buffer, 0xC bytes for alignment, 0x8 bytes for the stack canary and 0x8 bytes for the base pointer)
Exploitation
Control of the RIP register is trivially obtained by the end of func2, since the read() call of 0x1CC bytes overflows the local buffer and allows to override the return address.
The same function does also the favor of leaking its stack canary to the user, by means of the write() call of 0x144 bytes.
Since the executable is NX protected, the shellcode must be costructed using Return-Oriented Programming. No address guessing is needed, since it is possible to reliably compute libc’s base address using the output of func1.
Summing up, the steps required to execute arbitrary code are:
connect to the service
choose 1.Manual, read the output and compute libc’s base address by simple arithmetics
choose 2.Practice, send any string shorter than 0x12C+0xC=0x138 bytes, read the output and extract the stack canary
choose 2.Practice again and send the final exploit crafted as 0x138 filler bytes + leaked stack canary + 0x8 filler bytes + ROP chain
(in the ROP chain, remember to redirect stdin and stdout to the socket, using e.g. dup2)