文章声明
#仅是个人的学习笔记记录,不得转载和供他人学习#
#未经授权和许可 不得去在别人的网站使用!!#
#请自觉遵守网络安全法!!#
文件上传漏洞靶场upload-labs
练习笔记
PASS01 源码修改
源码:
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;
}}
解法:
下载源码
然后更改源码限制,重定向网站,完成上传,因为靶场部署在本机,等于就在服务器操作,所以可以直接更改源码绕过
此外
上方还有个form表单块
form表单有个action方法,用来规定当提交表单时向何处提交,写action提交给自己
因为是第一关 所以选择的URL也是第一关的链接
打开修改源码过后的网站,进行上传,成功上传,通过phpinfo拿到对应信息
成功!
PASS02 文件类型修改
is_upload = false;$msg = null;if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}}
可以看到第二题只限制了上传文件的类型
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
那么想要绕过
只需要在上传后,用BP将包拦下,然后修改为他要求可以通过的类型就能够绕过了
修改类型为image/jpeg、image/png、image/gif三种任意一个均能够绕过
成功
PASS03 名称限制-php1、phtml解析
$is_upload = false;$msg = null;if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$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); //收尾去空
黑名单验证这一题
解题方法:
- 和第一题一样直接源码修改,因为在本地服务器
- 如果不是本地服务器怎么办,首先要知道,Apache有个特性,能够解析.php3、phtml这种后缀类型的文件
那么就很简单了,上传前将文件后缀名改为php3,或者发包的时候用BP拦下来直接修改包里面的后缀名
成功
或者改包
PASS04 名称限制-超文本访问方法
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); //收尾去空
Web服务器根据目录应用设置的有用文件
这题需要通过上传.htaccess更改apache服务器的设置
意思就是你先上传一个更改服务器配置的文件,让他将loudong.jpg或者是其他你命名的这个文件,当成php的文件去解析,这样一来即便上传的文件是.jpg格式的,但是他实际上是php文件,.jpg只不过是为了绕过前端限制做的障眼法
(第三题也能这样做,不过他限制没那么严 所以可以直接改成php3更加方便)
PASS05 名称限制-大小写转换限制
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); //首尾去空
可以看到第五题有个转化为小写的限制没了
很简单,那就拦包,把后缀名改成大写
PASS06 名称限制-首尾去空限制
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 = $_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
首尾去空没了
那就加空格
PASS07 名称限制-删除文件末尾的点限制
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); //首尾去空
删除文件末尾的点没了
拦包,加点,加点是不影响执行php文件的
PASS08 名称限制-去除字符串限制
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); //首尾去空
去除字符串没了
拦包,加字符串::$DATA
这里需要注意的是
复制图片地址来访问是这样的
如果直接访问,是访问不了的
我们只需要将那个字符串给删除,留下.php就能够访问了
在 window 的时候如果文件名+"::$DATA"会把::$DATA 之后的数据当成文件流处理,不会检测后
缀名,且保持::$DATA 之前的文件名,他的目的就是不检查后缀名
例如:"phpinfo.php::$DATA"Windows 会自动去掉末尾的::$DATA 变成"phpinfo.php"
所以上面你访问的时候加了::$DATA就会报错,因为实际上保存进去的就是php文件
PASS09 代码不严谨
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 = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
这一行代码有问题
只是删除点 比如1.php.......这些后面的点从后往前删,一直删除到剩下1.php 然后判定为php文件不让上传
那么将其改成1.php. .(1.php点 空格 点)或者 点空
因为他只会删点 如果有个空格,他就不删了,变成剩下1.php.
PASS10 替换文件限制
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;
这题重点是这个
这个是个替换的方法
语法如下:
Str_ireplace(find,replace,string,count)
Find:必填参数,代表要查找的值
Replace:必填参数,替换查找的值的值
String:规定需要搜索的字符串
例子:
Str_ireplace(“php”,””,info.php)
这段的意思就是找Info.php这个字符串,然后将php替换为空
跟上面的一样
$file_name = str_ireplace($deny_ext,"", $file_name);
在变量$file_name也就是你上传的文件名中查找符合变量$deny_ext的,就是那一大串什么php,php5啥的,只要有就替换为空
如何绕过呢
改成这样
Info.pphphp
因为这个查找方法的逻辑是从前往后,也就是说他找pphphp找到第一个php然后就为空,结果保存下来还是php
PASS11 get请求的0x00截断
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;
主要是下面这一句
这段代码啥意思
Save_path代表保存路径
Rand(10,99)随机数取值
Date(“YmdHis”)时间戳
$file_ext文件后缀
也就是说,我们在上传文件以后,他会先将我们的文件确认保存的路径,然后进行一个重命名,格式就是随机数+时间戳+后缀名
所以如果我们上传了一个1.php上传上去以后,他通过这个方法就直接把1.php变成别的名称,别的后缀的文件了,我们就没法运用了
这个涉及了操作系统的底层漏洞 0x00截断
关于 0x00 截断
00 截断是操作系统层的漏洞,由于操作系统是 C 语言或汇编语言编写的,这两种语言
在定义字符串时,都是以\0(即 0x00)作为字符串的结尾。操作系统在识别字符串
时,当读取到\0 字符时,就认为读取到了一个字符串的结束符号。因此,我们可以通
过修改数据包,插入\0 字符的方式,达到字符串截断的目的。
save_path=../upload/
filename="loudong.jpg"
正常情况:../upload/loudong.jpg
save_path=../upload/1.php%00
filename="loudong.jpg"
拼接的路径为:../upload/1.php%00loudong.jpg :由于%00 当作结尾,故最终保存的文件
为../upload/1.php
所以这题怎么绕过呢
首先上传一个php文件
由于Save_path是一个可控的变量
我们直接在这里修改为../upload/2.php%00
这是什么意思
因为如果我们正常上传的话,我们的1.php会变成
/upload/rand(10,99)+时间戳.$file_ext这种格式的文件
但是如果加上了%00 也就是用上00截断
那么在%00之后的这些东西就会被认为结束,不再执行
所以就会变成这样
/upload/2.php%00(rand(10,99)+时间戳.$file_ext括号里这些统统都不会执行)
最终我们上传的文件将会作为2.php被保存下来,这就是00截断的用法,之所以是%00是因为本来是\0 但是在这里就需要转译 所以就是%00
做题的时候报这个
为什么
因为上传的是1.php文件 代码限制只能上传jpg png 和gif
改个后缀就行 反正传上去是会重命名的
上传结束后
和上面的字符串限制是一样的,因为你重命名了 存进去的是1.php
所以你访问这个无效
去掉后面的,只留下php
搞定
PASS12 post请求的0x00截断
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;
和上面一样的00截断
只不过上面的是Get请求,这里是post请求
区别在哪
get请求的'save_path'路径在头
Post的在请求体里
改的位置不同
这样改然后放包提示什么
为什么
因为post请求需要手动解码
将%00手动解码
PASS13 图片马-验证前两个头文件
这题的关键是这里,只读两字节
这个两字节是指什么呢
我们来看看jpg/png/gif图片的结构
用记事本打开
Png图片
GIF图片
可以看到图片前都是这样的
只检测前面这两个字符,如果只是像之前一样上传仅有phpinfo代码的图片是行不通的
需要在正常图片中加入恶意代码
可以直接用windows自带的命令将图片和恶意代码给融合
将php文件和png图片文件放在一块
打开cmd
输入copy image.png /b + info.php /a webshell.png
Copy 图片名 /b + 脚本名 /a 生成的图片名
记事本查看,已经将phpinfo加进去了
上传!
上传成功需要用文件包含漏洞才能验证
通过get请求传入file参数
成功!
PASS14 图片马
他这题的限制是
不管
直接用图片马的方式通过
上传上一题的webshell.png。将图片地址作为file参数提交Get请求
过
PASS15 图片马
一样,上传webshell.png
过
PASS16 图片马-二次渲染绕过
16题,他会针对你上传的图片做一次二次渲染
重新生成一张图片
不关你事jpg还是png还是gif
全部都会走二次渲染的逻辑
会整个检测你图片里面的情况,如果有恶意代码就会被删掉,然后换成二次渲染规则出来的图片
所以如果想要绕过
就必须先上传一次,然后再二次渲染以后,将二次渲染后的图片弄到手,再修改二次渲染的图片重新上传
生成一个Gif的带有恶意代码的图片(gif最高支持 256 种颜色。由于这种特性,重新渲染
改动不会太多)
上传以后将二次渲染的图片下载下来
通过010Editor 16位编辑器编辑 将phpinfo恶意代码对比前后上传图片 插入进去
因为他做过二次渲染 但是不可能把整个图片的内容都改了 只需要找到前后上传一致的地方插入,那么再上传 他做二次渲染也不会改到这个地方
将上传的图片和下载的图片放入作对比
找到一行相同的位置
替换2B
保存,再次上传
成功
PASS17 条件竞争
这里上传的除了白名单的文件,其他上传上去的文件都会通过unlink这个函数方法删除
但是如果我们在上传之后 将文件打开
那么他就删除不了了
因为是在打开状态,所以无法删除
用BP爆破 无限上传 在无限上传的时候不停尝试打开文件
上传,拦包,进入intruder爆破模块
在文件后面新增空格
然后选中空格add
设置
无限访问
在他删除前打开 因为BP在无限上传
成功
PASS18 解析漏洞
上传后进行移动然后重命名
然后是白名单验证
这里存在一个apache的解析漏洞——未知拓展名漏洞
主要是php.*结尾的 都会被解析成php文件
上传一个info.php.7z
然后爆破
开始访问
Localhost/upload/info.php
Localhost/uploadinfo.php
PASS19 黑名单 文件名可控
用0x00截断
他会保存这个
好,上传发包拦截 一气呵成
这里看到他保存的文件
直接截断
记得 这个是post请求,所以要手动解码
上传成功
PASS20 数组绕过
End:数组尾
Reset:数组头
PHP数组构成分析:
<?php
$fileName = array("upload-20","jpg"); //数组,两个数 一个upload-20,一个jpg
Sext=end($fileName);//定义变量ext 赋值数组尾给ext
echo $ext."</br>"; //打印变量ext 打印结果是jpg
$f = reset($fileName);//定义变量f 赋值数组头给f
echo $f;//打印变量f 打印结果是 upload-20
>
针对20题的代码 $file[count($file) - 1] 数组下标减一
改为:
//$fileName = array("upload-20","NULL","jpg");
$fileName = array()
$fileName[0]=”upload-20.php”;
$fileName[2]=”jpg”;
$ext=end($fileName);
Echo $ext."</br>";
$f = reset($fileName);
$real_name =rest($fileName).”.”.$fileName[count($fileName) -1]
这样主动赋值0下标和2下标
然后他取rest也就是头 也就是0下标
然后后面拼接一个count-1(数组总数减一,因为数组就赋值了两个) 也就是2-1=1
结果就是NULL 因为1下标没值
所以出来的变量real_name 就会等于upload-20.phpNULL也就是upload-20.php
Php文件就上传上去了
好
上传 拦截
将文件名改成php
赋值为下标0
然后新增一行 赋值下标2为jpg
放包
完成!
这里面还是有很多例子的
一个题可能也有很多的解法
通过这个练习掌握了一些针对于代码写的不够完善,可以上传恶意代码文件的方法
#重申!未经授权 不要去对别人的网站做这个东西!这是犯法!三年起步!#
#自觉遵守网络安全法#