论坛首页 漏洞分析研究区 阅读主题

[原创]强网杯2025 Qcalc WriteUp

347 浏览 2 回复
#1 楼主 2026-06-01 21:08:55
首先是有个Intent注入,APP处理 deep link 的时候,如果表达式里包含 "intent:",就会用 Intent.parseUri() 来解析。相当于给我们开了一个后门,可以往应用里注入恶意的 Intent。 而 BridgeActivity 这个组件本来是用来处理异常的,但是它有个问题,验证通过后会给攻击者授予 Content Provider 的访问权限,我们就可以通过这个来访问目标APP的私有目录,比如我们 location /data/data/com.qinquang.calc/flag-xxxxxxxx.txt 的 flag 和 history.yml。 最后是 YAML 反序列化漏洞,其实就是CVE-2022-1471这里用了一个叫 SnakeYAML 的库来读取历史记录文件 history.yml。它直接就把 YAML 文件里的内容给反序列化了,完全不管里面装的是什么东西。我们可以在YAML文件里放一个的对象,当APP读取这个文件的时候,就会自动创建这个对象,然后执行里面的代码 这里有个很离谱的 PingUtil 类,直接把用户输入拼接到 ping 命令里,完全没有过滤,基本就是命令执行 先构造一个恶意的 Intent,里面包含了 bridge_token(这个token是通过目标应用包名计算出来的)。然后把这个 Intent 编码后,通过deep link发送给目标应用。目标应用收到后,发现表达式里包含 "intent:",就会解析这个 Intent 并存储为 fallback(备用方案)。然后等一会儿,发送一个除零的表达式 (1/0) 给目标应用。目标应用计算的时候会抛出异常,这个时候就会启动 BridgeActivity 来处理这个异常BridgeActivity 检查 fallback Intent,验证 token,发现没问题,就给了我们 Content Provider 的访问权限,并且回调我们的应用 这个时候我们拿到权限后,就往 history.yml 文件里写入恶意的 YAML 内容。如果我们往 history.yml 写一个对象,那么后续这个 history.yml 被 loadHistory 时就会触发反序列化,来执行这个代码 这个时候我们就可以写入 PingUtil 类来进行目标APP权限下的命令执行其实到命令执行这一步当时很快就做到了,但是怎么利用这个来进行拿 flag 想了很久,试了很多方案由于这题的打远程的过程是,我们上传 APK 给容器,然后容器自动安装运行,后面就什么都没了。所以说,flag 肯定是 POC 安装运行后发送的,而目标 APP 是没有网络权限的,那我们只能给我们的POC网络权限,然后想办法让 POC 去读到目标 APP 私有目录下的 flag,读到 flag 后直接发给我们服务器就行那么我们解决问题的关键就在于,POC 的 APP 怎么去访问目标APP的私有目录可以很容易想到的就是,利用 BridgeActivity 给我们的 Content Provider 的访问权限去访问,但是这里有几个问题:我们此时虽然可以利用命令执行去操作 flag,比如 mv 操作,但是没有那种目标 APP 可以写,同时 POC APP 又可以读的公用目录。那 cat 呢,它也只是目标APP去读取,我的 POC 并没有读到,因为这个命令执行是目标 APP 发起的,而不是我们的 POC PS:如果不知道一个 APP 权限的 shell 能干嘛,可以 run-as 切换进去试试后面突然发现 BridgeActivity 是给我授予了对 history.yml 的读写权限的,那我直接把flag的内容覆写到 history.yml ,然后读取不就完了?与之而来的下一个问题就是,在正常的逻辑运行时, loadHistory 读取解析并真正执行了我们的覆写命令之后,会执行 saveHistory 将正常计算重新覆盖 history.yml 综上结论就是:授权是短暂的,BridgeActivity 通过 FLAG_GRANT_READ/WRITE_URI_PERMISSION 临时把 content://.../history.yml 授权给我,这种 URI 授权通常随“这次回调/这条任务链”有效,Activity 结束或进程状态变化后可能失效。所以要在回调同一时序窗口内尽快读取。文件内容是刚被覆盖的,恶意 YAML 触发的命令先把 flag 覆盖到 history.yml,我需要在“覆盖完成之后、被其他逻辑再次写回/清空之前”读取,才能拿到 flag。这就需要在触发正常计算后稍等一小会儿再读。那么这个稍微等一小会的就需要我们慢慢去测试测试方法也很简单:如果读取服务器收到的内容是我们写入的恶意 yml,就说明命令还没执行,间隔太短如果读取服务器读到的内容是一个正常的计算公式,就说明 yml 已经二次覆盖掉了,间隔太长然后测去不断缩小延时的区间就可以了当时本地测通了,一开始打远程的时候,我服务器啥回显都没有,后面莫名其妙又有了,过了一会莫名其妙又没了。远程的容器当时还满了,挺搞心态的,远程都打了我半个小时玩挺开心的,可惜最后还是没打进线下捏~// 首次由用户启动:自动驱动全链路(存fallback -> 触发BridgeActivity)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288864.htm
#2 2026-06-01 21:08:55
芥末强
#3 2026-06-01 21:08:55
你可以在利用一次intent重定向到HistoryActivity就可以避免调用saveHistory导致flag被覆盖了

请登录后参与讨论

立即登录 注册账号