php代码审计学习总结(1)

最近打ctf比赛,web狗遇到php代码审计被虐惨了,于是在GitHub上找了php代码审计的相关资料加以学习。在这里总结下方便以后参考。
一,ereg()函数strpos() 函数用数组返回NULL绕过

<?php  
$flag = "flag";  
   
if (isset ($_GET['password'])) {  
    if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)  
        echo 'You password must be alphanumeric';  
    else if (strpos ($_GET['password'], '--') !== FALSE)  
        die('Flag: ' . $flag);  
    else  
        echo 'Invalid password';  
}  

方法一: ereg()正则函数可以用%00截断 password=1%00–

方法二: 将password构造一个arr[],传入之后,ereg是返回NULL的,=判断NULL和 FALSE,是不相等的,所以可以进入第二个判断,而strpos处理数组,也是返回NULL,注意这里的是!,NULL!==FALSE,条件成立,拿到flag password[]=

二,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]);
  }
}
?>

构造 id=1024.1212

intval函数四舍五入,取值为1024,但if语句中已成功绕过1024的限制

三,SQL注入_WITH ROLLUP绕过

    <?php
    error_reporting(0);
    if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
        echo '<form action="" method="post">'."<br/>";
        echo '<input name="uname" type="text"/>'."<br/>";
        echo '<input name="pwd" type="text"/>'."<br/>";
        echo '<input type="submit" />'."<br/>";
        echo '</form>'."<br/>";
        echo '<!--source: source.txt-->'."<br/>";
        die;
    }
    function AttackFilter($StrKey,$StrValue,$ArrReq){  
        if (is_array($StrValue)){
    //检测变量是否是数组
            $StrValue=implode($StrValue);
    //返回由数组元素组合成的字符串
        }
        if (preg_match("/".$ArrReq."/is",$StrValue)==1){   
    //匹配成功一次后就会停止匹配
            print "水可载舟,亦可赛艇!";
            exit();
        }
    }
    $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
    foreach($_POST as $key=>$value){ 
    //遍历数组
        AttackFilter($key,$value,$filter);
    }
    $con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
    if (!$con){
        die('Could not connect: ' . mysql_error());
    }
    $db="XXXXXX";
    mysql_select_db($db, $con);
    //设置活动的 MySQL 数据库
    $sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
    $query = mysql_query($sql); 
    //执行一条 MySQL 查询
    if (mysql_num_rows($query) == 1) { 
    //返回结果集中行的数目
        $key = mysql_fetch_array($query);
    //返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
        if($key['pwd'] == $_POST['pwd']) {
            print "CTF{XXXXXX}";
        }else{
            print "亦可赛艇!";
        }
    }else{
        print "一颗赛艇!";
    }
    mysql_close($con);
    ?>
    playload: <?php
    error_reporting(0);
    if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
        echo '<form action="" method="post">'."<br/>";
        echo '<input name="uname" type="text"/>'."<br/>";
        echo '<input name="pwd" type="text"/>'."<br/>";
        echo '<input type="submit" />'."<br/>";
        echo '</form>'."<br/>";
        echo '<!--source: source.txt-->'."<br/>";
        die;
    }
    function AttackFilter($StrKey,$StrValue,$ArrReq){  
        if (is_array($StrValue)){
    //检测变量是否是数组
            $StrValue=implode($StrValue);
    //返回由数组元素组合成的字符串
        }
        if (preg_match("/".$ArrReq."/is",$StrValue)==1){   
    //匹配成功一次后就会停止匹配
            print "水可载舟,亦可赛艇!";
            exit();
        }
    }
    $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
    foreach($_POST as $key=>$value){ 
    //遍历数组
        AttackFilter($key,$value,$filter);
    }
    $con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
    if (!$con){
        die('Could not connect: ' . mysql_error());
    }
    $db="XXXXXX";
    mysql_select_db($db, $con);
    //设置活动的 MySQL 数据库
    $sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
    $query = mysql_query($sql); 
    //执行一条 MySQL 查询
    if (mysql_num_rows($query) == 1) { 
    //返回结果集中行的数目
        $key = mysql_fetch_array($query);
    //返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
        if($key['pwd'] == $_POST['pwd']) {
            print "CTF{XXXXXX}";
        }else{
            print "亦可赛艇!";
        }
    }else{
        print "一颗赛艇!";
    }
    mysql_close($con);
    ?>

playload:结合limit和offset就可以写出一个payload
即:输入的用户名为:’ or 1=1 group by pwd with rollup limit 1 offset 2 #
这里解释一下此时执行的SQL:
SELECT * FROM interest where uname=’ ’ or 1=1
group by pwd with rollup (在数据库中添加一行使得pwd=NULL)
limit 1 (只查询一行)
offset 2 (从第二行开始查询)
#注释
此时密码只要为空即可查询成功
四,switch没有break 字符与0比较绕过.

<?php
error_reporting(0);
if (isset($_GET['which']))
{
    $which = $_GET['which'];
    switch ($which)
    {
    case 0:
    case 1:
    case 2:
        require_once $which.'.php';
         echo $flag;
        break;
    default:
        echo GWF_HTML::error('PHP-0817', 'Hacker NoNoNo!', false);
        break;
    }
}
?>

playload:让我们包含当前目录中的flag.php,给which为flag,这里会发现在case 0和case 1的时候,没有break,按照常规思维,应该是0比较不成功,进入比较1,然后比较2,再然后进入default,但是事实却不是这样,事实上,在 case 0的时候,字符串和0比较是相等的,进入了case 0的方法体,但是却没有break,这个时候,默认判断已经比较成功了,而如果匹配成功之后,会继续执行后面的语句,这个时候,是不会再继续进行任何判断的。也就是说,我们which传入flag的时候,case 0比较进入了方法体,但是没有break,默认已经匹配成功,往下执行不再判断,进入2的时候,执行了require_once flag.php

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

因为通过逻辑运算符让字符串和数字比较时,会自动将字符串转换为数字.而当字符串无法转换为数字时,其结果就为0了,然后再和另一个0比大小,结果自然为ture。注意:如果那个字符串是以数字开头的,如6ldb,它还是可以转为数字6的,然后和0比较就不等了(但是和6比较就相等) if( s t r = = 0 ) 判 断 和 i f ( i n t v a l ( str==0) 判断 和 if( intval( str==0)if(intval(str) == 0 ) 是等价的

可以验证:

<?php $str="s6s"; if($str==0){ echo "返回了true.";} ?>

要字符串与数字判断不转类型方法有:

方法一: $str="字符串";if($str===0){ echo "返回了true.";}

方法二: $str="字符串";if($str=="0"){ echo "返回了true.";} ,

此题构造:which=aa

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值