[CISCN 2022 初赛]ezpop(ThinkPHP6.0.12LTS代码审计)

https://xz.aliyun.com/t/11531#toc-3

https://www.nssctf.cn/note/set/4490

因为在学习的过程中间发现自己必须学会审计一些代码,因为自己之前也没有认真的进行过审计,之前遇到了一个thinkphp的题目,但是直接利用了exp,没有仔细审过,所以这次我想仔细审一下,也算是希望自己能够真正进步和成长吧。

1、准备工作

就是使用composer安装

https://www.phpcomposer.com/

composer create-project topthink/think tp6 6.0.12

或者直接打开nssctf题目的环境访问/www.zip下载源码,然后在本地用phpstorm审。

https://www.nssctf.cn/problem/2347

2、找反序列化入口点__destruct

​ 入口点是__destruct,来触发下一步函数的执行

​ 使用ctrl+shift+F全局搜索__destruct,这里注意在搜索这一栏选择目录(D)这一栏,如果选择在项目(P)或者模块(M)或者作用域(S)这几栏的话会搜索不到,😅。
在这里插入图片描述在这里插入图片描述

vendor\topthink\think-orm\src\Model.php
public function __destruct(){
   
    if($this->lazySave){
   
        $this->save();
    }
}

这里我们按ctrl+B可以追踪到save

public function save(array $data = [], string $sequence = null): bool
{
   
    // 数据对象赋值
    $this->setAttrs($data);

    if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) {
   
        return false;
    }

    $result = $this->exists ? $this->updateData() : $this->insertData($sequence);

    if (false === $result) {
   
        return false;
    }

    // 写入回调
    $this->trigger('AfterWrite');

    // 重新记录原始数据
    $this->origin   = $this->data;
    $this->get      = [];
    $this->lazySave = false;

    return true;
}

​ 我们从前往后看,其中$this->isEmpty()false === $this->trigger('BeforeWrite')这两个式子只要一个为真,就会返回False,所以需要让它们均为假才可以,即$this->isEmpty为False,$this->trigger('BeforeWrite')为true

我们先看第二个,我们再按ctrl+B可以追踪到trigger

protected function trigger(string $event): bool
{
   
    if (!$this->withEvent) {
   
        return true;
    }

    $call = 'on' . Str::studly($event);

    try {
   
        if (method_exists(static::class, $call)) {
   
            $result = call_user_func([static::class, $call], $this);
        } elseif (is_object(self::$event) && method_exists(self::$event, 'trigger')) {
   
            $result = self::$event->trigger('model.' . static::class . '.' . $event, $this);
            $result = empty($result) ? true : end($result);
        } else {
   
            $result = true;
        }

        return false === $result ? false : true;
    } catch (ModelEventException $e) {
   
        return false;
    }
}

$this->withEvent为False就可以返回true

搜索withEvent

public function withEvent(bool $event)
{
   
    $this->withEvent = $event;
    return $this;
}

然后再看isEmpty,最后是跟进到了empty()函数

public function isEmpty(): bool
{
   
    return empty($this->data);
}
function PS_UNRESERVE_PREFIX_empty($var) {
   }

empty中,参数是非空非零会返回false,下面这些都是空

  • ""(空字符串)
  • 0(整型零)
  • 0.0(浮点零)
  • "0"(字符串零)
  • NULL
  • FALSE
  • 一个空的数组
  • 一个空的对象,包括类的对象

那只要让$this->data不为空就可以,现在已经成功跳过第一个if,汗颜🥵💦

接下来来到一个三元运算符

$result = $this->exists ? $this->updateData() : $this->insertData($sequence);

​ 意思就是如果this->existstrue,则执行updateData(),反之,则执行$this->insertData($sequence),这里$this->exists是可控的,先跟进updateData()

protected function updateData(): bool
{
   
// 事件回调
if (false === $this->trigger('BeforeUpdate')) {
   
    return false;
}

$this->checkData();

// 获取有更新的数据
$data = $this->getChangedData();

if (empty($data)) {
   
    // 关联更新
    if (!empty($this->relationWrite)) {
   
        $this->autoRelationUpdate();
    }

    return true;
}

if ($this->autoWriteTimestamp && $this->updateTime) {
   
    // 自动写入更新时间
    $data[$this->updateTime]       = $this->autoWriteTimestamp();
    $this->data[$this->updateTime] = $data[$this
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值