Guarded Memory Move (GMM) Home Page



The Guarded Memory Move tool gets handy when you have to study buffer overflows and you need to catch them together with a "good" stack image. When a stack overflow has been exploited, the back trace is already gone together with good information about parameters and local variables, that are of vital importance when trying to understand how the attacker is trying to work out the exploit. The GMM library uses dynamic function call interception to catch the most common functions that are used by attackers to exploit stack buffers. The GMM library uses the LD_PRELOAD capability and offers two services to the user. First of all, it avoids buffer overflow to allow the attacker to execute shell-code on your machine. Second, in case where an exploit is detected, the stack content is saved and a segmentation fault is triggered. The resulting core dump will then have all the necessary information to debug the exploit and fix the software. Internally, the library insert itself between the application and the glibc library and intercept functions that might lead to buffer overflow exploits. Before calling the glibc core function, the GMM layer saves part of the stack frame above the caller to a temporary location in its frame. It also stores the previous three return addresses in its local storage before calling the glibc core function. When the core function returns, the GMM code samples again the previously recorded return addresses and, if they differ, it restores the previously saved stack frame and issue a segmentation fault. This with a clean stack frame, so that it can be inspected with a debugger. While other solutions exist to detect buffer overflow exploits, like for example StackGuard and StackShield, those differs from GMM in many ways. They live as gcc patches and do require you to rebuild your application to use their functionalities. The good of this approach is that every single function is protected against buffer overflows. The bad of this solution is that every single function is protected against buffer overflows. That is, performance regression on the whole application, even if this is not really a huge problem when hunting for buffer overflows. Another solution similar to GMM is LibSafe, but it does not save and restore the stack frame by making it unusable for debugging. But let's see how GMM differs from the above listed solutions. First of all, GMM works everywhere there are stack frames and the gcc and glibc duo. That means that it is not limited to i386 only. And now the real reason for the GMM existence. This is how it will look like a stack frame when a buffer overflow is detected with any debugger or the above solutions:

[davide@bigblue test]$ gdb -c core.14600 gmm-test
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
Core was generated by `./gmm-test uiyueiwyeowyreoywoeywoewoyrowuruowyeouwyeoqwyeowyeoyruowuoewueywewou'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x776f6579 in ?? ()
(gdb) bt
#0  0x776f6579 in ?? ()
Cannot access memory at address 0x77716f65
(gdb)

This buffer overflow is generated using the test application available inside the test directory of the distribution package. No much of useful information are there and no debugging is basically possible with the above information. Let's look at how the stack frame looks like when GMM is on the loop:

[davide@bigblue test]$ gdb -c core.14604 gmm-test
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
Core was generated by `./gmm-test uiyueiwyeowyreoywoeywoewoyrowuruowyeouwyeoqwyeowyeoyruowuoewueywewou'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from ../gmm/.libs/libgmm.so...done.
Loaded symbols for ../gmm/.libs/libgmm.so
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libdl.so.2...done.
Loaded symbols for /lib/libdl.so.2
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x400185d4 in sprintf (str=0xbffff840 "юб", fmt=0x8048464 "%s") at gmm.c:243
243     WRAP_VFUNCTION(int, sprintf, (char *str, const char *fmt, ...), fmt, (str, fmt, args))
(gdb) bt
#0  0x400185d4 in sprintf (str=0xbffff840 "юб", fmt=0x8048464 "%s") at gmm.c:243
#1  0x08048376 in do_overflow (str=0xbffffa44 "uiyueiwyeowyreoywoeywoewoyrowuruowyeouwyeoqwyeowyeoyruowuoewueywewouew") at gmm-test.c:33
#2  0x08048396 in run_test (str=0xbffffa44 "uiyueiwyeowyreoywoeywoewoyrowuruowyeouwyeoqwyeowyeoyruowuoewueywewouew") at gmm-test.c:41
#3  0x080483b3 in main (argc=2, argv=0x390d) at gmm-test.c:51
#4  0x40043ab7 in __libc_start_main () from /lib/libc.so.6
(gdb)

A lot better, isn't it? The whole stack frame is preserved and debugging and inspection of function parameters and local variables is possible. This is the main reason that drove the GMM development. It is possible to use the environment variable GMM_FAULT_EXEC to specify the path of an executable to be run when a fault is detected. The executable will be run with only one parameter, that is the PID of the monitored process. The monitored process will be waiting the external process to complete before continuing the execution (that will lead to a segmentation fault). The GMM_FAULT_EXEC can be used for many purposes. From sending an email notification up to for running a debugger to attach the faulting process. For the GMM library to work, the software should be compiled with frame pointers (that is gcc default) and for the stack dump to be useful, debugging information should be included inside the binary (gcc -g). There is a little performance regression in using this library, but it should not impact at all the normal use of the executable. And, when you are hunting for exploits, you don't really care about performance. To use the library, you first have to build it:

$ ./configure (put eventual configure parameters here)
$ make
# make install

To use the library you have to add it to the LD_PRELOAD in your enviroment (or put it on the same command line you're using to run the binary). Example:

$ LD_PRELOAD=/usr/local/lib/libgmm.so XXXX ...

where XXXX is the path of the binary you want to monitor. You might want to be sure that your core dump limit is not set to zero by issuing:

$ ulimit -c NNNN

where NNNN is the maximum size of the core dump in Kb.


Software


The latest package source code is available here:

GMM     0.6


Links


GMM White Paper

Rate this paper at SecurityDocs.com:
GMM Home Page at FreshMeat
StackGuard
StackShield
LibSafe



Author Home Page