Format strings: bug #1: BSD-lpr

From: Chris Evans (chris@SCARY.BEASTS.ORG)
Date: Tue Sep 26 2000 - 01:57:04 CEST

  • Next message: Chris Evans: "Format strings: bugs #3 & #4: ISC-dhcpd, ucd-snmp"

  • 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


    Format strings: bug #2: LPRng

    From: Chris Evans (chris@SCARY.BEASTS.ORG)
    Date: Tue Sep 26 2000 - 01:57:43 CEST

  • Next message: Matthew Franz: "Nmap Protocol Scanning DoS against OpenBSD IPSEC"

  • 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


    Format strings: bugs #3 & #4: ISC-dhcpd, ucd-snmp

    From: Chris Evans (chris@SCARY.BEASTS.ORG)
    Date: Tue Sep 26 2000 - 01:58:12 CEST

  • Next message: Chris Evans: "Format strings: bug #2: LPRng"

  • 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