PHP代码审计实例

PHP代码审计实例

0x01.extract变量覆盖

<?php

$flag='C:\test.txt';
extract($_GET);
 if(isset($shiyan))
 { 
    $content=trim(file_get_contents($flag));//当文件不存在时$content为空,传入一个空的$shiyan即可,但是当文件存在时,这要将$flag也传入空。
    if($shiyan==$content)
    { 
        echo'ctf{xxx}'; 
    }
   else
   { 
    echo'Oh.no';
   } 
   }
?>
payload:http://127.0.0.1/?shiyan=&flag=

0x02.绕过过滤的空白字符

<?php
 
$info = ""; 
$req = [];
$flag="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
 
ini_set("display_error", false); //为一个配置选项设置值
error_reporting(0); //关闭所有PHP错误报告
 
if(!isset($_GET['number'])){
   header("hint:26966dc52e85af40f59b4fe73d8c323a.txt"); //HTTP头显示hint 26966dc52e85af40f59b4fe73d8c323a.txt
 
   die("have a fun!!"); //die — 等同于 exit()
 
}
 
foreach([$_GET, $_POST] as $global_var) {  //foreach 语法结构提供了遍历数组的简单方式 
    foreach($global_var as $key => $value) { 
        $value = trim($value);  //trim — 去除字符串首尾处的空白字符(或者其他字符)
        is_string($value) && $req[$key] = addslashes($value); // is_string — 检测变量是否是字符串,addslashes — 使用反斜线引用字符串
    } 
} 
 
 
function is_palindrome_number($number) { 
    $number = strval($number); //strval — 获取变量的字符串值
    $i = 0; 
    $j = strlen($number) - 1; //strlen — 获取字符串长度
    while($i < $j) { 
        if($number[$i] !== $number[$j]) { 
            return false; 
        } 
        $i++; 
        $j--; 
    } 
    return true; 
} 
 
 
if(is_numeric($_REQUEST['number'])) //is_numeric — 检测变量是否为数字或数字字符串 
{
 
   $info="sorry, you cann't input a number!";
 
}
elseif($req['number']!=strval(intval($req['number']))) //intval — 获取变量的整数值
{
 
     $info = "number must be equal to it's integer!! ";  
 
}
else
{
 
     $value1 = intval($req["number"]);
     $value2 = intval(strrev($req["number"]));  
 
     if($value1!=$value2){
          $info="no, this is not a palindrome number!";
     }
     else
     {
 
          if(is_palindrome_number($req["number"])){
              $info = "nice! {$value1} is a palindrome number!"; 
          }
          else
          {
             $info=$flag;
          }
     }
 
}
 
echo $info;

首先判断了$_GET是否传入了number,没有则返回hint并且终止程序且输出“have a fun!!”,接下来遍历传入的数组,检测传入的number是否为数字或者数字字符串,如果是则失败(绕过),再判断是否为整数(绕过),再判断变量的字符串反转值和其本事是否相等,最后再调用is_palindrome_number这个函数判断是否为回文数(绕过)返回false则拿到flag。

条件:

1.不为空,且不能是一个数值型数字,包括小数。(由is_numeric函数判断)//%00或者%20绕过

2.不能是一个回文数。(is_palindrome_number判断)// /f(%0c)绕过

3.该数的反转的整数值应该和它本身的整数值相等;

2与3冲突//传入一个最大整数值或者/f绕过2

方法:

一:

1、is_numeric函数对于空字符%00判断为非数值,绕过第一个条件。
函数判断为非数值,但又不影响它值的构造,理所当然想到空格字符%20和空字符%00。

2、2147483647不是一个回文数绕过第二个条件。

3、这里利用了intval函数的溢出问题。
Intval最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。
至于服务器是什么系统的可以用burp抓包分析出来为32位

 $value1 = intval($req["number"]);
 $value2 = intval(strrev($req["number"]));  

我们构造的2147483647经过strrev反转函数后为7463847412,又经过intval函数值又变为2147483647。

故满足条件3,可以输出flag。

二:

因为要求不能为回文数,但又要满足intval($req["number"])=intval(strrev($req["number"])),所以我们采用科学计数法构造payload为number=0e-0%00,这样的话我们就可以绕过。

xey在php中就是x*10的y次方

注意
is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后

三:

is_numeric函数在开始判断前,会先跳过所有空白字符可是题目获取$req[‘number’]的时候明明使用trim过滤了空白字符这时候我们可以引入\f(也就是%0c)在数字前面,来绕过最后那个is_palindrome_number函数,而对于前面的数字判断,因为intval和is_numeric都会忽略这个字符,所以不会影响。
所以我们构造payload=URL?%00%0c191即可绕过上面的条件获得flag

四:

+(%2b)

‘+191’=='191’且intval(‘191+’)==191

payload

%0c0%20

%002147483647

0e-0%00

%00%2b0

0x03.多重加密

<?php
    include 'common.php';
    $requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);
    //把一个或多个数组合并为一个数组
    class db
    {
        public $where;
        function __wakeup()
        {
            if(!empty($this->where))
            {
                $this->select($this->where);
            }
        }
        function select($where)
        {
            $sql = mysql_query('select * from user where '.$where);
            //函数执行一条 MySQL 查询。
            return @mysql_fetch_array($sql);
            //从结果集中取得一行作为关联数组,或数字数组,或二者兼有返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
        }
    }

    if(isset($requset['token']))
    //测试变量是否已经配置。若变量已存在则返回 true 值。其它情形返回 false 值。
    {
        $login = unserialize(gzuncompress(base64_decode($requset['token'])));
        //gzuncompress:进行字符串压缩
        //unserialize: 将已序列化的字符串还原回 PHP 的值

        $db = new db();
        $row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
        //mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。

        if($login['user'] === 'ichunqiu')
        {
            echo $flag;
        }else if($row['pass'] !== $login['pass']){
            echo 'unserialize injection!!';
        }else{
            echo "(╯‵□′)╯︵┴─┴ ";
        }
    }else{
        header('Location: index.php?error=1');
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值