Web漏洞之文件的上传、下载及包含
- 文件上传
- 一、基础知识
- 二、PHP函数
- 三、Upload-labs过关记录(Pass 01-Pass21)
- Pass-01(前端,JS类验证)
- Pass-02(白名单,MIME类型)
- Pass-03(黑名单,特殊解析后缀)
- Pass-04(黑名单 , .htaccess解析文件)
- Pass-05(黑名单 ,一次过滤绕过)
- Pass-06(黑名单 ,大小写绕过)
- Pass-07(黑名单 ,空格绕过)
- Pass-08(黑名单 ,点绕过)
- Pass-09(黑名单 ,::$DATA绕过)
- Pass-10(黑名单,与Pass-5重复 )
- Pass-11(黑名单 ,双写绕过)
- Pass-12(白名单,%00截断GET型)
- Pass-13(白名单,%00截断POST型)
- Pass-14(白名单,文件头检测,图片马)
- Pass-15(突破getimagesize(),图片马)
- Pass-16(突破exif_imagetype(),图片马)
- Pass-17(二次渲染)
- Pass-18(条件竞争)
- Pass-20(突破move_upload_file())
- Pass-21(利用数组绕过)
- 四、绕过WAF
- 文件包含
- 文件下载
(部分搜寻的资料用于自学,如有侵犯,联系可删! ———— by 611)
文件上传
一、基础知识
1、文件上传漏洞
文件上传在一些网站应用中是必不可少的一部分,比如个人博客上传头像、上传某些文件等,那么就可以利用这个文件上传的功能将webshell进行上传,但是大多数网站都会对文件上传的功能进行过滤优化,从而阻止这些webshell的上传,因此我们的目的就是想尽各种办法将webshell进行上传。
2、黑名单
常见后台代码:
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR))
{
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$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,即:将字符串中所有的::$DATA都换成空格
$file_ext = trim($file_ext); //收尾去空(去掉后缀名的空格)
if (!in_array($file_ext, $deny_ext))
{
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name']))
{
$img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
$is_upload = true;
}
}
else
{
$msg = '此文件不允许上传!';
}
}
else
{
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
(1)后缀名绕过(Pass 3)
.php ——————> .php3 .php4 .php5 .phtml 等
(2).htaccess解析(仅限于Apache使用,Pass 4)
.htaccess文件是Apache的分布式配置文件(httpd.conf是全局配置文件),该文件提供了针对目录改变配置的方法,也就是如果在一个特定的目录里放入该文件,该文件里写一条或多条命令,那么这个目录及其子目录下的所有都会按照这个文件里所要求的命令来执行。
所以在文件上传里,我们就可以上传一个新的.htaccess文件,但是这个新的.htaccess文件的解析规则是我们自己重新写的,上传之后,就会覆盖掉之前的.htaccess解析文件,从而执行我们重新写好的,进而实现webshell的上传,常见的重写解析代码如下:(可以自己上网搜)
<FilesMatch "6111">
SetHandler application/x-httpd-php
</FilesMatch>
//上述几行代码意思是将文件名为6111的文件按照application/x-httpd-php的方式进行解析
(3)大小写绕过(Pass 6)
许多后台文件上传代码中如果没有进行大小写的过滤,比如并未采用strtolower函数对其全部降为小写,如果采用了黑名单方式,那么就可以利用后缀大小写来绕过,从而上传webshell。(比如Pass 06)
(4)空格绕过(Pass 7)
|.php|——————>|.php | //就是.php后面加个空格,应该抓包加空格,因为比如windows系统重命名时会自动去掉
注意:是末尾加空格,中间加空格就算能上传成功,后缀也无法解析,不能识别。(比如.p hp无法解析)
(5)点绕过(Pass 8)
.php——————>.php.
(6)::$DATA绕过(Pass 9)
利用Windows的特性,在Windows中如果遇到 “ 文件名 + ::$DATA ” 的形式,会把::$DATA之后的数据都当做文件流来处理,不会检测后缀名,而且保持::$DATA之前的文件名,例如:" phpinfo.php::$DATA ",Windows就会自动去掉末尾的::$DATA,变成phpinfo.php
.php——————>.php::$DATA
(7)双后缀名绕过(Pass 11)
.php——————>.pphphp
(8)一次过滤绕过(Pass-5)
许多后台代码,对于点、空格等可能只是过滤了一次,不会过滤第二次,我们就可以钻这个空子,将被过滤数据进行二次复写。
3、白名单
(1)%00截断(0x00截断)
使用条件:
- php版本小于5.3.4
- 魔术引号(magic_quotes_gpc)为off状态。(因为开启魔术引号后%00会被加上一个反斜杠转义掉)
原理分析:无论是0x00还是%00,最终都会被解析成chr(0),chr()是一个函数,这个函数是用来返回参数所对应的字符的,Ascii码的0对应的就是空字符NULL,截断的关键就是这个空字符。许多应用程序(比如php解释器)在编写时,读取字符串时,将空字符作为字符串的结尾,也就是说,当一个字符串中存在空字符时,在被解析的时候会导致空字符后面的字符被丢弃。那么也就是说,假如存在过滤,我按规则上传了一个611.php.0x00.jpg文件,由于是图片格式,所以会成功上传,但是解析的时候,.jpg会被截断掉,php文件就成功上传了。
0x00和%00:0x00代表16进制的空字符00,需要在HEX中改为00,进行截断;而%00是URL解码之前的字符,它被解码成16进制ASCII码之后实际上也是0x00,所以它们最终都对应的是空字符,只不过使用的位置不同。
- %00截断GET用法(Pass 12)
.php——————>.php%00——————>提交给服务器
- %00截断POST用法(Pass 13)
.php——————>.php%00——————>url解码成.php ——————>提交给服务器
有区别的原因:POST请求正文传输过程需要保证其一致性,正确性,所以要保证内容在编码前什么样,解码完就必须什么样。但Get型请求不一样,有的编有的不编。
例如输入一个字符串:abc%00ef
POST型传输(假设是URL编码):abc%00ef ——> abc%2500ef ——> abc%00ef
Get型传输:abc%00ef ——>abc%00ef ——abc空ef
也就是说:要想POST型达到Get型传输一样的结果,就需要Post方式下让其交给服务器的内容是按照我们的想法编码好的,比如只有让其编码完是abc%00ef,服务器解码完才是对的。但是文件上传中有的post数据的编码方式可能并不是URL编码(比如pass 13中post数据的编码方式是multipart/form-data,就算我们传递给服务器abc%00ef,服务器也不会帮我们解码出abc空ef,因为服务器只会按照Content-Type中的multipart/form-data方式解码,所以在Post型提交的时候,我们要帮服务器提前进行url解码,解码完才会达到我们想要的效果。
(2)MIME类型(参见Pass 02)
许多文件类型限制在了MIME类型中,我们可以抓包修改MIME类型来绕过。
4、其他
(1)文件头检测:用图片马通过。
如Pass-14中的代码是通过检测文件头的前两个字节来判断是否是图片类型,比如89 50就是png格式。

(2)二次渲染
二次渲染是一种技术,就是指:上传图片后,网站会对图片进行二次处理(格式、尺寸、保存、删除要求等等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片,将其进行显示,所以我们所上传的图片信息有一部分会被更改或处理,这种技术手段叫二次渲染。所以如果写代码时第一次是没有经过过滤的,那么我们就意味着第一次是可以成功上传,那就可以后续在想办法绕过二次处理,从而就产生了文件上传的漏洞。
如果我们上传了图片马,由于进行二次处理,就会导致图片马中的代码被删掉处理,这样新生成的图片就不再是图片马了,代码无法执行。所以我们绕过的思想就是上传图片,然后用十六进制查看器对比原图片和处理后的图片哪里发生了改变,哪里没变,把木马插入到没变的地方,再配合文件包含漏洞,就可以绕过二次渲染。(了解原理,一般得写python程序,人工尝试会很费力)
(3)条件竞争
条件竞争,官方一点的定义就是:两个或者多个进程同时处理一个资源时产生的时间或序列的冲突。简单来说,原理就是卡BUG,在文件上传中,许多源代码设计成:如果上传了php文件,后端会在短时间内将其删除掉,所以我们要在其删除之前访问文件,就会无法删除。这里就相当于我们平时在打开某个文件的时候去删除它,会导致无法删除,那么在我们访问成功的那一瞬间,文件就会被写入,木马就会成功执行。
(4)突破getimagesize函数:用图片马通过。
getimagesize()函数主要用于获取图像大小及相关的信息。我们用图片马通过。
(5)突破exif_imagetype函数:用图片马通过。
exif_imagetype()函数主要用于确定图像的类型。我们用图片马通过。
(6)突破move_upload_file()函数(Pass 20)
move_uploaded_file(file,newloc),该函数用来把上传的文件移动到新的位置。但该函数有一个特性,就是会忽略掉文件末尾的/.
所以如果只有黑名单过滤,没有其他的,那么就可以上传.php/.的文件,绕过黑名单后缀成功上传,然后后端使用了move_upload_file()函数又会忽略点末尾的/. 那么.php文件就成功地被解析了。
(7)内容逻辑数组绕过(见Pass 21)
5、中间件解析漏洞(用vulhub靶场复现)
前面描述的都是由于代码书写而导致的文件上传漏洞,而实际上除了代码问题以外,对于某些中间件的某些版本本身就有解析漏洞,解析漏洞就是一些特殊文件被Apache、IIS、Nginx等Web容器在某种情况下解释成脚本文件格式并得以执行而产生的漏洞。
解析漏洞分类: IIS解析漏洞、Apache解析漏洞、Nginx解析漏洞

vulhub靶场搭建步骤:
//先更新软件,防止出错
sudo apt-get update
//安装docker
apt install docker.io
//安装docker-compose
sudo apt-get install python3-pip //安装python3环境
pip3 install docker-compose
sudo docker-compose -v //查看版本,验证是否安装成功
//安装vulhub靶场
git clone https://github.com/vulhub/vulhub.git
(1)Apache多后缀文件解析漏洞(CVE-2017-15715)
该漏洞和Apache版本和php版本无关,属于用户配置不当造成的解析漏洞。
- 描述:
Apache解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。比如test.php.owf.rar,这两种后缀是apache不可识别解析,apache就会把其解析成php。
运维人员如果进行了如下配置也会导致漏洞:
(1)如果在Apache的conf里有这样一行配置 AddHandler php5-script .php,这时只要文件名里包含.php 即使文件名是 test2.php.jpg 也会以 php 来执行。
(2)如果在 Apache 的 conf 里有这样一行配置 AddType application/x-httpd-php .jpg,这样凡是. jpg格式的都会以 php 方式执行。(.jpg也可以换成别的,比如换成.htm那就表明凡是.htm的都以php执行。
AddHandler 指令的作用是: 在文件扩展名与特定的处理器之间建立映射
AddHandler php5-script .php ————————> 指定扩展名为 .php 的文件应被 php5-srcipt 处理器来处理。
AddType 指令的作用是:在给定的文件扩展名与特定的内容类型之间建立映射关系。
-
总结:Apache文件解析漏洞就是由于用户在配置服务器时,配置不当导致本来非php文件也会被认为php文件处理。
-
修复方案:
方案一:在apache配置文件中加入:禁止.php.这样的文件执行。
<Files ~ “.(php.|php3.)”> Order Allow,Deny Deny from all </Files>方案二:用伪静态能解决这个问题,重写类似.php.*这类文件,打开apache的httpd.conf找到LoadModule rewrite_module modules/mod_rewrite.so
把#号去掉,重启apache,在网站根目录下建立.htaccess文件,代码如下:<IfModule mod_rewrite.c> RewriteEngine On RewriteRule .(php.|php3.) /index.php RewriteRule .(pHp.|pHp3.) /index.php RewriteRule .(phP.|phP3.) /index.php RewriteRule .(Php.|Php3.) /index.php RewriteRule .(PHp.|PHp3.) /index.php RewriteRule .(PhP.|PhP3.) /index.php RewriteRule .(pHP.|pHP3.) /index.php RewriteRule .(PHP.|PHP3.) /index.php </IfModule> -
漏洞复现:
1、打开Linux操作系统(比如Kali、Ubuntu等都可以,以下是用Kali实验的),利用vulhub进行漏洞复现,进入vulhub中该漏洞的目录下:
cd vulhub/httpd/apache_parsing_vulnerability

2、创建docker容器启动该漏洞环境
sudo docker-compose up -d

3、查看本地ip,浏览器访问本地ip地址
ifconfig -a


4、利用vim编辑器编写一个php脚本,将文件命名为11.php.jpg,进行上传,发现上传成功。
vim 11.php.jpg //新建11.php.jpg并用vim编辑器打开
i //进入vim编辑器的编辑模式
<? php phpinfo(); ?> //在该模式下写php脚本
ESC //回到命令模式
:wq //保存并退出



5、根据提示路径,访问上传的文件,发现php文件解析成功。其核心原因就是后缀jpg在白名单中,所以可以成功上传,但是由于Apache配置不当而产生的多后缀解析漏洞,导致只要后缀里有.php,就都按php解析执行,因此访问时php脚本执行成功。

(2)Nginx配置文件错误导致的解析漏洞
该漏洞和Nginx版本和php版本无关,属于用户配置不当造成的解析漏洞。
- 描述:
在了解该漏洞之前,我们需要了解一个PHP的漏洞,在PHP会有一个选项,叫做cgi.fix_pathinfo,如下图所示:

这个值从字面意思理解就是:对路径进行修正,那么如何修正呢?举个例子,在php中,我们接收到了一个路径为:A.rar/B.jpg/C.php,收到这个路径后,我们的php会先从最后开始解析,也就是会先解析C.php存不存在。如果C.php不存在,则会向上一级走,判断B.jpg是否存在,如果存在的话,是按照C.php的文件格式去解析B,而不是按照B本身的.jpg去进行解析,因此如果这个开关设置为1,就会存在漏洞。
比如我们创建一个一句话木马,内容是:。由于上传文件的限制只允许我们上传图像格式,我们把木马的名字设定为muma.jpg,上传成功后我们通过网页去访问这个文件//muma.jpg。由于文件格式为图像格式,我们就按照图片的处理方式去处理,那么毫无疑问的是我们得不到任何东西。但是结合我们刚刚讲解的漏洞试一试,我们可以自己构建url:http://wwwhttps://link.zhihu.com/?target=http%3A//www.com/*/mamu.jpg/sdad.php,因为sdad.php不存在,我们php会继续向前解析,发现mamu.jpg存在这个路径,我们会将muma.jpg当作.php去执行。然后就能成功利用php解析。
这里有一个问题:按照这个说法,这应该是一个php漏洞,为什么是Nginx的漏洞呢?
因为在Nginx中有一个特性,当Nginx拿到了url(文件路径包含在url里面)会解析里面的文件路径。比如路径是/test.jpg/test.php,当发现文件格式为.php,会直接转交给php去处理。若php收到之后发现/test.jpg/test.php不存在,就会把test.php删掉去查看test.jpg存不存在。如果test.jpg存在的话会把test.jpg当作test.php去解析,从而就完成了漏洞的利用。而Apache不一样,Apache会先验证路径存不存在后再交给php处理,因为先验证了存不存在的问题就没有解析漏洞了。而在Nginx中,只要看到是.php结尾,不管存不存在都会直接交给php处理(IIS也有这样的问题)。
-
修复方案:
方案一:将php.ini文件中的cgi.fix_pathinfo的值设置为0,这样php再解析1.php/1.jpg这样的目录时,只要1.jpg不存在就会显示404页面。
方案二:php-fpm.conf中的security.limit_extensions后面的值设置为.php。意思是你只有后缀是.php,我才会承认你是一个php文件,按照php执行,如果你是.jpg,硬说自己是php,我无法按PHP执行。
-
漏洞复现:
1、进入靶场目录:vulhub/nginx/nginx_parsing_vulnerability
cd vulhub/nginx/nginx_parsing_vulnerability
2、开启靶场环境(如果之前开过其他靶场环境,记得要用sudo docker-compose down将其关掉,否则会出错)
关闭之前的靶场环境:
sudo docker-compose down

打开新的靶场环境:
sudo docker-compose up -d

3、制作一个图片马,进行上传,上传成功后的到路径,访问路径,在后面加上一个不存在的php文件,访问后会发现图片马会被成功解析。



(3)Nginx 文件名逻辑漏洞(CVE-2013-4547)
-
影响版本:
Nginx 0.8.411.4.3/1.5.01.5.7
-
描述:
该漏洞利用了Nginx错误的解析了URL地址,导致可以绕过服务端限制,从而解析PHP文件,造成命令执行的危害。
举个例子,比如,Nginx匹配到.PHP结尾的请求,就发送给fastcgi进行解析,常见的写法如下:
location ~ \.PHP$ { include fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.PHP; fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT /var/www/html; 正常情况下(关闭了pathinfo的情况下),只有.php后缀的文件才会被发送给fastcgi解析。而存在CVE-2013-4547的情况下,我们请求1.jpg0x20.PHP,这个URI可以匹配上正则.PHP$,可以进入这个Location块;但进入后,Nginx却错误地认为请求的文件是1.jpg[0x20](相当于截断),那么就将1.jpg当作php来解析,这样如果1.jpg是个图片马,就可以成功被解析。
-
漏洞复现:
1、打开靶场环境:
cd vulhub/nginx/CVE-2013-4547
sudo docker-compose up -d

2、上传图片马,将文件名改成611.jpg%20%00.php,然后将其进行URL解码(看成post型00截断)



3、上传成功后进行访问,但是发现路径中的%20空格会被忽略,所以抓包改为刚才修改的格式后在发送,进行访问。



4、访问成功,图片马被成功解析。

6、编辑器漏洞
有些网站里附加了某些编辑的功能,引入了第三方的编辑器,(比如下图这样的界面经常会见到),这些编辑器是可能存在漏洞的。
常见的编辑器:ewebeditor、kindenditor、fckeditor、ckeditor、ueditor等。如果有编辑器,则网上查询相关的编辑器漏洞。

二、PHP函数
| 函数名 | 用法 | 作用 |
|---|---|---|
| $_FILES | $FILES["file"] ["name"] – 被上传文件的名称 $FILES["file"] ["type"] – 被上传文件的类型 $FILES["file"] ["size"] – 被上传文件的大小 |
|
| $_POST | $_POST["name"] | 获取form表单中的值。(name指表单元素的name属性值) |
| $_GET | $_GET["name"] | |
| isset | isset($var) | 检查变量var是否声明,如果已声明,返回true;否则返回false |
| trim | trim($str) | 移除字符串str两边的空格(或者是预定义的字符) |
| strrchr | strrchr($str1,$str2) | 在str1中查找str2,找到最后一次出现位置,并且返回str1从该位置到末尾的所有字符。比如611.jpg.php,如果用这个函数,str2设为. 那就相当于是只读最后一个后缀php |
| strtolower | strtolower($str1) | 将str1转换为小写 |
| str_replace | str_replace(find,replace,string,count) | 把字符串string中的find字符串全都替换成replace字符串 |
| strrpos | strrpos(str1,str2) | 查找字符串str2在str1中最后一次出现的位置 |
| getimagesize | getimagesize(string $filename) | 确定jpg、png、gif、psd、bmp等图像文件的大小并返回图像的尺寸、类型及高度宽度 |
| exif_imagetype | exif_imagetype(string $filename) | 确定图像的类型 |
三、Upload-labs过关记录(Pass 01-Pass21)
下载地址:https://github.com/c0ny1/upload-labs
过关攻略:https://www.cnblogs.com/huajiaobuxiango/p/15968800.html
过关标准:php能成功上传并执行就算过关。
Pass-01(前端,JS类验证)
1、上传php文件,提示“该文件不允许上传”;再上传一次,发现有了“不允许再次提示”的框,一般这种情况,就说明是前端的验证,可以禁用js来实现上传。


2、查看源码可判断出该关文件上传的验证是前端验证,采用了白名单,凡是后缀为jpg、png、gif的文件才能上传成功。

3、方法一(首选):直接禁用js代码
禁用js,发现可以上传成功。


方法二:
把想上传的webshell后缀改成jpg,从而通过前端的验证,然后进行抓包改包,把后缀改回php,再发送。



方法三:查看源码发现是Js代码进行了前端验证,所以把网站源码复制下来,新建一个Html,放入代码,然后将js代码删除。

但是这个新的代码只有当前页面的信息,不像源码里是有关联的头文件的,那些关联的头文件就包含着应该把文件上传到哪里,因此我们需要知道把文件上传的地点,加到我们的代码中,才能正确地将webshell上传成功。

上传一个图片,通过网络监控得到上传的地址,表单上传中action元素是表明图片交给谁的,因此我们将其加入其中。

修改后将php上传,即可成功。
Pass-02(白名单,MIME类型)
1、查看源码获知这里是通过MIME信息进行验证的,所以可以抓包改包,修改MIME类型。

MIME改成如下信息后,webshell上传成功。

Pass-03(黑名单,特殊解析后缀)
1、查看源码获知这里通过黑名单来进行文件上传的验证,即:凡是后缀为.asp、.aspx、.php、.jsp的都不允许上传。

2、可以把后缀改成php5、phtml、phps、pht等进行绕过。改完上传之后访问发现是空白页,原因是Apache的配置文件中默认是无法解析php5代码的,因为解析php5的那行代码被注释掉了,所以应该找到Apache的httpd.conf配置文件,把代码取消注释,这样才能使页面正常显示。

找到Apache的httpd.conf配置文件,修改配置代码:


把这行取消注释,并且加个.php5,使其能够解析php5,更改后页面显示正常。


Pass-04(黑名单 , .htaccess解析文件)
1、黑名单中没有.htaccess文件的限制,所以我们可以上传.htaccess文件,对解析规则进行重写,然后再上传指定的文件名,这样就可以按照指定的解析方式将其变为php。
<FilesMatch "文件名">
SetHandler application/x-httpd-php
</FilesMatch>

2、将.htaccess文件上传

3、上传phpinfo.jpg,成功将其按照php进行解析。

Pass-05(黑名单 ,一次过滤绕过)
1、这关查看源码发现,对于点、空格、去空、转小写等过滤只做了一次,所以我们可以上传后缀为.php. .


2、根据后台代码,可以分析,当上传了这样一个后缀后,代码先去空,然后删除文件末尾的点,我们后缀的最后一个点就被去掉了;然后收尾去空时我们的空格又被去掉了,此时还剩.php. ,将会被在黑名单中查询是否匹配,由于我们的后缀后面还有个. 所以不会查出匹配,那么就顺利地存活了下来,成功上传!

Pass-06(黑名单 ,大小写绕过)
1、查看源码,发现没有利用strtolower函数进行大小写绕过,所以上传一个php后缀大小混写的即可。


Pass-07(黑名单 ,空格绕过)
1、查看源码发现没有进行去空的trim函数,即:对文件名没有进行去空处理。

2、上传文件名里加空格的文件,即:phpinfo.php ,但是发现没有办法把文件重命名为phpinfo.php ,因为Windows系统对于文件的重命名会自动把空格给去掉,所以我们需要进行抓包,然后在抓到的数据包中把文件名加上空格。


3、改包发送后,文件上传成功。(这关上传成功后,文件会被重命名)

Pass-08(黑名单 ,点绕过)
1、查看源码发现没有进行去点的deldot函数,即:对文件名没有进行去点处理。
2、按照上一关的方法,把空格换成点即可通关。



Pass-09(黑名单 ,::$DATA绕过)
1、查看源码发现没有::$DATA的绕过,因此上传文件名为phpinfo.php::$DATA的文件,即可绕过。



Pass-10(黑名单,与Pass-5重复 )
Pass-11(黑名单 ,双写绕过)
1、查看源码发现,对于黑名单中的后缀,利用str_irelpace函数将所有黑名单里的后缀都去掉了,但是只去掉了一次,所以可以进行双写绕过。

2、上传文件名为phpinfo.pphphp ,这样在从头扫描的时候,先扫描到了phpinfo中的php,将其删除,继续往下扫,到后缀区域,扫描到第一个p,发现下一个字符并不是h,所以留下第一个p,第二三四个字符恰好是php,因此进行删除,函数执行结束,而由于只执行了一次,所以留下了一个php的后缀。


Pass-12(白名单,%00截断GET型)
1、根据源代码可以看出,可以通过抓包更改GET型参数save_path,利用%00截断实现目的。

2、首先需要将phpstudy版本改到5.3.4以下,而且需要关闭魔术引号开关。

3、抓包改包
上传一个jpg文件,然后修改路径参数,将上传的文件保存为php,加上%00截断后即可实现。(可以看到src路径中11.php后面的682022.....jpg虽然显示了,但实际上被截断了,所以最后文件中才只会有11.php,而没有682022....jpg这个文件。

Pass-13(白名单,%00截断POST型)
该关卡与上一关一样,只不过变成了POST型,POST型的%00截断不可以直接写%00,需要对%00进行URL手动解码。

解码后,发送数据包,上传成功。(注意下图的11.php后面看起来什么都没有,但是其实是%00已经解码完成了)

Pass-14(白名单,文件头检测,图片马)
1、查看源代码发现是通过检查文件头的前两个字节来判断是否是图片格式,是无法通过手段上传php文件的,根据提示可以知道本关卡存在文件包含漏洞,所以用图片马的方式突破。那么就相当于要把木马写入图片,将图片马上传上去,然后利用文件包含漏洞执行里面的代码。

2、制作好图片马611.png,然后上传成功,得到图片路径。

3、利用文件包含漏洞,访问include.php,让文件包含函数的参数设置为图片马,让图片里的代码成功执行。

Pass-15(突破getimagesize(),图片马)
本关卡利用getimagesize()来检测文件类型,因此可以和Pass-14一样,用图片马通过。
Pass-16(突破exif_imagetype(),图片马)
本关卡利用exif_imagetype()来检测文件类型,因此可以和Pass-14一样,用图片马通过。
Pass-17(二次渲染)
1、查看源码发现使用了二次渲染。

2、上传图片,对比原图和新图的差异,找到未被更改的地方,插入木马。(具体实现需要用脚本跑)


Pass-18(条件竞争)



Pass-20(突破move_upload_file())
1、上传文件,抓包将文件名后缀改成.php/.

2、上传成功。

Pass-21(利用数组绕过)
1、查看源码发现将文件名先截取后缀,然后检查后缀是否在白名单内,如果在白名单内,则将文件拆分成数组,比如611.php就拆成x[0]=611,x[1]='.',x[2]='php',然后进行保存。

2、我们可以传入带两个后缀的,将正确的后缀放在判断后缀、检查后缀的函数中,让其绕过检查;然后在取数组元素的时候,让其取成611.php,这样就就可以绕过。
3、我们将传入的文件名,按照数组的方式进行传入,以达到我们后续的目的。

改成:


四、绕过WAF





文件包含
基础知识
一、文件包含漏洞
文件包含漏洞属于代码注入漏洞。程序开发人员为了减少重复代码的编写,引入了文件包含函数(相当于include "Bobhash"这种头文件),通过文件包含函数将文件包含起来,直接调用。那如果文件包含函数中的参数(比如Bobhash)没有经过过滤(比如参数用的是变量形式),那么我们就可以通过一定的技术手段,让其所包含的文件变成我们自己写好的木马文件,这样在代码执行时,调用头文件就相当于执行了木马,从而达到注入漏洞的目的。
二、相关函数及参数开关
1、php配置参数
| 参数开关 | 状态 | 说明 |
|---|---|---|
| allow_url_fopen | On/Off | 是否允许将URL作为文件处理(必须打开才能包含文件) |
| allow_url_include | On/Off | 是否允许include/require打开URL作为文件处理 |
2、php文件包含函数
| 函数名 | 说明 |
|---|---|
| include() | 执行到include时才包含文件,找不到被包含文件时只会产生警告,脚本将继续执行 |
| require() | 只要程序一运行就包含文件,找不到被包含的文件时会产生致命的错误,并停止脚本 |
| include_once() | 若文件中代码已被包含则不会再次包含 |
| require_once() | 同上 |
三、漏洞利用条件
1、程序用include()等文件包含函数通过动态变量的范式引入需要包含的文件。
2、用户能够控制该动态变量。
3、要保证php.ini中的allow_url_fopen和allow_url_include要为On。
四、文件包含的类型及绕过方法


文件包含分为两大类型:本地包含和远程包含,按照有无限制区分,分为:无限制和有限制两种情况。无限制是指:代码中没有为包含文件指定特定前缀或者.php、.html等扩展名;有限制是指代码中为包含文件指定了特定的前缀或者.php、.html等扩展名,则我们在攻击的时候需要想办法截断这些限制的扩展名。
1、本地文件包含(LFI,即:Local File Include;):包含的是本地的文件
代码示例:1.asp是本地的一个文件
#include file="1.asp"
(1)本地文件包含无限制:(611.php)
代码示例:
<?php
$filename=$_GET['filename'];
include($filename);
?>
- 611.php中有文件包含函数include(),从Get方法中获取到1.txt,传给变量filename,include函数中的参数即为1.txt,执行代码后得到运行结果。

- 如果想要包含的文件不在当前的目录,可以使用../返回上级(用一次就是返回一级),比如:
http://127.0.0.1/611.php?filename=../../../1.txt
(2)本地文件包含有限制:
代码示例:
<?php
$filename=$_GET['filename'];
include($filename."html");
?>
- 611.php代码中的文件包含函数加了后缀名限制,即:不管上传什么,后缀都会加个.html,这样就导致假如上传了1.txt,那么include里的参数就会变成1.txt.html,由于目录中没有1.txt.html文件,所以一定会找不到,导致出错,因此需要进行截断,把.html给截断掉。(比如用%00给html截断掉)

绕过方法:
- %00截断:
使用条件:magic_quotes_gpc=Off且php版本小于5.2.4
filename = 1.txt %00 //filname=1.txt%00.html ,.html就被截掉了
-
长度截断:不同操作系统会限制文件名的最大长度,只要让文件名变得很长,就会把扩展名顶掉。
使用条件:Windows:长度大于256
Linux:长度大于4096
示例:
filename = 1.txt/./././././././././././././././././././././././././././ //一直写,让它超过长度,从而截断(/.不影响读取,不会报错的)
2、远程文件包含(RFI,即:Remote File Include,allow_url_fopen 和allow_url_include 必须都为On):包含的是远程文件。
代码示例:1.jsp不是本地的文件,是需要远程访问到的
import url="http://thief.one/1.jsp"
(1)远程文件包含无限制:
611.php中的参数filename不再来自本地的目录文件,而是通过url找到的(这里由于没有其他的远程条件,所以选了这个url)

(2)远程文件包含有限制:与本地文件包含有限制同理。
绕过方法:
- %00截断:(注意:后两个%23和%20只能用于远程文件包含的截断,本地只能用%00)
http://127.0.0.1/611.php/?filename=http://127.0.0.1/1.txt%00
或者
http://127.0.0.1/611.php/?filename=http://127.0.0.1/1.txt%23 // %23是井号
或者
http://127.0.0.1/611.php/?filename=http://127.0.0.1/1.txt%20 // %20是空格
- 长度截断:与本地包含相同。
3、伪协议(适用于任何一种类型,包括本地、远程、有无限制)
php伪协议 - 看不尽的尘埃 - 博客园 (cnblogs.com)
伪协议就是带有URL风格的封装协议,在各种语言中(PHP、JAVA等)都有很多内置的URL风格的封装协议(可以理解为php中的具有指定功能的内置函数,只不过这些函数是URL风格的,不像我们常见的funtion()这种风格的),那就可以利用这些伪协议实现绕过,获取信息。
PHP中常见伪协议:

文件下载
一、基础知识
1、文件下载漏洞
诸多网站提供了下载文件的功能,一般我们点击下载链接,变回向后台发送一个下载请求,该请求会包含一个需要下载的文件名称,后台在收到请求后会开始执行下载,将该文件名对应的文件反馈给浏览器,但是从获取文件到下载文件的过程中可能并没有过滤,比如这样的网站下载地址:https://www.test.com/upload/xiazai.php?file=/wenjian/123.doc,文件名是作为一个参数传入的,那么我们就可以把这个参数值赋成我们想要的一些配置文件,进行下载,从而获取到相应的配置信息,就产生了文件下载漏洞。
2、靶场演示(pikachu)
1、观察靶场,点击球员名字即可下载头像图片。

2、随便选择一个球员名字,右键复制链接,在新窗口打开,检查链接内容。观察链接发现用了filename这个参数来接受文件名字,那么我们能否尝试改变文件名字,让其下载其他重要的源码文件呢,比如链接中的execdownload.php文件。
http://127.0.0.1/pikachu/vul/unsafedownload/execdownload.php?filename=ai.png

3、如果直接把filename的传递值改成execdownload.php,我们会发现报错,那是因为execdownload.php不再相应的目录中,那我们可以寻找其所在的路径。随意点击一个图片,查看链接,发现图片存储在一个叫download的目录中。

http://127.0.0.1/pikachu/vul/unsafedownload/download/ns.png
4、根据URL比较发现:download的上级是unsafedownload,execdownload.php的上一级也是unsafedownload,那么就说明download和execdownload.php是在同一级的,而无法下载execdownload.php就说明当前下载的路径所在是download这个文件夹中,因此我们可以加一个返回上级目录的符号(../),来退出当前目录,从而下载目标文件。
http://127.0.0.1/pikachu/vul/unsafedownload/execdownload.php?filename=../execdownload.php
5、下载成功。

浙公网安备 33010602011771号