Web学习20

知识点

1、过滤函数缺陷绕过
2、CTF考点与代码审计

详细点

==与===
md5
intval
strpos
in_array
preg_match
str_replace

案例

==与===

=赋值 ==弱类型对比 ===还会比较类型

<?php
header("Content-Type:text/html;charset=utf-8");
$flag='xiaodi ai chi xigua!';
$a=1;
if($a==$_GET['x']){
    echo $flag;
}

当x=1或x=1.0或x=+1或x=1admin时,都会正确的输出flag,所以当使用“==”时,进行对比会有缺陷,不是非要1才能相等,甚至“1a”也可以。这种判断是不具有唯一性的,会有多个字符使条件成立。

<?php
header("Content-Type:text/html;charset=utf-8");
$flag='xiaodi ai chi xigua!';
$a=1;
if($a===$_GET['y']){
    echo $flag;
}

当y=1时,正确,但是1.0或+1或1admin就不可以了,因为譬如说1admin是字符串类型,和原本的1整型是不一样的。

md5

<?php
header("Content-Type:text/html;charset=utf-8");
$flag='xiaodi ai chi xigua!';
if($_GET['name']) != $_GET['password']){
    if(MD5($_GET['name']) == MD5($_GET['password'])){
        echo $flag;
    }
     echo '?';
}

代码逻辑就是让name和password的字符不相等,但是让两者的MD5值相等,这看起来是有点矛盾的。这里用到的绕过知识就是0e绕过

分别输入两个字符,他们在md5加密后都是0e开头即可绕过

<?php
header("Content-Type:text/html;charset=utf-8");
$flag='xiaodi ai chi xigua!';
if($_GET['name']) != $_GET['password']){
    if(MD5($_GET['name']) === MD5($_GET['password'])){
        echo $flag;
    }
     echo '?';
}

如果是”===”,就要用到数组绕过,譬如说你给输入name[]=1,它接受到的结果就是null,同时输入password[]=2,它接受的结果也是null,这样就实现数组绕过

实际应用:如果在后台的账号密码验证存在==或===的缺陷,那就可以通过绕过直接登录后台了。

补充:md5绕过的文章,里面有一些常用的绕过姿势:https://blog.csdn.net/LYJ20010728/article/details/116779357?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171803858416800180687639%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171803858416800180687639&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-116779357-null-null.142

intval

相关链接https://www.runoob.com/php/php-intval-function.html

函数的具体解释

$flag='xiaodi ai chi xigua!';
$i='666';
$ii=$_GET['n'];
if(intval($ii==$i)){
    echo $flag;
}

当给ii赋值为+666时,会自动将+666转换为10进制的整数即666,与i相等

$flag='xiaodi ai chi xigua!';
$i='666';
$ii=$_GET['n'];
if(intval($ii==$i,0)){
    echo $flag;
}

譬如说加上0x就会使用16进制转化,666的16进制是0x29a,这时两者就相等了

strpos

相关链接https://www.runoob.com/php/func-string-strpos.html

查找 “php” 在字符串中第一次出现的位置:

$flag='xiaodi ai chi xigua!';
$i='666'
$ii=$_GET['h'];
if(strpos($i,$ii,"0")){
    echo $flag;
}

对于strpos()函数,我们可以利用换行进行绕过(%0a),空格%20也可以绕过

in_array

相关链接https://www.runoob.com/php/func-array-in-array.html

在数组中搜索值 “Runoob” ,并输出一些文本:

$flag='xiaodi ai chi xigua!';

$whitelist = [1,2,3];
$page=$_GET['i'];
if (in_array($page, $whitelist)) {
    echo $flag;
}

这是第三个参数,如果没有设置,就相当于是”==”缺陷,默认是不会去检测类型
再来看源码,这里就存在绕过了,如果输入?i=1e也是会输出flag的,如果第三个参数没有设置,就可以绕过

preg_match

相关链接https://www.runoob.com/php/php-preg_match.html

$flag='xiaodi ai chi xigua!';
if(isset($_GET['num'])){
    $num = $_GET['num'];
    if(preg_match("/[0-9]/",$num)){
        die("no no no!");
    }
    if(intval($num)){
        echo $flag;
    }
}

进行数组绕过,就可以让preg_match函数失效,直接进行下一个if语句的判断,达到绕过的目的

str_replace

相关链接https://www.runoob.com/php/func-string-str-replace.html

$sql=$_GET['s'];
$sql=str_replace('select',$sql);
echo $sql;

就是把select去掉的意思
简单的过滤sql语句,存在缺陷就是无法迭代,我们可以输入sselectelect进行绕过,这个函数只能过滤一次

CTFshow题目

preg_match

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

直接数组绕过,?num[]=1即可得到flag

intval-进制转换

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转换为16进制即0x117c即可

preg_match-换行绕过

show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im',$a)){
        if(preg_match('/^php/i',$a)){
            echo 'hacker';
        }
        else{
            echo $flag;
        }
}
else{
        echo 'nonononono';
}

:”^”这个符号代表着前面有没有字符都无所谓,只要有php这个字符就行。
/i 表示不区分大小写(如果表达式里面有a,那么A也是匹配对象)
/m表示可以进行换行

换行绕过,%0a表示换行,输入%0aphp即可得到flag

intval-化整绕过

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);
    }
}

输入?num=4476.1即可,intval会将4476.1转换成整数即4476,但是如果输入4476.0在第一步进行比较的时候与4476是弱相等的

intvla-化整绕过(2)

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(intval($num,0)==4476){
                echo $flag;
        }else{
                echo intval($num,0);
        }
}

同样输入?num=4476.1即可绕过,首先4476.1不等于4476,他里面也不包含有a-z的字母,同样进行整数化后等于4476

strpos

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

这里就不能用4476.1来绕过了,因为最后一步是”===”,他会严格比较大小,所以这里应该用进制转化+换行绕过,输入?num=%20010574,其中%20相当于空格也就是换行了,010574是4476的8进制。

注:还可以输入4476.0也可以成功绕过

strpos(2)

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

同样输入?num=%20010574即可绕过,因为这题他会过滤了”.”,所以4476.0是不可以使用了。

==-弱类型比较

highlight_file(__FILE__);

if(isset($_GET['u'])){
        if($_GET['u']=='flag.php'){
                die("no no no");
        }else{
                highlight_file($_GET['u']);
        }
}

既要读出flag.php同时又得通过弱类型比较,可以加上路径,输入?u=./flag.php,即可得到flag

md5

include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a'])) and isset($_POST['b'])) {
if ($_POST['a']) != $_POST['b'])
if (md5($_POST['a'])) === md5($_POST['b']))
echo $flag;
else
print 'Wrong.';
}

post输入a和b,md5数组绕过一下就行了,a[]=1&b[]=2

实例

要想绕过str_replace,可以利用它无法迭代过滤的特性-只能过滤一次

输入…..///http\…..//\config\config_db.php即可绕过,函数会先都分别将../和./删掉,然后再执行你输入的语句,就可以成功访问到数据库的内容了

in_array第三个参数没有设置,可以执行sql注入

红日安全的代码审计项目https://github.com/hongriSec/PHP-Audit-Labs

思维导图