webshell一些上传心得
我们以upload-labs为基础
一、前端拦截:
如第一关
工作方式:
直接在前端拦截
绕过方式:
因为没有限制后端,所有可以用bs 绕过前端修改格式即可
-
将需要上传的php文件改成jpg格式
-
使用burp suite 拦截上传后,使用repeater模块将jpg改回php发送即可
-
可以看到成功上传
二、只判断文件类型:
如第二关
工作方式:
只判断了文件的类型,而没有进行其他的检查方式
绕过方式:
使用bs将返回的数据包中文件格式直接改成允许的文件格式即可绕过
-
将php文件上传的同时使用bs抓包
-
使用repeater模块,将content-type中数据改为
image/png
即可
-
可以看到已成功上传
三、黑名单限制
如第5、6、7、8、9关(因为是windows的特性,所以只能在windows中使用)
工作方式:
匹配到代码带有的黑名单后会直接拦截
绕过方式:
将后缀改为一些没有被拦截到的方式进行绕过
绕过方式 | 示例 | 绕过原因 |
---|---|---|
修改大小写绕过 | 1.Php | windows不区分大小写 |
添加末尾空格绕过 | 1.php | Windows会自动删除首尾空格 |
在末尾添加 . 绕过 | 1.php. | windows会删除末尾的点 |
在末尾添加 ::$DATA 绕过 | 1.php:$DATA | Windows会将以::$DATA 结尾的文件以数据流的方式处理 |
四、删除黑名单内容
如第十关
工作方式:
将匹配到的黑名单的信息删掉
绕过方式:
双写代码实现绕过如1.pphphp
五、修改文件上传位置:
如第十一、十二关
工作方式:
用户在上传文件后,程序将在temp目录下生成一个临时文件,再将该文件转到程序指定的目录下
绕过方式:
在第十一关:文件保存路径是由第9行代码决定
# 第十一关的部分代码如下
$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类型文件!";
}
}
我们随意上传一个文件:可以看出用户可以修改save_path函数的内容,那我们将内容改为../uploads/1.php%00
然后上传文件后缀为.jpg
的php
文件,代码处得到的后缀为jpg,能够通过对文件后缀的检测,但在$img_path
变量处就会出现其值为../uploads/1.php%00+随机日期.jpg
,当执行move_uploaded_file
函数时,服务器会对路径中%00后的内容不做解析,默认迁移文件为../uploads/1.php
。
%00截断原理:
这是字符串的结束标识符(不再对后文的信息进行处理),攻击者可以利用手动添加字符串标识符的方式将后面的内容忽略,而后面的内容又可以帮助我们绕过检测。
-
将jpg格式的php文件上传的同时使用bs抓包
-
将抓到的数据包转到repeater模块同时修改
save_path
并发送 -
可以看出php文件以及上传为1.php。同时,因为1.php后面的\0将后面的jpg忽略了
注意在第十二关中使用的是post方法,需要对%00解码:
六、文件头检查(文件包含):
如第14、15、16关
工作方式:
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;
}
如这个函数片段,该检查方式是查看文件头部的两个字节的信息(前几个字节是格式信息)。如图:
绕过方式:
前提:需要有文件包含漏洞才可实现,因为使用图片马会导致拼接的php代码无法解析
因为检查的文件头部信息,上述的如改文件格式等方式肯定是不行了,就需要使用图片马了
图片马:
在图片信息的后面拼接木马信息,使得在检查时,前几个字节仍然是正常的图片信息,但后面的php不会被检查,从而绕过检测上传
- 制作图片马:
打开cmd窗口(注意工作目录)、copy 1.png/b + 1.php /a 1.png
拼接之后的数据:
-
将制作好的图片马直接上传
-
再利用文件包含漏洞即可成功
七、二次渲染:
第16关
工作方式:
用户上传图片后,程序并没有直接将该图片使用,而是用该图片生成一个新的图片,将新的图片用于内部使用
# 16关源码片段:
$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_PATH.'/'.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格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".jpg";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagejpeg($im,$img_path);
@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格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".png";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagepng($im,$img_path);
@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格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagegif($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else{
$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}
}
绕过方式:
格式 | webshell插入位置 |
---|---|
GIF: | 可以直接在渲染前后没变化的数据块插入木马即可 |
PNG: | 需要将数据写入PLTE或IDAT模块 |
JPG: | 需要插入到指定的数据块,而且可能不成功,所以需要多次尝试 |
GIF绕过:
-
上传一个普通的GIF图片;将渲染后的图片下载后进行比较