Still Shines.

一次恶意PHP脚本初探

Word count: 2.6k / Reading time: 9 min
2018/08/27 Share

这是一篇前段时间写的文章,现在归整到这个博客中,那个时候刚学网络安全不久。当时遇到这个木马也是极其偶然,就当做兴趣进行分析,搞了差不多有一天半的时间,期间收获颇多,果然实践中才是出真知啊。


木马来源

  有天早去上课的时候收到学妹的消息说她的服务器被人上传了木马,我当时心里一愣,因为前一天还在和她讨论关于在她网站上存在的安全性问题,结果第二天就被人黑了,不禁感叹现在黑客的效率是真的高啊。

为了证明我这不是马后炮,贴出以下聊天记录:
前一天:
前一天
后一天:
后一天
  她用的是WordPress这个博客系统,wordpress本身的安全性还可以,使用也很方便。但是各种第三方插件的安全性就不敢保证了。她正是因为装了有安全漏洞的第三方插件,所以就被黑客利用了,估计还是大规模攻击的受害者。通过腾讯云的路径提示找到了恶意脚本文件(木马,webshell等在本文中是同一个意思)。再通过查看访问流量看到入侵者的IP地址,查明后发现来源是俄罗斯。俄罗斯黑客在我印象中都是挺厉害的,就打算分析一下源码,下面就把这个过程分享出来。

初始信息分析

脚本名:404.php(伪装成404文件,起隐藏作用。)

1、在php环境下浏览器打开

显示如下:

恶意脚本的登录界面,需要输入密码进入,尝试多次弱口令登录没有通过。

2、用Notepad++打开查看源码

显示如下:

发现是一个经过编码加密后的内容,从这里看不到源码,所以只能先进行破解。


开始破解

第一步
观察变量,把中间一大串密文字符忽略(这里用X代替),整体框架显示如下:

这里解码较为容易,第一行是一串无规则的字符,存放到一个变量中。再从这个变量中取第几位,和其他字符组成一个完整的单词。比如$MZz9092[9]就是最开头的第0位数到第九位的字符,也就是p。
第二步
我们加一个echo($AI2908);让浏览器运行的值显示出来,保险起见可以先把其他代码先注释掉。
操作如下:

显示结果如下:

这是一个PHP的替换函数。
第三步
解码下一个变量的值:$vVzI785

  这串代码中有chr()函数,查ascll码表得知chr(101)是e,通过ascll码表的对应关系,可以解除chr()的字符,在这其中还存在着十六进制(hex)编码,整个就像是混合编码,机器是能够直接识别,人眼就不容易发现规律了。

编码原理:chr(101)意思就是ascll码表上101个字符 是e
\x61 对应的解码是 a

之后在变量前加个echo让机器自动解码,$vVzI785变量和$ePpo5652编码原理相同,就一起显示出来:

浏览器显示如下:

  因为中间没有加换行符,所以显示的结果连在一起,主要加密的内容(X代替的部分)就放在这个括号中。

最后整理下得到如下:

最后一行加密部分解码出来是一个正则表达式:/.*/e 此处没实际作用就先不管它。
接下来看主体的编码方式。
第四步
  存放主体的变量$kJVTr8520是base64加密后再压缩编码。所以解码的顺序就反着来,先解压缩然后base64解码。这里我们继续使用echo(echo大法好!)
  把之前x替换的主体放进括号,然后用echo大法构造这行echo($kJVTr8520);这里要把原来的eval删去改成echo。文件尾部图片中已改。

文件头部:

文件尾部:

利用echo查看传给这个变量的值。
浏览器查看直接得到解码后的“原文”:

第五步
放到编辑器上整理一下:
代码头部:

代码尾部:

又是一层加密,而且感觉是多重加密,这个脚本的作者应该不是!(估计是程序生成)
这段代码可以看成两个部分:密码验证部分主体.
主体也分成了两个部分:代码尾部的base64加密的部分是一段多重base64加密,主体部分又是一大串加密编码后的字符传值给一个变量。
第六步
  这里先从密码验证部分入手,作者之所以把这部分独立出来估计他也是怕忘记密码后没法改吧。所以我们正好可以利用这一点,既然猜不出你的密码,那就自己改咯。
先看到第一行代码:

密码是md5加密后的,我试过解这串md5但是现有的解码网站都解不出。
那就换一个思路,自己改密码值。
先查了下已知明文admin经过md5加密后的值是多少:

这里就用第一行的密文,替换掉原来的md5:

Ps:这里如果直接输$auth_pass=”admin”是不行的。
第七步
之后再回到之前最开始访问的登录界面,密码处敲入admin。

进去了!现在就可以使用这个木马做想做的事情咯~而且功能还挺全的,是个大马。

字符编码是:窗口1251,属于斯拉夫语系,俄语正是斯拉夫语系的,看来是俄罗斯的木马没跑了。
现在到这一步就可以把这个木马收归己有了~
第八步
再从这里查看源码:

诶?发现只是一个静态的界面,执行这段代码没有任何功能,所以从这里我们获得的不是真正的源码。


主体内容破解

  精彩的内容来了!接下还是要分析主体部分。规律掌握了,就不再慌张。上面说了主体也是可以看成两个部分,代码部分和加密函数部分。加密函数就是解密代码部分的内容。

1、先从加密函数开始


这串密文果然是经过多次base64加密的(真的很麻烦呐),利用多次echo大法解出整理后得到如下:

脚本的作者还把变量名起的很复杂难以理解,看来是使用程序生成的,手工破解的我就用简单的字符替换了:

现在就比较清晰了。
这里主要关注for循环的内容,就能理解加密规则。
php中的strlen函数可以获取代码的字符串长度。for循环中i从0开始,也就是第一个字符开始,每循环一次,i自加1跳到下一个字符,直到最后一个字符为止。
从第一个字符开始,然后让它和后面的2129405204进行异或(^)的位运算。

(1)拿n这个字符举例:

得到的是110(ord就是求n再ascll码中对应的数值)。
(2)再让n进行位运算:

得到的是:

(3)再通过chr函数得到最后的结果为: z
这样n就替换成了z。
这样整篇大段的字符都被相同的方式替换。最后传值给$a。

知道这个原理后我们就继续用echo显示出传给$a的值:

得到以如下代码:

又双叒是一层加密。
让我想到了杨宗纬的《洋葱》一层一层拨开你的心~
稍微欣慰点的是这个变量名不那么奇怪了。

2、了解两个函数

先来了解substr和hexdec这两个函数的功能(毕竟对php不熟,磨刀不误砍柴工嘛。)
Substr:

Hexdec:

接下来继续看加密函数,现在这个脚本整体编码的思想就是替换,密码学算法知识尚未涉及,不过花样确实够多,只有这样既能绕过防火墙检测还能被电脑继续执行。

这个替换函数的规则是用substr提取字符,并把取出的字符当做是十六进制再转换为十进制,最后再用chr转换为字符进行替换,而且是一次性提取两个。
比如“0123456789abcde中”(因为是作为十六进制的,上面一大串代码中就不会出现其它字符了)
取到了cd,把cd当成一个十六进制的值转为十进制就是205:

如此进行替换。
这一部分函数的功能明白后开始继续用echo大法。

得到下一串代码:

又是一层加密!!不过能预感到这是最后一层了,底部出现了似曾相识的正则替换,

但在这里意义同样不大。

3、继续echo大法:


Duang~浏览器运行直接出现网页了,不过这个报错的弹窗是什么鬼?

但经历过这么多的我看到这里,内心没有丝毫波动,甚至还有点想笑,一眼看出这是运行JavaScript的结果,真相就在这里了!

4、查看源码

源码就在这里,但是怎么才能查看呢?
我们可以写一个解码用的脚本,让它把让echo显示的值直接写到文件上:

1
2
3
4
5
6
7
8
9
10
<?php
$Code = ''; //base64
$File = 'test.php';//解码后保存的文件
$Temp = base64_decode($Code);
$temp = gzinflate($Temp);
$FP = fopen($File,'w');
fwrite($FP,$temp);
fclose($FP);
echo "success!";
?>

把之前要解码的字符放上去,最后在同一个目录下生成了一个test.php的文件。文本编辑器打开就是心心念念的源码了,不再是之前得到的静态”源码”!

然后找到了刚刚弹窗报错的那段代码。呵,小把戏。一切都一目了然了~
剥完这个洋葱后,留下了“欣喜”的泪水。

CATALOG
  1. 1. 木马来源
  2. 2. 初始信息分析
    1. 2.1. 1、在php环境下浏览器打开
    2. 2.2. 2、用Notepad++打开查看源码
  3. 3. 开始破解
  4. 4. 主体内容破解
    1. 4.1. 1、先从加密函数开始
    2. 4.2. 2、了解两个函数
    3. 4.3. 3、继续echo大法:
    4. 4.4. 4、查看源码