freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

伪协议php:input命令执行的原理
may1as 2023-04-07 14:27:59 239798
所属地 河南省

文前漫谈

研究几种webshell管理工具时遇见,发现几款常见的webshell管理工具都有对php://input的利用

本文记录我对php://input原理的学习和思考,如有疏漏失错,还请联系告知

$HTTP_RAW_POST_DATA的作用和php://input的作用相同,但是PHP 5.6.0. 被废弃了,后面的版本中就是用php://input替代。所有本文省略

官方文档的解释

$_POST数组

当 HTTP POST 请求的 Content-Type 是application/x-www-form-urlencodedmultipart/form-data时,会将变量以关联数组形式传入当前脚本。

php://input 伪协议

php://input 是个可以访问请求的原始数据的只读流。当请求方式是post,并且Content-Type不等于"multipart/form-data"时,可以使用php://input来获取原始请求的数据。

从POST的几种Content-Type看PHP的$_POST []与 php://input

通常的,在php中我们用$POST[]数组来处理封装好的POST请求正文中的内容,下面从http post上传时几种不同的表单编码格式分析$POST[]数组和php://input伪协议在处理post内容时的差别

POST表单上传时常见有这几种编码:

  • multipart/form-data

  • application/x-www-data-urlencoded

  • application/json

  • text/plain

multipart/form-data (文件上传时的编码)

服务端代码

<html>
<form enctype="multipart/form-data" method="post">
<input type="text" name="name" />
<input type="file" name="upload_file" />
<button type="submit" name="submit" value="Submit">Submit</button>
</form>
<?php
echo "\$_POST[]: ";
var_dump($_POST);
echo "<br>";echo "<br>";
echo "php://input: ";
var_dump(file_get_contents("php://input"));
?>
</html>

上传 upload.txt , form表单如下,文件上传的post包就不多解释了

boundary=----WebKitFormBoundaryHwjtGxAgxib9xeFe就是multipart分块传输的分界线

这个http包我精简过,注意Content-Type即可

POST /test/demo.php HTTP/1.1
Host: 192.168.1.136
Content-Length: 398
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHwjtGxAgxib9xeFe
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
Connection: close

------WebKitFormBoundaryHwjtGxAgxib9xeFe
Content-Disposition: form-data; name="name"

123456
------WebKitFormBoundaryHwjtGxAgxib9xeFe
Content-Disposition: form-data; name="upload_file"; filename="upload.txt"
Content-Type: text/plain

upload test
------WebKitFormBoundaryHwjtGxAgxib9xeFe
Content-Disposition: form-data; name="submit"

Submit
------WebKitFormBoundaryHwjtGxAgxib9xeFe--

看见后端只有$POST[] 数组接收了form表单上传的内容,正如上面说的,当Content-Type: multipart/form-data;,php://input并不起作用

image.png

application/x-www-data-urlencoded

服务端代码

<html>
<form enctype="application/x-www-data-urlencoded" method="post">
<input type="text" name="name" />
<button type="submit" name="submit" value="Submit">Submit</button>
</form>
<?php
echo "\$_POST[]: ";
var_dump($_POST);
echo "<br>";echo "<br>";
echo "php://input: ";
var_dump(file_get_contents("php://input"));
?>
</html>

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
Content-Type: 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;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.1.136/test/demo.php
Accept-Encoding: gzip, deflate
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
Connection: close

name=demo&submit=Submit

$_POST[] 和 php://input都能接收到form表单的内容,也正如上面所说,php://input访问的时原始数据的只读流,后端接收到的和http传输的是相同的,但是解析的结果依然不同

image.png

这里我突发奇想看看试试如果url编码的结果是什么

把 'demo' 进行再一次编码url全编码,相当于url二次编码了

demo
->urlencode
%31%32%37%2e%30%2e%30%2e%31

image.png

这里两者之间就有些差别了,具体原因就是浏览器发包时还会对post请求进行一次url编码,$_POST[]数组的内容是urldecode()之后的,而php://input访问的还是原始数据,也就没有解码

image.png

application/json

json格式通常在传输数据时使用,我直接在post包中发送json格式的数据了。其实理所应当的能想到$_POST[]数组是处理不了json格式的数据的,这种情况php只能用php://input读post的数据

image.png

总的来说

php://input会接收除了Content-Type: multipart/form-data情况下的内容

而$_POST[]数组只处理类型为application/x-www-form-urlencodedmultipart/form-data的情况,因为只有这两种能被直接写成关联数组的形式(就是python里的字典,go\java里的map)

php://input 命令执行的原理

请求头中的Content-Type字段告诉服务器后端用户交互上传的是什么类型的数据,$_POST能处理form表单上传的键值对格式(类似字典)的内容,但是处理如上的json格式或者其他格式内容并不会生效。何况php的Content-Type类型且不止这三种

上面的三个例子也更好的说明了php://input是怎样和为什么要从原始数据的只读流处理post请求包的内容,但这不是php://input能进行命令执行的关键

它能进行命令执行的关键还是看它和什么函数联动,它本身并不能进行RCE,是处理php://input内容的函数出了问题

比如经典的远程文件包含

<?php
include($_GET['file']);
?>

file接收php://input的内容,post body里就是完整的php文件内容,这里的关键就是include()函数,它会解析

image.png

或者说直接是

<?php
eval(file_get_contents("php://input"));
?>

这种情况根据上面所说,直接在post body里输入php代码就行,连标签都不用加。(注意php://input和全局变量$_POST不同,它通常配合file_get_contents()函数使用)

image.png

比如冰蝎4的默认shell

image.png

# web安全 # php # webshell # 伪协议 # php伪协议
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 may1as 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
may1as LV.2
学习ing
  • 4 文章数
  • 4 关注者
面试经典 Redis未授权漏洞与组合拳
2022-11-08
CTF中我的USB键盘鼠标流量解密指南和脚本
2022-11-05
pythonweb SSTI的payload构造思路研究
2022-07-24
文章目录