文章目录
- Pass-01 前端检测(JS检测)
- 1.1 原理分析
- 1.2 实验
- Pass-02 后端检测(MIME检测)
- 2.1 原理分析
- 2.2 实验
- Pass-03 后端检测(黑名单绕过,特殊后缀名)
- 3.1 原理分析
- 3.2 实验
- Pass-04 后端检测(黑名单绕过,.htaccess)
- 4.1 原理分析
- 4.2 实验
- Pass-05 后端检测(黑名单绕过,大小写绕过)
- 5.1 原理分析
- 5.2 实验
- Pass-06 后端检测(黑名单绕过,空格绕过)
- 6.1 原理分析
- 6.2 实验
- Pass-07 后端检测(黑名单绕过,点绕过)
- 7.1 原理分析
- 7.2 实验
- Pass-08 后端检测(黑名单绕过,::$DATA绕过)
- 8.1 原理分析
- 8.2 实验
- Pass-09 后端检测(黑名单绕过,. .绕过)
- 9.1 原理分析
- 9.2 实验
- Pass-10 后端检测(黑名单绕过,双写绕过)
- 10.1 原理分析
- 10.2 实验
- Pass-11 后端检测(白名单绕过,%00截断绕过—get)
- 11.1 原理分析
- 11.2 实验
- Pass-12 后端检测(白名单绕过,%00截断绕过—post)
- Pass-13 后端检测(白名单绕过,文件内容检测—前两个字节)
- 13.1 原理分析
- 13.2 实验
- Pass-14 后端检测(白名单绕过,文件内容检测—getimagesize)
- 14.1 原理分析
- 14.2 实验
- Pass-15 后端检测(白名单绕过,文件内容检测—exif_imagetype)
- 15.1 原理分析
- 15.2 实验
- Pass-16 后端检测(白名单绕过,二次渲染绕过)
- 16.1 原理分析
- 16.2 实验
- Pass-17 后端检测(白名单绕过,条件竞争(一)绕过)
- 17.1 原理分析
- 17.2 实验
- Pass-18 后端检测(白名单绕过,条件竞争(二)绕过)
- 18.1 原理分析
- 18.2 实验
- Pass-19 后端检测
- 19.1 原理分析
- Pass-20 后端检测(白名单绕过,数组绕过)
- 20.1 原理分析
- 20.2 实验
- 总结
环境:在kali中使用docker进行搭建。
Pass-01 前端检测(JS检测)
1.1 原理分析
客户端(Client):或称为用户端(前端),与服务器相对应。由于客户端对于文件上传漏洞的防御是通过JS代码实现的,所以客户端检测与绕过也称为JS检测与绕过。
由于后端PHP代码没有对文件做任何检测,所以只要绕过前端JS的校验就可以上传WebShell。绕过方法:
- 删除浏览器事件;
- 禁用JS;
- 利用BurpSuite抓包修改文件后缀名。
1.2 实验
查看源码:
从form表单可以看出他在使用了onsubmit
这个函数,触发了鼠标的单击事件,在表单提交后马上调用了checkFile()
这个函数对上传的文件进行检查。checkfile()
返回值为假,文件将不会上传。
该函数只允许上传的文件类型为.jpg、.png、.gif
。
综上分析,这种检测方式属于前端检测(JS检测)。
这里使用上述三种方法进行JS绕过:
(1)禁用JS
(2)利用burp抓包修改文件后缀
(3)删除浏览器事件
先将源代码全部保存到1.html
文件中,然后删除onsubmit事件
,以及JS函数。使用action
事件,告诉浏览器将表单提交给谁。
使用火狐打开firefox 1.html
,然后上传文件即可。
Pass-02 后端检测(MIME检测)
2.1 原理分析
MIME检测原理:
判断$_FILES["upload_file"]["type"]
是不是图片格式(image/gif、image/png、image/jpeg),不是则不允许上传。在HTTP 协议中,使用Content-Type 字段表示文件的MIME 类型。 $_FILES["file"]["type"]
的值是从请求数据包中Content-Type中获取。
常见的MIME 类型如下:
文件拓展名 | Mime-Type |
---|---|
.js | application/x-javascript |
.html | test/html |
.jpg | image/jpeg |
.png | image/png |
application/pdf |
绕过方法:修改数据包中的content-type值就行。
2.2 实验
查看源码,发现检测MIME格式是否为
image/gif、image/jpeg、image/png
。抓包修改MIME值即可。
Pass-03 后端检测(黑名单绕过,特殊后缀名)
3.1 原理分析
(1)黑名单绕过
- 名单列表绕过
有些中间件允许解析其他文件后缀名,如asa、cer之类的或在httpd.conf配置文件中,配置如下代码,则能解析php、php3、phtml文件,所以上传一个后缀名为php3、phptml的文件即可。
默认状态下
.php3
,.php4
,.php5
,.phtml
都是会被解析为php
- Windows特性
一些特殊的文件名命名方式在windows下是不被允许的,利用BurpSuite抓包修改后缀名,绕过验证后上传文件,windows会自动去掉后面添加的,但要注意Unix/Linux系统没有这个特性。比如:
- 末尾的点(
.
) 如1.php.
- 空格(
1.php
- ::$DATA,如
1.php::$DATA
(2)白名单绕过
白名单绕过需要配合文件包含漏洞或者解析漏洞。
(3).htaccess文件攻击
.htaccess文件是Apache服务器中的分布式配置文件(IIS中不存在该文件),该配置文件会覆盖Apache服务器的全局配置,作用于当前目录及其子目录。
- 如果一个web应用允许上传.htaccess文件,那就意味着攻击者可以更改Apche的配置。
在httpd.conf配置文件中,AllowOverride参数就是指明Apache服务器是否去找**.htacess**文件作为配置文件,如果设置为none,那么服务器将忽略.htacess文件;如果设置为All,那么所有在.htaccess文件里有的指令都将被重写,即允许.htaccess文件覆盖掉Apache 的配置。
(4)Apahce解析机制
Apche解析机制:从右往左开始解析文件后缀,若后缀名不可识别,则继续判断直到遇到可解析的后缀为止。
3.2 实验
可见,属于黑名单验证。
查看源代码,后缀加
.
、(空格)
、::$DATA
、大小写均被拦截。
通过返回的数据包,可知网站中间件为apache,故用特殊可解析后缀进行绕过。
注意:
- 需要配置apache的后缀解析规则,才能使用特殊后缀名绕过黑名单检测;
- 本靶场搭建在linux上,所以修改
/etc/apache2/mods-available/mime.conf
文件(windows下为httpd.conf文件),增加语句AddType application/x-httpd-php .phptml
;- 如果用不了vim进行编辑,可以是使用
echo "AddType application/x-httpd-php .phptml" | cat >> mime.conf
。
Pass-04 后端检测(黑名单绕过,.htaccess)
4.1 原理分析
.htaccess文件是Apache服务器中的分布式配置文件(IIS中不存在该文件),该配置文件会覆盖Apache服务器的全局配置,作用于当前目录及其子目录。
- 如果一个web应用允许上传.htaccess文件,那就意味着攻击者可以更改Apche的配置。
在httpd.conf配置文件中,AllowOverride参数就是指明Apache服务器是否去找.htaccess文件作为配置文件,如果设置为none,那么服务器将忽略.htacess文件;如果设置为All,那么所有在.htaccess文件里有的指令都将被重写,即允许.htaccess文件覆盖掉Apache 的配置。
4.2 实验
黑名单中并没有限制.htaccess
文件的上传,故上传一个.htaccess
文件,文件内容如下:
<FileMatch "shell.png">
SetHandler application/x-httpd-php
大致意思就是把shell.png图片文件当作php代码进行解析。
先上传.htaccess
文件,再上传shell.png文件,即可。
注意:
- 需要修改
/etc/apache2/apache2.conf
配置文件(windows下为httpd.conf文件),其中的AllowOverride
参数设置为All
;- 使用cat命令进行写入。
Pass-05 后端检测(黑名单绕过,大小写绕过)
5.1 原理分析
原理:windows对大小写不敏感,linux对大小写敏感。
5.2 实验
可以看出后端没有对大小写进行过滤。
抓包,修改文件后缀。
本靶场搭建再linux环境下,故phP文件无法被解析为php文件。
Pass-06 后端检测(黑名单绕过,空格绕过)
6.1 原理分析
一些特殊的文件名命名方式在windows下是不被允许的,利用BurpSuite抓包修改后缀名,绕过验证后上传文件,windows会自动去掉后面添加的,但要注意Unix/Linux系统没有这个特性。比如:
- 末尾的点(
.
) 如1.php.
- 空格(
1.php
- ::$DATA,如
1.php::$DATA
6.2 实验
可以看出后端没有对空格进行过滤。
Pass-07 后端检测(黑名单绕过,点绕过)
7.1 原理分析
一些特殊的文件名命名方式在windows下是不被允许的,利用BurpSuite抓包修改后缀名,绕过验证后上传文件,windows会自动去掉后面添加的,但要注意Unix/Linux系统没有这个特性。比如:
- 末尾的点(
.
) 如1.php.
- 空格(
1.php
- ::$DATA,如
1.php::$DATA
7.2 实验
可以看出后端没有对点进行过滤。
Pass-08 后端检测(黑名单绕过,::$DATA绕过)
8.1 原理分析
一些特殊的文件名命名方式在windows下是不被允许的,利用BurpSuite抓包修改后缀名,绕过验证后上传文件,windows会自动去掉后面添加的,但要注意Unix/Linux系统没有这个特性。比如:
- 末尾的点(
.
) 如1.php.
- 空格(
1.php
- ::$DATA,如
1.php::$DATA
8.2 实验
可以看出后端没有对::$DATA
进行过滤。
注意,在使用蚁剑进行连接时,不要加上
::$DATA
。
Pass-09 后端检测(黑名单绕过,. .绕过)
9.1 原理分析
一些特殊的文件名命名方式在windows下是不被允许的,利用BurpSuite抓包修改后缀名,绕过验证后上传文件,windows会自动去掉后面添加的,但要注意Unix/Linux系统没有这个特性。比如:
- 末尾的点(
.
) 如1.php.
- 空格(
1.php
- ::$DATA,如
1.php::$DATA
9.2 实验
deldot()
函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来。假如文件名为shell.php. .
,deldot函数会删除最后一个点,然后将.php.
转换为小写,再去除特殊字符串::$DATA
,最后去掉空格,得到.php.
绕过检测。
Pass-10 后端检测(黑名单绕过,双写绕过)
10.1 原理分析
str_ireplace()
函数寻找文件名中存在的黑名单字符串,将它替换成空;并且不区分大小写。
10.2 实验
可见,此处使用str_ireplace()
函数删除黑名单后缀。故,使用双写绕过。
上述关卡均为黑名单绕过,而且只验证一次。接下来的关卡将是白名单绕过。
白名单绕过需要配合文件包含漏洞或者解析漏洞。
Pass-11 后端检测(白名单绕过,%00截断绕过—get)
11.1 原理分析
截断漏洞出现的核心就是chr(0),这个字符不为空 (Null),也不是空字符 (" "),更不是空格。当程序在输出含有 chr(0)变量时,chr(0)后面的数据会被停止,换句话说,就是误把它当成结束符,后面的数据直接忽略,这就导致了漏洞产生。由于00代表结束符,PHP会把00后面的所有字符删除。
截断条件
PHP版本小于5.3.4、magic_quotes_gpc 为OFF状态。
- linux在
/usr/local/etc/php/php.ini
中查看magic_quotes_gpc参数状态。- 本靶场php版本高于5.3.4,故只讲原理。
11.2 实验
str_ireplace()
函数遇到%00
会截断。如下图,保存路径12.php%00
,不管你文件名,最终保存在服务器路径上的文件(你上传的文件)的文件名都为12.php
。
Pass-12 后端检测(白名单绕过,%00截断绕过—post)
原理同上,唯一的不同就是路径用post进行传递。
Pass-13 后端检测(白名单绕过,文件内容检测—前两个字节)
13.1 原理分析
根据上传文件内容的前两个字节,来判断上传文件类型。
13.2 实验
制作图片马进行绕过。
成功上传图片马后,需要通过文件包含漏洞才能成功获取shell。
Pass-14 后端检测(白名单绕过,文件内容检测—getimagesize)
14.1 原理分析
利用getimagesize()
函数获取图片的宽高等信息,如果上传的不是图片,那么则获取不到信息。服务端主要检测文件幻数:
类型 | 文件幻数 |
---|---|
JPG | FF D8 FF E0 00 10 4A 46 49 46 |
GIF | 47 49 46 38 39 61 (GIF89a) |
PNG | 89 50 4E 47 |
绕过方式
在脚本文件开头补充图片对应的头部值,或在图片后写入脚本代码
14.2 实验
可知,本关卡用
getimagesize()
函数检测文件函数。使用图片马绕过+文件包含漏洞。
Pass-15 后端检测(白名单绕过,文件内容检测—exif_imagetype)
15.1 原理分析
exif_imagetype()
读取一个图像的第一个字节并检查其后缀名。只是换了一个函数,故绕过方法与上一关一样。
15.2 实验
Pass-16 后端检测(白名单绕过,二次渲染绕过)
16.1 原理分析
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
简单来说,就是后台会根据你上传的图片,重建一个相同的图片。
绕过:
- 对比源文件和渲染后的文件,在没有变化的部分加入一句话木马;
- 对于做文件上传之二次渲染建议用
GIF
图片,相对于简单一点。
16.2 实验
使用burp的比较模块进行源文件和渲染后文件的比较。
在没有变化的部分添加一句话木马。
Pass-17 后端检测(白名单绕过,条件竞争(一)绕过)
17.1 原理分析
一些网站文件检测逻辑是先允许上传任意文件,然后检查文件内容是否包含可执行脚本,如果包含则删除。
绕过方式
利用成功上传到删除文件的时间差,上传一个.php文件,在未删除之前立即访问,则会自动生成一个新php文件,新文件不会被删除。
简单来说就是,在删除文件之前,访问文件,这样就会提示文件在另一个程序中无法删除。
17.2 实验
$is_upload = false;
$msg = null;if(isset($_POST['submit'])){$ext_arr = array('jpg','png','gif');$file_name = $_FILES['upload_file']['name'];$temp_file = $_FILES['upload_file']['tmp_name'];$file_ext = substr($file_name,strrpos($file_name,".")+1);$upload_file = UPLOAD_PATH . '/' . $file_name;if(move_uploaded_file($temp_file, $upload_file)){if(in_array($file_ext,$ext_arr)){$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;rename($upload_file, $img_path);$is_upload = true;}else{$msg = "只允许上传.jpg|.png|.gif类型文件!";unlink($upload_file);}}else{$msg = '上传出错!';}
}
从源码中可以看出,后端先把上传的文件从临时文件夹移动到指定的位置,再判断文件后缀是否属于白名单中的文件后缀,不属于,就使用
unlink
函数删除文件。
上传php文件(只有上传php文件,服务端才会运行其中的php脚本),payload如下:
<?php fputs(fopen('shell00.php','w'),'<?php phpinfo()?>');?>
注意,写入的文件夹名不能与上传的文件夹名一致,不然会被删掉。
无限发送空的payload
python访问脚本:
import requests
url = "http://192.168.92.1:32768/upload/shell00.php"
while True:html = requests.get(url)if html.status_code == 200:print("OK")break
在bp攻击的同时,运行python脚本访问上传的文件。
Pass-18 后端检测(白名单绕过,条件竞争(二)绕过)
18.1 原理分析
原理同上
18.2 实验
//index.php
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))
{require_once("./myupload.php");$imgFileName =time();$u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);$status_code = $u->upload(UPLOAD_PATH);switch ($status_code) {case 1:$is_upload = true;$img_path = $u->cls_upload_dir . $u->cls_file_rename_to;break;case 2:$msg = '文件已经被上传,但没有重命名。';break; case -1:$msg = '这个文件不能上传到服务器的临时文件存储目录。';break; case -2:$msg = '上传失败,上传目录不可写。';break; case -3:$msg = '上传失败,无法上传该类型文件。';break; case -4:$msg = '上传失败,上传的文件过大。';break; case -5:$msg = '上传失败,服务器已经存在相同名称文件。';break; case -6:$msg = '文件无法上传,文件不能复制到目标目录。';break; default:$msg = '未知错误!';break;}
}//myupload.php
class MyUpload{
......
......
...... var $cls_arr_ext_accepted = array(".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",".html", ".xml", ".tiff", ".jpeg", ".png" );......
......
...... /** upload()**** Method to upload the file.** This is the only method to call outside the class.** @para String name of directory we upload to** @returns void**/function upload( $dir ){$ret = $this->isUploadedFile();if( $ret != 1 ){return $this->resultUpload( $ret );}$ret = $this->setDir( $dir );if( $ret != 1 ){return $this->resultUpload( $ret );}$ret = $this->checkExtension();if( $ret != 1 ){return $this->resultUpload( $ret );}$ret = $this->checkSize();if( $ret != 1 ){return $this->resultUpload( $ret ); }// if flag to check if the file exists is set to 1if( $this->cls_file_exists == 1 ){$ret = $this->checkFileExists();if( $ret != 1 ){return $this->resultUpload( $ret ); }}// if we are here, we are ready to move the file to destination$ret = $this->move();if( $ret != 1 ){return $this->resultUpload( $ret ); }// check if we need to rename the fileif( $this->cls_rename_file == 1 ){$ret = $this->renameFile();if( $ret != 1 ){return $this->resultUpload( $ret ); }}// if we are here, everything worked as planned :)return $this->resultUpload( "SUCCESS" );}
......
......
......
};
从源码来看的话,服务器先是将文件后缀跟白名单做了对比,然后检查了文件大小以及文件是否已经存在,文件上传之后又对其进行了重命名。
故,上传图片马,而且在图片马没有被重命名之前访问它,配合其他漏洞,比如文件包含,apache解析漏洞等,最终获取shell。
一句话木马,一访问图片马,就将php探针写入到shell01.php中。
<?php fputs(fopen('shell01.php','w'),'<?php phpinfo();?>');?>
bp的操作和上一关一样,bp发包的同时,python脚本访问。
需要用到文件包含漏洞,python脚本如下:
import requests
url = "http://192./include.php?file=upload/pass19.png"
while True:html = requests.get(url)if ( 'Warning' not in str(html.text)):print('ok')break
Pass-19 后端检测
19.1 原理分析
根据源码,本关卡没有对上传的文件做判断,只对用户输入的文件名做判断。黑名单用于用户输入的文件后缀名进行判断。move_uploaded_file()
会忽略掉文件末尾的 /.
Pass-20 后端检测(白名单绕过,数组绕过)
20.1 原理分析
$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{//save_name不是数组,就对文件的文件名进行切分$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 = "请选择要上传的文件!";
}
验证过程:
--> 验证上传路径是否存在
--> 验证['upload_file']的content-type是否合法
--> 判断POST参数是否为空,并定义$file变量(关键:构造数组绕过下一步的判断)
--> 判断file不是数组则使用explode('.', strtolower($file))对file进行切割,将file变为一个数组
--> 判断数组最后一个元素是否合法
--> 数组第一位和$file[count($file) - 1]进行拼接,产生保存文件名file_name
--> 上传文件
20.2 实验
reset()
函数将内部指针指向数组中的第一个元素,并输出 upload-20.php
伪造的数组有两个值,count($file)-1=2-1=1
$file[1]='' 空
save_name[0]='upload-20.php'
save_name[1]=''
save_name[2]='png'
file={'upload-20.php','','png'}
经过源码中的拼接upload-20.php.
靶场搭建在windows上,就可以访问到phpinfo页面。