我的服务器上有一些垃圾邮件问题,在发现并删除了一些Perl和PHP脚本后,我开始检查它们的真正功能,尽管我是一名资深PHP程序员,但我对Perl没有什么经验,有人能帮我处理一下这里的脚本吗:
http://pastebin.com/MKiN8ifp
(这是一长行代码,脚本名为list.pl)
脚本的开头是:
$??s:;s:s;;$?::s;(.*); ]="&%[=.*.,-))'-,-#-*.).<.'.+-<-~-#,~-.-,.+,~-{-,.<'`.{'`'<-<--):)++,+#,-.{).+,,~+{+,,<)..})<.{.)-,.+.,.)-#):)++,+#,-.{).+,,~+{+,,<)..})<*{.}'`'<-<--):)++,+#,-.{).+:,+,+,',~+*+~+~+{+<+,)..})<'`'<.{'`'<'<-}.<)'+'.:*}.*.'-|-<.+):)~*{)~)|)++,+#,-.{).+:,+,+,',~+*+~+~+{+<+,)..})
它继续使用宝贵的少数非标点符号字符,直到最后:
0-9;\_rs}&a-h;;s;(.*);$_;see;
将s;(.*);$_;see;
替换为print
以获得此值。在有效载荷的前半部分用print
再次替换s;(.*);$_;see;
,得到这个,这就是解密代码。有效负载的后半部分是要解密的代码,但我不能再往下说了,因为正如你所看到的,解密代码正在envvar或cookie中寻找密钥(这样大概只有脚本的创建者才能控制或解码它),而我没有那个密钥。这实际上是相当巧妙的做法。
对于那些对细节感兴趣的人。。。第一部分,当去纠缠看起来像这样:
$? ? s/;s/s;;$?/ :
s/(.*)/...lots of punctuation.../;
行开头的$?
是包含子错误的预定义变量,毫无疑问,这只是混淆。它将是未定义的,因为此时不可能有子错误。
它后面的问号是三元算子的开始
CONDITION ? IF_TRUE : IF_FALSE
这也只是为了混淆。为true返回的表达式是一个替换正则表达式,其中/
斜线分隔符已替换为冒号s:pattern:replacement:
。上面,我放回了斜线。另一个表达式,也就是将要执行的表达式,也是一个替换正则表达式,尽管它非常长。分隔符为分号。
这种替换将$_
(默认的输入和模式搜索空间)中的.*
替换为大量的标点符号,这些标点符号代表了大部分代码。由于.*
匹配任何字符串,即使是空字符串,它也会被简单地插入到$_
中,并且在所有意图和目的上都与简单地将字符串分配给$_
相同,这就是我所做的:
$_ = q;]="&%[=.*.,-))'-,-# .......;;
以下几行是音译和另一种替换。(我插入注释指出分隔符)
y; -"[%-.:<-@]-`{-}#~$\;{$()*.0-9;\_rs}&a-h;;
#^ ^ ^ ^
#1 2 3
(1,2,3是分隔符,2和3之间的分号是转义符)
它的基本要点是,各种字符和范围-"
(空格到双引号),以及看起来像字符类(有范围)[%-.:<-@]
但不是的东西,被音译成更易读的字符,例如大括号、美元符号、括号、0-9
等。
s;(.*);$_;see;
下一次换人是魔术发生的地方。它也是一个使用模糊分隔符的替换,但有三个修饰符:see
。s
在这种情况下不起任何作用,因为它只允许通配符.
与换行符匹配。然而,ee
意味着对表达式求值两次。
为了了解我在评估什么,我进行了音译并打印了结果。我怀疑我在某个地方有一些字符被破坏了,因为有一些细微的错误,但这里是简短的(清理过的)版本:
s;(.*);73756220656e6372797074696f6e5f6 .....;; # very long line of alphanumerics
s;(..);chr(hex($1));eg;
s;(.*);$_;see;
s;(.*);704b652318371910023c761a3618265 .....;; # another long line
s;(..);chr(hex($1));eg;
&e_echr($_);
s;(.*);$_;see;
长正则表达式再次成为数据容器,并将数据插入$_
中以作为代码进行评估。
s/(..)/chr(hex($1))/eg;
开始看起来相当清晰。它基本上是一次从$_
读取两个字符,并将其从十六进制转换为相应的字符。
倒数第二行&e_echr($_);
让我困惑了一段时间,但它是一个子程序,定义在这个评估代码的某个地方,因为霍布斯能够很好地解码。美元符号的前缀是反斜杠,这意味着它是对$_
:的引用,即子程序可以更改全局变量。
经过多次评估后,$_
通过该子程序运行,之后$_
中包含的任何内容都将进行最后一次评估。大概这次是在执行代码。正如hobbs所说,需要一个密钥,该密钥取自运行脚本的机器的环境%ENV
。我们没有。
询问B::Deparse模块使其可读性(稍微提高一点)。