Hi,
INTRO
-----
Welcome to a short series of security bugs, all involving mistakes with
"user supplied format strings". This class of bug is very popular on
Bugtraq at the moment, so what an ideal time for a few examples.
BSD-lpr
-------
If we look into
lpr/lpd/printjob.c, we can find the following two lines of code
if ((s = checkremote()))
syslog(LOG_WARNING, s);
This is a classic format string mistake.
It may not be exploitable, because the failure strings returned by
checkremote() in lpr/common_source/common.c, do not contain much data
that
a user could control.
However, it illustrates that format string bugs creep in everywhere,
even
in code that gets syslog() calls correct the majority of the time,
as is
the case with BSD-lpr.
Fix
---OpenBSD ship BSD-lpr. Not only have they already fixed this in their CVS, but they also offer web indexed CVS. They caught it independently as part of their "format strings" audit.
http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/lpr/lpd/printjob.c?r1=1.19&r2=1.20
Conclusion ----------
The next format string bug in the series will be much more interesting.
Cheers Chris
Hi,
SUMMARY
-------
LPRng is almost certainly vulnerable to remote-root compromise on account
of a format string bug. The flaw is almost identical to the rpc.statd
one
I found; namely a faulty syslog() wrapper. This is becoming a very
common
flaw.
Details
-------
Here is a code excerpt from:
/LPRng-3.6.22/src/common/errormsg.c, use_syslog()
--- static void use_syslog(int kind, char *msg) ... # ifdef HAVE_OPENLOG /* use the openlog facility */ openlog(Name, LOG_PID | LOG_NOWAIT, SYSLOG_FACILITY ); syslog(kind, msg); closelog();# else (void) syslog(SYSLOG_FACILITY | kind, msg); # endif /* HAVE_OPENLOG */ ... ---
Here we see two classic format string bugs. Both syslog() calls are missing a "%s" format string argument.
But how exploitable is this? Does the daemon log any use supplied data? Let's do a test on the extremely recently released RedHat7.0, which has switched to LPRng.
[chris@localhost chris]$ telnet localhost printer Trying 127.0.0.1... Connected to localhost.localdomain (127.0.0.1). Escape character is '^]'. Mary had a little lamb. Connection closed by foreign host.
...
grep lamb /var/log/messages Sep 24 07:38:36 localhost SERVER[1282]: Dispatch_input: bad request line 'Mary had a little lamb.^M'
...
Well, how obliging of (my particular version) of LPRng to log any input line I give it.
Just to confirm %'s cause trouble:
Client: [chris@localhost chris]$ telnet localhost printer Trying 127.0.0.1... Connected to localhost.localdomain (127.0.0.1). Escape character is '^]'. %s%s%s%s%s%s%s%s%s%s
Server: Program received signal SIGSEGV, Segmentation fault. 0x400f7c66 in _IO_vfprintf (s=0x80c53a0, format=0xbffff190 "Dispatch_input: bad request line '%s%s%s%s%s%s%s%s%s%s^M'", ap=0xbfffed0c) at ../sysdeps/i386/i486/bits/string.h:529 (gdb) bt #0 0x400f7c66 in _IO_vfprintf (s=0x80c53a0, format=0xbffff190 "Dispatch_input: bad request line '%s%s%s%s%s%s%s%s%s%s^M'", ap=0xbfffed0c) at ../sysdeps/i386/i486/bits/string.h:529 #1 0x4017d60b in vsyslog (pri=6, fmt=0xbffff190 "Dispatch_input: bad request line '%s%s%s%s%s%s%s%s%s%s^M'", ap=0xbfffed08) at syslog.c:193 #2 0x4017d447 in syslog (pri=6, fmt=0xbffff190 "Dispatch_input: bad request line '%s%s%s%s%s%s%s%s%s%s^M'") at syslog.c:102 ...
The program has root privs at this time;
(gdb) print geteuid() $1 = 4 <-- initially encouraging (gdb) print getuid() $2 = 0 <-- depressing
FIX ---
- Add "%s" arguments to the syslog() calls - Firewall the printer port
Exploit -------
Not my scene. I'm sure some friendly black hat will come out with one soon, though. Perhaps remembering to credit me this time? ;-)
Cheers Chris
Hi,
SUMMARY
-------
More format string bugs. Exploitability on these has not really been
researched. Current feeling is "maybe exploitable under certain
circumstances/configurations".
An in-depth discussion is not required. Here are the locations of the
code
flaws:
---[root@localhost dhcp-2.0]# pwd /usr/src/redhat/BUILD/dhcp-2.0 [root@localhost dhcp-2.0]# find . -name \*.c | xargs grep syslog |less ./client/dhclient.c: /* Initially, log errors to stderr as well as to syslogd. */ ./common/errwarn.c: syslog (log_priority | LOG_ERR, mbuf); ./common/errwarn.c: syslog (LOG_CRIT, "exiting."); ./common/errwarn.c: syslog (log_priority | LOG_ERR, mbuf); ./common/errwarn.c: syslog (log_priority | LOG_INFO, mbuf); ./common/errwarn.c: syslog (log_priority | LOG_DEBUG, mbuf); ./common/errwarn.c: syslog (log_priority | LOG_ERR, mbuf); ./common/errwarn.c: syslog (log_priority | LOG_ERR, token_line); ./common/errwarn.c: syslog (log_priority | LOG_ERR, ./relay/dhcrelay.c: /* Initially, log errors to stderr as well as to syslogd. */ ./server/dhcpd.c: /* Initially, log errors to stderr as well as to syslogd. */ [root@localhost dhcp-2.0]#
--- ucd-snmp-4.1.2/snmplib/snmp_logging.c snmp_log_string() ~line 183
... if (do_syslogging) { syslog(priority, string); } ... ---
Cheers Chris