CTF php特性(下)

30.松散比较==

error_reporting(0); 
highlight_file(__FILE__); 
if(isset($_POST['f1']) && isset($_POST['f2'])){   
    $f1 = (String)$_POST['f1'];   
    $f2 = (String)$_POST['f2'];   
    if(preg_match('/^[a-z0-9]+$/', $f1)){     
        if(preg_match('/^[a-z0-9]+$/', $f2)){       
            $code = eval("return $f1($f2());");    
            if(intval($code) == 'ctfshow'){  
                echo file_get_contents("flag.php");   
            }
        }
    }
} 

根据代码可知,f1和f2必须是字母和数字。if判断是弱等于,需要intval($code)的值为0

intval() 成功时,返回参数的 integer 值,失败时返回 0。空的 array 返回 0,非空的 array 返回 1。 字符串有可能返回 0,取决于字符串最左侧的字符。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1

所以需要$f1($f2());[system(system)] 的返回值,或者是字母开头的字符串,或者是空数组,或者就是0,或者FLASE。

f1=system&f2=system

31.取反~

error_reporting(0); 
highlight_file(__FILE__); 
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
    $v1 = (String)$_GET['v1'];   
    $v2 = (String)$_GET['v2'];   
    $v3 = (String)$_GET['v3'];   
    if(is_numeric($v1) && is_numeric($v2)){
        if(preg_match('/^\W+$/', $v3)){ 
            $code = eval("return $v1$v3$v2;");    
            echo "$v1$v3$v2 = ".$code;   
        }
    }
} 

绕过无字母数字的方法参考yu师傅的脚本

绕过return的方式: php中有个有意思的地方,数字是可以和命令进行一些运算的,例如 1-phpinfo();结合减号是可以执行phpinfo()命令的。(不一定是减号,还有加、乘、除号,若用加号。要用+,要进行URL编码,这是个特殊字符,不进行编码会当作空格)

32.

error_reporting(0); 
highlight_file(__FILE__); 
if(isset($_GET['v1'])){   
    $v1 = (String)$_GET['v1'];   
    if(is_numeric($v1)){     
        $d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d);
        sleep($d);     
        echo file_get_contents("flag.php");
    }
} 

?v1=0 八进制

?v1=0x0 16进制

?v1=0e123 科学计数法

PHP语言特性

一.弱类型

1.php语言中一些相等的值:

" == false == NULL = 'abc' = 0

'123' == 123

'123a' == 0

'0x01' == 1

'0e123456789' == '0e987654321'

["] == [false] == [NULL] == [0]

true == 1

2.== 与 === 两种符号的区别

"==" 在比较时会自动进行类型转化且不改变原来的值,容易存在漏洞

eg: $input == 1

如果$input输入的值为 1abc,则在比较时 1abc会被转换为 1.

而1又代表true,所以在进行if语句判断时,会满足条件,进而引发漏洞产生

再来一个案例

eg: $GET['a'] != $GET['b'] && md5($GET['a']) == md5($GET['b'])

MD5函数返回值时一个32位的字符串,如果这个字符串以'0e'开头的话.类型转换进制会将它识别为一个科学计数法表示的数字"0",给出两个不同的字符串

但当不是==而是===时

eg: $GET['a'] != $GET['b'] && md5($GET['a']) === md5($GET['b'])

刚才给出的两个字符串不能成功了,但是我们仍然可以利用PHP语言函数错误处理的特性: a[]=1&b[]=2成功绕过.

因为我们令MD5函数的参数为一个数组的时候,函数会报错并返回NULL值

函数参数虽然是两个不同的数组,但是函数的返回值是相同的NULL,因此可以绕过

同理,在程序中返回值判断错误的函数还有很多,eg: strpos函数

strpos函数 -- 查找字符串首次出现的位置

eg: strpos($str1,$str2) == false

当str1在str2开头时,函数的返回值是0

0==false,会造成逻辑以外的结果(如if)

3.截断

通过NULL(\x00)字符的时候,处理函数就会将它作为结束的标记,这个漏洞可以帮我们去掉变量结尾处不想要的字符

eg: ?file=etc/passwd%00其他字符

或者

利用路径长度绕过

eg: ?file=../../..//etc/passwd

当系统在处理过长的路径会选择主动截断它.

还要一个能造成截断的情况:不正确的使用iconv函数:

在变量file中包含非法utf-8字符的时候,iconv函数就会截断这个字符串

eg: iconv("UTF-8","gb2313",$file);

4.变量覆盖

(1) 函数使用不当

extract函数

<?php
$auth = false;
extract($_GET);
if($auth){
    echo "flag{...}";
}else{
    echo "yuanshen";
}
?>

此外的extract函数将GET传入的数据转换为变量名和变量值,所以这里构造Payload即可将$auth的值变为true并获得flag

?auth=1

parse_str函数

<?php
$auth = false;
parse_str($_SERVER['QUERY_STRING']);
if($auth){
    echo "flag{...}";
}else{
    echo "yausnhen";
}
?>

此外的parse_str函数同样也是将GET传入的字符串解析为变量,所以Payload与上方extract函数的Payload一样.

import_request_variables函数

<?php
$auth = false;
import_request_variables('G');
if($auth){
    echo "flag{...}";
}else{
    echo "yuanshen";
}
?>

此外 import_request_variables函数的值由G,P,C三个字母组合而成,G代表GET,P代表POST,C代表Cookies.

排在前面的字符会覆盖派在后面的字符传入参数的值,如:参数为"GP",且GET和POST同时传入了auth参数,则POST传入的auth会被忽略.

(2)配置不当

当php配置register_globals=ON时便可能出现该漏洞

<?php
if($auth){
    echo "flag{...}";
}else{
    echo "yuanshen";
}
?>

利用register_globals的特性,用户传入参数auth=1即可进入if语句,需要注意的是,如果在if语句前初始化$auth变量,则不会触发这个漏洞

(3)代码逻辑漏洞

在讲述代码逻辑漏洞导致的变量覆盖之前,需要明白php中的$$(可变变量).可变变量可以让一个普通变量的值作为这个可变变量的变量名.

<?php
$foo="hello";  //赋值普通变量
$$foo="world"; //使用foo变量的值作为可变变量的变量名
echo "$foo ${$foo}";  //输出:hello world 
echo "$foo $hello";  //等同于上面的语句,同样输出hello world
?>

但是新版本php移除了import_request_variables函数和register_globals选项之后

我们可以使用foreach遍历数组来注册变量,这样也会存在变量覆盖漏洞

<?php
$auth=false;
foreach($_GET as $key => $value){
    $$key = $value;
}
if($auth){
    echo "flag{...}";
}else{
    echo "yuanshen";
}
?>

此外的forteach循环就将GET传入的参数注册为变量,所以和前面一样,传入"?auth=1"可绕过.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值