Search code examples
perlstack-overflow

Perl command line memory storage


I'm trying to pass a command line argument to a program 'notesearch.c' in order to overflow the buffer and rewrite the return address to 0x00007fff9e89b2e7 in little endian format using the command :

./notesearch $(perl -e 'print "\xe7\xb2\x89\x9e\xff\x7f\x00\x00" x 20')

However, the value stored at argv[1] is :

0x7fff9cd441cc: 0xe7 0xb2 0x89 0x9e 0xff 0x7f 0xe7 0xb2

0x7fff9cd441d4: 0x89 0x9e 0xff 0x7f 0xe7 0xb2 0x89 0x9e

0x7fff9cd441dc: 0xff 0x7f 0xe7 0xb2 0x89 0x9e 0xff 0x7f ......

The zeros are not stored ! So the actual 64bit overwritten return address can be any permutation of the non zero hexadecimal digits. How do i store the zeros as well?


Solution

  • On a unix-like system, it is not possible to pass arguments containing \0 characters.

    Perl is capable of printing the \0's, and some shells may be capable of retaining them in an internal representation of the command line, but when the shell runs the other program, it will do so with the execve syscall (all higher-level program execution routines are built on top of execve). The format of the argv passed to execve is NULL-terminated array of \0-terminated strings.

    This is the kernel ABI for program execution; there's no way around it. You could almost reimplement execve in userspace with your own ELF parser, but only the kernel can give you the privilege escalation of the set-id bits, and the kernel only does that when you call execve.