深入解析PHP中$_POST[]与php://input接收表单数据的差异与应用场景
POST /test/demo.php HTTP/1.1
Host: 192.168.1.136
Content-Length: 398
Content-Type 为 multipart/form-data 且边界为 ----WebKitFormBoundaryHwjtGxAgxib9xeFe 。
Mozilla/5.0 对应的是 Windows NT 10.0 系统且为 Win64 和 x64 架构,其内置的 AppleWebKit 版本是 537.36,该版本的内核像 Gecko ,浏览器 Chrome 的版本是 111.0.0.0 ,同时 Safari 的版本也是 537.36 ,而 Edg 的版本为 111.0.1661.54 。
Connection: close
WebKitFormBoundaryHwjtGxAgxib9xeFe 这个边界用于分隔 HTTP 请求中的不同部分,它在 Web 开发中具有特定的作用和意义,帮助服务器和客户端更好地处理和解析请求与响应。
Content-Disposition 表明这是一个表单数据,其中的 name 属性值为"name"。
123456
------WebKitFormBoundaryHwjtGxAgxib9xeFe
Content-Disposition 表明这是表单数据,其中 name 为"upload_file",对应的文件名是"upload.txt"
Content-Type: text/plain
upload test
------WebKitFormBoundaryHwjtGxAgxib9xeFe
Content-Disposition 为 form-data 形式,其名称为 "submit"。
Submit
需要说明的是,仅根据提供的这部分内容,难以确切理解其具体含义和情境,以上改写只是基于给定的字符串进行的一般性处理。
![深入解析PHP中$_POST[]与php://input接收表单数据的差异与应用场景 深入解析PHP中$_POST[]与php://input接收表单数据的差异与应用场景](http://blog.seo.xz.cn/zb_users/upload/sanimg/7167272c481baa8224ab68d7d713edaa.png)
后端只有$POST[]数组接收了 form 表单上传的内容。如上文所述,当 Content-Type 为 multipart/form-data 时,php://input 不起作用。
application 类型为 x-www-data-urlencoded
服务端代码
echo "\$_POST[]: ";
var_dump($_POST);
echo "
";echo "
";
echo "php://input: ";
输出通过 php://input 获取到的内容的相关信息。具体来说,就是将通过 php://input 读取到的内容以特定的格式进行输出展示,以便查看其具体的内容和结构等相关信息。
?>
form表单的内容
POST /test/demo.php HTTP/1.1
Host: 192.168.1.136
Content-Length: 23
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.1.136
内容类型为 application/x-www-form-urlencoded。
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54
Accept 包含以下内容:text/html、application/xhtml+xml、application/xml,其中 application/xml 的 q 值为 0.9;还包含 image/webp、image/apng 等,这些的 q 值均为 0.8;以及 application/signed-exchange,其 q 值为 0.7。
Referer 指向的是 http://192.168.1.136/test/demo.php 这个地址
Accept-Encoding 包含 gzip 和 deflate 。
语言偏好为:英语优先,中文(简体)其次,其权重为 0.9;中文(简体)又比单纯的中文权重高 0.1,权重为 0.8。
Connection: close
name=demo&submit=Submit
$_POST[]能够接收到 form 表单的内容。php://input 也能够接收到 form 表单的内容。正如上面所说,php://input 访问的是原始数据的只读流。后端接收到的和 http 传输的是相同的。但是解析的结果依然不同。
这里我突发奇想看看试试如果url编码的结果是什么
对“demo”进行再次编码并进行 url 全编码,这就相当于对其进行了 url 二次编码。
demo
->urlencode
%31%32%37%2e%30%2e%30%2e%31
这里存在差别。原因在于浏览器发包时会对 post 请求进行一次 url 编码,$_POST[]数组中的内容是经过 urldecode()处理之后的,而 php://input 访问的是原始数据,所以没有进行解码。
application/json
json格式通常在传输数据时被使用。我直接在 post 包中发送了 json 格式的数据。本来就应该能想到 $_POST[]数组是处理不了 json 格式数据的。在这种情况下,php 只能通过 php://input 来读取 post 的数据。
总的来说
php://input 能够接收除了 Content-Type 为 multipart/form-data 这种情况之外的内容。
$_POST[]数组仅处理类型为 application/x-www-form-urlencoded 或者 multipart/form-data 的情况。因为只有这两种类型能够被直接写成关联数组的形式,就如同在 python 里是字典,在 go 或 java 里是 map 一样。
php://input 命令执行的原理
请求头中的 Content-Type 字段会告知服务器后端用户交互上传的数据类型。$_POST 能够处理 form 表单上传的键值对格式(类似字典)的内容。然而,对于上述的 json 格式或其他格式的内容,$_POST 处理起来并不会生效。并且,php 的 Content-Type 类型不止这三种。
上面的三个例子说明了 php://input 是如何以及为何要从原始数据的只读流来处理 post 请求包的内容,并且这不是 php://input 能进行命令执行的关键所在。
它能进行命令执行主要取决于它与何种函数联动。它自身并不能直接进行 RCE,而是处理 php://input 内容的函数出现了问题。
比如经典的远程文件包含
file 接收来自 php://input 的内容,而 post body 中包含着完整的 php 文件内容。这里的关键之处在于 include()函数,该函数能够进行解析。
或者说直接是
根据上面的情况,直接在 post body 里输入 php 代码就可以了,并且不需要添加标签。需要注意的是,php://input 与全局变量 $_POST 是不同的,它通常是与 file_get_contents()函数一起配合使用的。
比如冰蝎4的默认shell
完