你不知道的文件上传漏洞php代码分析

2025-05-29 0 56

漏洞描述

开发中文件上传功能很常见,作为开发者,在完成功能的基础上我们一般也要做好安全防护。
文件处理一般包含两项功能,用户上传和展示文件,如上传头像。

文件上传攻击示例

upload.php

?

1

2

3

4

5

6

7

8

9

10
<?php

$uploaddir = 'uploads/';

$uploadfile = $uploaddir . basename($_files['userfile']['name']);

if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){

echo "file is valid, and was successfully uploaded.\\n";

}

else {

echo "file uploading failed.\\n";

}

?>

upload.html

?

1

2

3

4
<form name="upload" action="upload1.php" method="post" enctype="multipart/formdata">

select the file to upload: <input type="file" name="userfile">

<input type="submit" name="upload" value="upload">

</form>

上述代码未经过任何验证,恶意用户可以上传php文件,代码如下

<?php eval($_get['command']);?>

恶意用户可以通过访问 如http://server/uploads/shell.php?command=phpinfo(); 来执行远程命令

content-type验证

upload.php

?

1

2

3

4

5

6

7

8

9

10

11

12

13
<?php

if($_files['userfile']['type'] != "image/gif") {//获取http请求头信息中contenttype

echo "sorry, we only allow uploading gif images";

exit;

}

$uploaddir = 'uploads/';

$uploadfile = $uploaddir.basename($_files['userfile']['name']);

if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){

echo "file is valid, and was successfully uploaded.\\n";

} else {

echo "file uploading failed.\\n";

}

?>

该方式是通过http请求头信息进行验证,可通过修改content-type ==> image/jpg绕过验证,可以通过脚本或burpsuite、fiddle修改
如下
content-disposition: form-data; name="userfile"; filename="shell.php"
content-type: image/gif

图片类型验证

该方法通过读取文件头中文件类型信息,获取文件类型

备注:如jpeg/jpg文件头标识为ffd8

你不知道的文件上传漏洞php代码分析

upload.php

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14
<?php

$imageinfo = getimagesize($_files['userfile']['tmp_name']);

if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg') {

echo "sorry, we only accept gif and jpeg images\\n";

exit;

}

$uploaddir = 'uploads/';

$uploadfile = $uploaddir . basename($_files['userfile']['name']);

if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){

echo "file is valid, and was successfully uploaded.\\n";

} else {

echo "file uploading failed.\\n";

}

?>

可以通过图片添加注释来绕过此验证。
如添加注释<?php phpinfo(); ?>,保存图片后将其扩展名改为php,则可成功上传。
上传成功后访问该文件则可看到如下显示

你不知道的文件上传漏洞php代码分析

文件扩展名验证

通过黑名单或白名单对文件扩展名进行过滤,如下代码

upload.php

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16
<?php

$blacklist = array(".php", ".phtml", ".php3", ".php4");

foreach ($blacklist as $item) {

if(preg_match("/$item\\$/i", $_files['userfile']['name'])) {

echo "we do not allow uploading php files\\n";

exit;

}

}

$uploaddir = 'uploads/';

$uploadfile = $uploaddir . basename($_files['userfile']['name']);

if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){

echo "file is valid, and was successfully uploaded.\\n";

} else {

echo "file uploading failed.\\n";

}

?>

当黑名单不全,构造特殊文件名可以绕过扩展名验证

直接访问上传的文件

将上传文件保存在非web root下其他文件夹下,可以防止用户通过路径直接访问到文件。
upload.php

?

1

2

3

4

5

6

7

8

9
<?php

$uploaddir = 'd:/uploads/';

$uploadfile = $uploaddir . basename($_files['userfile']['name']);

if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)) {

  echo "file is valid, and was successfully uploaded.\\n";

} else {

  echo "file uploading failed.\\n";

}

?>

用户不可以直接通过http://localhost/uploads/ 来访问文件,必须通过view.php来访问
view.php

?

1

2

3

4

5
<?php

$uploaddir = 'd:/uploads/';

$name = $_get['name'];

readfile($uploaddir.$name);

?>

查看文件代码未验证文件名,用户可以通过例如http://localhost/view.php?name=..//php/upload.php,查看指定的文件

解决漏洞示例

upload.php

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22
<?php

require_once 'db.php';

$uploaddir = 'd:/uploads/';

$uploadfile = tempnam($uploaddir, "upload_");

if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)) {

  $db =& db::connect("mysql://username:password@localhost/database");

  if(pear::iserror($db)) {

    unlink($uploadfile);

    die "error connecting to the database";

  }

  $res = $db->query("insert into uploads set name=?, original_name=?,mime_type=?",

      array(basename($uploadfile,basename($_files['userfile']['name']),$_files['userfile']['type']));

  if(pear::iserror($res)) {

    unlink($uploadfile);

    die "error saving data to the database. the file was not uploaded";

  }

  $id = $db->getone('select last_insert_id() from uploads');

  echo "file is valid, and was successfully uploaded. you can view it <a href=\\"view.php?id=$id\\">here</a>\\n";

} else {

  echo "file uploading failed.\\n";

}

?>

view.php

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21
<?php

require_once 'db.php';

$uploaddir = 'd:/uploads/';

$id = $_get['id'];

if(!is_numeric($id)) {

  die("file id must be numeric");

}

$db =& db::connect("mysql://root@localhost/db");

if(pear::iserror($db)) {

  die("error connecting to the database");

}

$file = $db->getrow('select name, mime_type from uploads where id=?',array($id), db_fetchmode_assoc);

if(pear::iserror($file)) {

  die("error fetching data from the database");

}

if(is_null($file) || count($file)==0) {

  die("file not found");

}

header("content-type: " . $file['mime_type']);

readfile($uploaddir.$file['name']);

?>

上述代码文件名随机更改,文件被存储在web root之外,用户通过id在数据库中查询文件名,读取文件,可以有效的阻止上述漏洞发生

总结

通过以上示例分析,可总结一下几点

1.文件名修改,不使用用户上传的文件名

2.用户不可以通过上传路径直接访问文件

3.文件查看采用数据库获取文件名,从而在相应文件服务器读取文件

4.文件上传限制文件大小,个人上传数量等

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 你不知道的文件上传漏洞php代码分析 https://www.kuaiidc.com/96485.html

相关文章

发表评论
暂无评论