LD_PRELOAD example library with example code!

execvhack.so

I had a desire, or a nerdy, geeky need to create this library that overrides:

  • int execv(const char *path, char *const argv[]);
  • int execvp(const char *file, char *const argv[]);
  • int execve(const char *path, char *const argv[], char *const envp[]);

Upon initialization, all original function pointers are saved via the constructor, as defined here: http://tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html#INIT-AND-...

When a given overloaded function is called, the values of argv are printed to stderr, prefixed with the called file or path.

I built it as an RPM, with included source, signed by my RPM signer key, and put on a remote repository. I also included a repository RPM to help the ease of use of this repo. It resides at http://www.gonoph.net/repos/gonoph.net/

I'll work on getting it into github.

To use:

  1. cd /tmp ; wget http://www.gonoph.net/repos/gonoph.net/generic/dist/gonophnet-generic-1....
  2. yum install /tmp/gonophnet-generic-1.0.0-1.x86_64.rpm
  3. yum install execvhack
  4. less /usr/share/doc/execvhack/README
  5. man execvhack.so

The source RPM is here: http://www.gonoph.net/repos/gonoph.net/generic/sources/execvhack-1.0.0-1...
(I also created an RPM version of shc.)

Shell to C - aka shc

Sometime ago, I ran across a cool program by Francisco Javier Rosales García called shc which stands for shell to C. His webpage is http://www.datsi.fi.upm.es/~frosal/. His software basically turns a shell program into a C binary, while doing some neat tricks.

It does the following:

  • encrypts the shell script payload
  • hinders debugging or tracing via re-exec() of argv[0]
  • prevents redistribution via a mechanism which ties the encryption key to the file itself.
  • prevents strace or ptrace() calls by forking and obtaining an exclusive lock on /proc/$pid/kmem
  • performs an expire check if desired, to automatically expire the script by a certain date
  • executes the shell script as a /bin/$shell -c "$payload"
  • immediately wipes the argument list after the shell starts

It's a rather clever piece of software. I started down a path to figure out how to peek inside and see something I shouldn't - as that's part of the purpose of shc. I tried:

strace:
Didn't work, as the re-exec() of the shell based on argv[0] kept executing strace.
Even stopping the process and attaching strace didn't seem to work.
microsecond sleep loop to kill -STOP and kill -CONT :
Didn't work as cmdline was wiped before I could read it.
gdb debugger:
Didn't work at first due to the re-exec()
gdb debugger attaching to $pid
Didn't work as it forks a process to get an exclusive lock on /proc/$pid/kmem, and then kills itself if it can't.

Eventually, I had an idea:

Why don't I override execv(), and print out all the arguments, then pass the execution back to the original system call?

That worked perfectly.

I also figured other people might want be interested in this, and while there are lots of tutorials out there, there isn't anything that's just a pre-compiled binary, ready as an example. So, I built one.

From the README:

OVERVIEW OF USAGE
by Billy Holmes 

This library is an example of how to perform LD_PRELOAD, and is an example of
how certain system calls can be hijacked for other purposes. Imagine malloc()
being  hijacked, and a new thread being created which monitors the memory
pointers of everything returned by the original malloc() function. Based on
other filters and logic, this thread could easedrop or change memory which the
calling program assumed was secure or immutable.

While this is not a huge concern for normal open source software, proprietary
software, or security software maybe concerned.

Additionally, a noble developer may use this solve a bug, or implement a
feature that wasn't included in an existing library for which there is no
original code (inherited systems anyone???). The sky is the limit here - it's
just up to your imagination!

To build it:

	$ make all

To install the shared library under /usr/local:

	$ make install

OR just install it from the execvhack.spec file.

	$ rpmbuild -ba execvhack.spec
	$ yum install `ls ~/rpmbuild/RPMS/$(uname -p)/execvhack-*.rpm | head -1`

HOW TO USE IT

	$ LD_PRELOAD=/usr/local/lib/execvhack.so sh -c 'sh -c "/bin/echo this is a test"'
	Loading hack.
	/usr/bin/sh: argv[0]: [[sh]]
	/usr/bin/sh: argv[1]: [[-c]]
	/usr/bin/sh: argv[2]: [[/bin/echo this is a test]]
	Loading hack.
	/bin/echo: argv[0]: [[/bin/echo]]
	/bin/echo: argv[1]: [[this]]
	/bin/echo: argv[2]: [[is]]
	/bin/echo: argv[3]: [[a]]
	/bin/echo: argv[4]: [[test]]
	Loading hack.
	this is a test

REAL WORLD EXAMPLE

There is a script emedded in the file called "./secret". After your distro's
installation, it may reside in your "docs" directory. On fedora and gentoo type
installs, that will be in /usr/share/doc/execvhack. It may have a version
number behind it.

When you run it:

	$ ./secret
	Type the secret:
	ERROR!! You don't know the SECRET!

If you perform the preload trick:

	echo | LD_PRELOAD=/usr/local/lib/execvhack.so  ./secret 2>&1 > /dev/null | grep SECRET=
	_SECRET=### RANDOM ###

After the grep, you should see the secret password. If you use that secret
code, it will compile and run an embedded C program that demostrates a rounding
bug in casting int from a double. This bug exists in python, C, perl, and java.

You can look at the original "secret" shell script, the embedded shell script,
and the embedded C program in the following files:

	secret.sh
	mycode.sh
	mycode.c

Additionally, to check the compiled script vs the original:

	$ echo | LD_PRELOAD=/usr/local/lib/execvhack.so  ./secret 2>&1 > /dev/null | sed -n '/#!\/bin\/sh$/,/]]/p' | \
	sed 's%^.*\(#!/bin/sh\)$%\1%' | head -n -1 | sha256sum ; sha256sum secret.sh
	aead59f0462b7438941c342bb59c914d27f84610cb97d1a75824199edea44170  -
	aead59f0462b7438941c342bb59c914d27f84610cb97d1a75824199edea44170  secret.sh

And to check the embedded shell script vs the original:

	$ ./secret --check ; sha256sum mycode.sh
	Checking sha256 checksum
	50e2581f858224d857eb854061b3dc2c95069abf730a8e29db26318ee8f51d07  -
	50e2581f858224d857eb854061b3dc2c95069abf730a8e29db26318ee8f51d07  mycode.sh

Happy hacking!!

--b

Recent comments