美文网首页ctfCTF练习
CTF中常见的PHP知识点

CTF中常见的PHP知识点

作者: ch3ckr | 来源:发表于2018-01-12 16:41 被阅读1520次

    PHP是一门比较松散的语言,既方便,又容易出现一些问题。本文主要概括一些常见的PHP弱类型,正则表达式函数跟变量覆盖的内容,在CTF这方面也经常出现在代码审计相关的题目中。

    一、弱类型

    0x01 "=="与"==="的区别
    在使用"=="时会自动转换类型,而"==="则是校验类型,而非转换。
    
    1 == '1';  //true
    1 == '1abcdef';  //true
    0 == 'abcdefg';  //true
    0 === 'abcdefg';  //false
    
    0x02 Hash比较
    使用"=="时,如果字符串满足0e\d+,解析为科学计数法,否则视为正常字符串。
    
    "0e132456789" == "0e7124511451155"  //true
    "0e123456abc" == "0e1dddada"  //false
    "0e1abc"=="0"     //true
    md5('240610708') == md5('QNKCDZO')  //true
    
    0e开头的md5:
    QNKCDZO
    0e830400451993494058024219903391
    
    s878926199a
    0e545993274517709034328855841020
      
    s155964671a
    0e342768416822451524974117254469
      
    s214587387a
    0e848240448830537924465865611904
      
    s214587387a
    0e848240448830537924465865611904
      
    s878926199a
    0e545993274517709034328855841020
      
    s1091221200a
    0e940624217856561557816327384675
      
    s1885207154a
    0e509367213418206700842008763514
    
    0x03 传入数组返回null系列
    md5()是不能处理数组的,md5(数组)会返回null,同理的有sha1(),strlen(),eregx()。
    
    $array1[] = array(
        "foo" => "bar",
        "bar" => "foo",
    );
    $array2 = array("foo", "bar", "hello", "world");
    var_dump(md5($array1)==var_dump($array2));  //true
    
    0x04 十六进制转换
    使用"=="时,PHP会将十六进制转换为十进制然后再进行比较
    
    "0x1e240"=="123456"     //true
    "0x1e240"==123456       //true
    "0x1e240"=="1e240"      //false
    
    0x05 intval()函数
    intval()函数会将从字符串的开始进行转换直到遇到一个非数字的字符。
    如果出现无法转换的字符串,intval()不会报错而是返回0。
    
    if(intval($a)>1000) {
        mysql_query("select * from news where id=".$a)
    }
    这个时候$a的值有可能是1002 union…..
    
    0x6 strcmp()函数
    strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算。
    在PHP5.3版本之后使用这个函数比较array跟sring会返回0。
    
    $array=[1,2,3];
    var_dump(strcmp($array,'123')); //null,在某种意义上null也就是相当于false。
    
    0x07 switch()函数
    如果switch是数字类型的case的判断时,switch会将其中的参数转换为int类型。
    
    $i ="2abc";
    switch ($i) {
    case 0:
    case 1:
    case 2:
        echo "i is less than 3 but not negative";
        break;
    case 3:
        echo "i is 3";
    }
    
    0x08 in_array(),array_search()函数
    bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ),
    如果strict参数没有提供,那么in_array就会使用松散比较来判断$needle是否在$haystack中。
    当strince的值为true时,in_array()会比较needls的类型和haystack中的类型是否相同。
    
    $array=[0,1,2,'3'];
    var_dump(in_array('abc', $array));  //true
    var_dump(in_array('1bc', $array));  //true
    
    0x09 is_numeric()函数
    当有两个is_numeric判断并用and连接时,and后面的is_numeric可以绕过.
    "="优先级比and高。
    <?php
    $a=$_GET['a'];
    $b=$_GET['b'];
    $c=is_numeric($a) and is_numeric($b);
    var_dump(is_numeric($a));
    var_dump(is_numeric($b)); 
    var_dump($c);  //$b可以不是数字,同样返回true
    $test=true and false;
    var_dump($test);     //返回true 
    ?>
    
    16进制也可以绕过is_numeric()检验,可以用来绕过sql注入里的过滤.
    <?php
    $a = is_numeric ( $_GET ['a'] ) ? $_GET ['a'] : 0;
    $con = mysql_connect ( 'localhost', 'root', 'root' );
    mysql_select_db ( 'test' );
    $sql = 'insert into a values(' . $a . ',"a")';
    mysql_query ( $sql );
    ?>
    test.php?a=0x31206f7220313d31时,数据库中成功插入值
    
    0x10 json绕过
    输入一个json类型的字符串,json_decode函数解密成一个数组,
    判断数组中key的值是否等于 $key的值,但是$key的值我们不知道,
    但是可以利用0=="admin"这种形式绕过
    最终payload message={"key":0}
    
    <?php
    if (isset($_POST['message'])) {
        $message = json_decode($_POST['message']);
        $key ="*********";
        if ($message->key == $key) {
            echo "flag";
        } 
        else {
            echo "fail";
        }
     }
     else{
         echo "~~~~";
     }
    ?>
    

    二、正则表达式

    0x01 eregi()函数
    1. 字符串对比解析,当ereg读取字符串string时,%00后面的字符串不会不会被解析。
    #这里 a=abcd%001234,可以绕过
    <?php
        if (ereg ("^[a-zA-Z]+$", $_GET['a']) === FALSE)  {
            echo 'You password must be alphabet';
        }
    ?>
    
    2. 如果传入数组,ereg返回NULL
    
    0x02 preg_match函数
    如果在进行正则表达式匹配的时候,没有限制字符串的开始和结束(^ 和 $),则可以存在绕过的问题.
    
    $ip = '1.1.1.1 abcd'; // 可以绕过
    if(!preg_match("/(\d+)\.(\d+)\.(\d+)\.(\d+)/",$ip)) {
      die('error');
    } else {
      // echo('key...')
    }
    

    0x03 preg_replace函数

    preg_replace() 的第一个参数如果存在 /e 模式修饰符,则允许代码执行。
    如果没有 /e 修饰符,可以尝试 %00 截断。
    
    <?php
        preg_replace("/test/e",$_GET["nac"],"jutst test");
    ?>
    
    ?nac=phpinfo() #可以被执行
    

    三、变量覆盖

    0x01 extract()函数
    extract() 函数从数组中把变量导入到当前的符号表中。
    对于数组中的每个元素,键名用于变量名,键值用于变量值。
    
    <?php  
        $auth = '0';  
        // 这里可以覆盖$auth的变量值
        extract($_GET); 
        if($auth == 1){  
            echo "private!";  
        } else{  
            echo "public!";  
        }  
    ?>
    
    0x02 parse_str()函数
    parse_str() 的作用是解析字符串,并注册成变量.
    与 parse_str() 类似的函数还有 mb_parse_str(),parse_str() 将字符串解析成多个变量,
    如果参数 str 是 URL 传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域.
    
    //var.php?var=new  
    $var='init';  
    parse_str($_SERVER['QUERY_STRING']);
    // $var 会变成 new
    echo $var;
    
    
    0x03 $$的使用
    如果把变量本身的 key 也当变量,也就是使用了 $$,就可能存在问题。
    
    // http://127.0.0.1/index.php?_CONFIG=123
    $_CONFIG['extraSecure'] = true;
     
    foreach(array('_GET','_POST') as $method) {
        foreach($$method as $key=>$value) {
          // $key == _CONFIG
          // $$key == $_CONFIG
          // 这个函数会把 $_CONFIG 变量销毁
          unset($$key);
        }
    }
    if ($_CONFIG['extraSecure'] == false) {
        echo 'flag {****}';
    }
    
    0x04 unset()
    unset($bar); 用来销毁指定的变量,如果变量 $bar 包含在请求参数中,
    可能出现销毁一些变量而实现程序逻辑绕过。
    

    相关文章

      网友评论

        本文标题:CTF中常见的PHP知识点

        本文链接:https://www.haomeiwen.com/subject/ycybnxtx.html