perianmellon has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks! I'm working on a buffer overflow example for a course and am trying to translate pre-existing exploit code into perl. Being a bit of a perl noob, I've gotten myself stuck! Is there any way to find the address of the top of the stack in perl (I need to find the address where my environment variables are going) Update: I'm using perl to exploit another c program that is vulnerable to buffer overflows. My perl program is just constructing the "egg" to feed into my vulnerable program and puts the exploit code into an environment variable. I'm trying to find the address of this variable so I can overflow the buffer in my vulnerable program with it. Thanks for your help!

Replies are listed 'Best First'.
Re: Finding stack addresses
by Joost (Canon) on Sep 18, 2006 at 20:51 UTC
    In pure perl (except for possible bugs in the interpreter) there is no way to get buffer overflows: the interpreter manages the memory for its variables without any direct intervention from the language and will just allocate more memory if you try to extend a string, hash or array. This might fail, ofcourse, but that will just shut down the interpreter with an out of memory error.

    In C/XS extensions, there is just as much possibility for buffer overflows as in pure C, because they are basically written in C (give or take a few hundred macros and some other preprocessing).

    In other words, it seems to me you're asking for the impossible or the obvious. See perlxs for the obvious answer.

    update: to find the top of the perl stack (which is not really where the environment variables are kept) see caller

      ah yes, I'm sorry I didn't clarify. I'm using perl to exploit another c program that is vulnerable to buffer overflows. My perl program is just constructing the "egg" to feed into my vulnerable program and puts the exploit code into an environment variable. I'm trying to find the address of this variable so I can overflow the buffer in my vulnerable program with it. Thanks for your help!
Re: Finding stack addresses
by ikegami (Patriarch) on Sep 18, 2006 at 20:54 UTC
    Perl doesn't use the system stack for passing arguments to Perl functions. We need to know more about the bug being exploited to answer you relevantly.
Re: Finding stack addresses
by mugwumpjism (Hermit) on Sep 19, 2006 at 06:38 UTC

    Perl's use of the system stack is sparing; only XS functions and closures invoked from within opcodes such as sort will cause a new stack frame to be made. So the top of the stack is only interesting to modules like Coro when it is freezing the current state of the Perl runops loop to swap another co-routine in.

    However the "top" might mean the logical "bottom" of the stack (ie, the very earliest call frame), given that the conventional treatment of these terms treats a stack as growing from the top down. I'm guessing what you're after is the actual raw offset of the environment space, which lives in address space beyond the end of the stack space. It might stand to reason that subsequent invokations of commands with the same environment would end up with the environment in the same place; perhaps it is even more reliably invariant than that. If that is the case, you have a good chance of finding a useful value to carefully overflow into a place on the stack that the EIP register will be restored from. Then as soon as the vulnerable function returns it will return into the trampoline you inserted into the environment.

    So, let's have a poke around with gdb:

    wilber:~$ gdb /usr/bin/debugperl GNU gdb 6.4-debian Copyright 2005 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and y +ou are welcome to change it and/or distribute copies of it under certain cond +itions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for det +ails. This GDB was configured as "x86_64-linux-gnu"...Using host libthread_d +b library "/lib/libthread_db.so.1". (gdb) run -dle 'my $x; print \$x' Starting program: /usr/bin/debugperl -dle 'my $x; print \$x' [Thread debugging using libthread_db enabled] [New Thread 46912504641232 (LWP 20986)] Loading DB routines from perl5db.pl version 1.28 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): my $x; print \$x DB<1> n main::(-e:1): my $x; print \$x DB<1> p \$x SCALAR(0x71bd20) DB<2> ^C Program received signal SIGINT, Interrupt. [Switching to Thread 46912504641232 (LWP 20986)] 0x00002aaaaae54162 in __read_nocancel () from /lib/libpthread.so.0 (gdb) bt #0 0x00002aaaaae54162 in __read_nocancel () from /lib/libpthread.so.0 #1 0x00002aaaab5b0657 in rl_getc (stream=0xb97170) at /build/buildd/readline5-5.1/input.c:451 #2 0x00002aaaab5b0615 in rl_read_key () at /build/buildd/readline5-5.1/input.c:431 #3 0x00002aaaab59ec41 in readline_internal_char () at /build/buildd/readline5-5.1/readline.c:479 #4 0x00002aaaab59eceb in readline (prompt=<value optimized out>) at /build/buildd/readline5-5.1/readline.c:526 #5 0x00002aaaab45288b in XS_Term__ReadLine__Gnu__XS_rl_readline () from /usr/lib/perl5/auto/Term/ReadLine/Gnu/Gnu.so #6 0x00000000004ca3d1 in Perl_pp_entersub (my_perl=0x6d1010) at pp_ho +t.c:2888 #7 0x000000000049ccc5 in Perl_runops_debug (my_perl=0x6d1010) at dump +.c:1452 #8 0x00000000004240f2 in S_run_body (my_perl=0x6d1010, oldscope=1) at perl.c:2000 #9 0x00000000004239f1 in perl_run (my_perl=0x6d1010) at perl.c:1919 #10 0x000000000041d2ca in main (argc=3, argv=0x7fffffbfd848, env=0x7fffffbfd868) at perlmain.c:98

    Well, looks like main::env is actually at a far different address than the stack pointer. Also it seemed (on this x86_64 system) to vary between invocations of the program, meaning that the assumptions about the exploit you're attempting I've made would indicate that on my platform, it wouldn't work. Bear in mind I'm no black hat hacker.

    I tried looking around with Devel::Peek on \%ENV to see if any of the internal magic structures of \%ENV are useful, but indeed none of them match the pointers returned by gdb. Digging deeper, sure enough Perl_my_clearenv and friends do not use an environment pointer from magic; the system environ pointer is used instead.

    However this looks interesting;

    wilber:/usr/src/perl-5.8.8$ gdb /usr/bin/debugperl GNU gdb 6.4-debian Copyright 2005 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and y +ou are welcome to change it and/or distribute copies of it under certain cond +itions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for det +ails. This GDB was configured as "x86_64-linux-gnu"...Using host libthread_d +b library "/lib/libthread_db.so.1". (gdb) run -dle '$x=1;print\$x;0' Starting program: /usr/bin/debugperl -dle '$x=1;print\$x;0' [Thread debugging using libthread_db enabled] [New Thread 46912504641232 (LWP 21378)] Loading DB routines from perl5db.pl version 1.28 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): $x=1;print\$x;0 DB<1> n main::(-e:1): $x=1;print\$x;0 DB<1> SCALAR(0x71bd50) main::(-e:1): $x=1;print\$x;0 DB<1> Program received signal SIGINT, Interrupt. [Switching to Thread 46912504641232 (LWP 21378)] 0x00002aaaaae54162 in __read_nocancel () from /lib/libpthread.so.0 (gdb) p Perl_Iorigenviron_ptr $1 = {char ***(PerlInterpreter *)} 0x57c780 <Perl_Iorigenviron_ptr>

    Well, no solution, but perhaps some interesting clues.

    $h=$ENV{HOME};my@q=split/\n\n/,`cat $h/.quotes`;$s="$h/." ."signature";$t=`cat $s`;print$t,"\n",$q[rand($#q)],"\n";