我们用开源 AI 安全代理挖出 24 个安卓漏洞的全过程
幻泉之洲
2026年10月11日 10:19
北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
GitHub 安全实验室用自研的开源 Taskflow Agent,在安卓应用里挖出 24 个漏洞,包括 OsmAnd 的静默定位追踪和维基百科安卓版的账号接管。这篇文章讲清楚三件事:任务流怎么设计、漏洞怎么被串成完整攻击链、以及 LLM 在找漏洞这件事上到底哪里行、哪里不行。
AI 在安全圈火起来之后,我们团队搞了个 GitHub Security Lab Taskflow Agent,目的是让安全研究员能把自己摸索出来的有效 AI 提示词和工作流打包、自动化、共享出去。这篇讲的是我怎么写出一套审计任务流,用它去安卓应用里找漏洞。
模型理解代码的能力确实在涨。但光靠模型还不够——自定义任务流提示词的价值在于,研究员能把研究拆成一步步的小任务,引导 LLM 更快地找到复杂漏洞,或者找到它原本压根不会注意到的东西。
靠这套任务流,我已经报告了 20 多个安卓应用的漏洞,全部加起来目前是 24 个。后面会挑两个影响比较大的案例详细拆解。
想自己跑一遍?三步
任务流是开源的,可以直接上手。但有几点先说清楚:需要 GitHub Copilot 授权,提示词会消耗高级模型的请求额度;跑一次会产生大量工具调用,token 烧得很快。
- 打开 seclab-taskflows 仓库,启动一个 codespace。
- 等几分钟让 codespace 初始化完成。
- 在终端里执行
./scripts/audit/run_mobile.sh myorg/myrepo。
中等规模的仓库大概要跑一两个小时。跑完会自动弹出一个 SQLite 查看器,打开 audit_results 表,找 has_vulnerability 列打了勾的行。
为安卓应用定制审计任务流
我同事 Peter 和 Mo 之前写过他们那套审计任务流。那套东西单独用已经不错,但安卓应用有自己特有的漏洞类型,得专门引导模型关注。
第一件事,我加了一个 gather_mobile_entry_point_info.yaml。入口点指的是攻击者可控数据可能流经的代码位置。这个任务流把入口点分成移动端和非移动端两类。这样一来,同一个仓库里就算同时有手机应用、Web 服务、桌面程序,AI 也能识别出正确的攻击面。
第二件事,改 classify_application_local.yaml。我在里面列了一批常见漏洞类型,要求 LLM 结合每个入口点和组件逐一考虑。安卓漏洞不像 Web 漏洞那么广为人知,而 LLM 本身是非确定性的,所以必须确保它检查到那些关键类别。举个例子:如果前一步识别出这是个基于 intent 的入口,那它就应该带着一份 intent 相关漏洞清单去查——confused deputy(混淆代理)、insecure broadcasts(不安全广播)之类。这能帮 LLM 建立组件之间的关联,同时保持对整体威胁模型的把握。
跑多轮、把两种提示词结合起来,效果最好:严格的提示词加重复运行,保证明显的漏洞不会漏掉;宽泛的提示词则让 AI 的创造力有发挥空间。
案例一:通过 OsmAnd 追踪用户位置
OsmAnd 是个挺流行的第三方导航应用,主要数据源是 OpenStreetMap,App Store 和 Play Store 都有。我们看的是安卓版,下载量超过 1000 万。
发现的三个漏洞里,最有意思的一个能让恶意应用追踪设备位置。先说清楚怎么回事。
OsmAnd 导出了一个叫 MapActivity 的 activity。安卓里的 activity 就是一个带界面的独立屏幕。MapActivity 负责处理应用内打开设置文件和 deeplink,而且它是 exported(导出)状态——意思是别的应用可以启动它。
然后每一个瓦片的精确 x、y 坐标就全泄露了。这个 URL 预期返回一张图片,所以我们在攻击者服务器后端从 OpenStreetMap 取对应的瓦片发回去,用户看到的界面完全正常。而攻击者手里拿到的是用户在 OsmAnd 里加载过的每一个瓦片的 x、y 坐标列表。用户对自己应用设置被改了这件事,毫不知情。
换句话说,任何一个应用——哪怕它一个权限都没有——都能覆盖 OsmAnd 的设置,把私密位置数据传回自己的服务器。
[TILE #1] 14:23:07 z=15 x=9649 y=12320
├── center: 40.70979, -73.98743
└── https://www.openstreetmap.org/#map=15/40.70979/-73.98743
同样的漏洞还能拿到用户每次导航路线的起点和终点,用户那边看不出任何变化。
[ROUTE #1] 07:02:47 vehicle=car waypoints=2
├── path: /osrm/car/-122.084,37.4219983;-122.32450103759766,37.99944305419922
├── ORIGIN: 37.421998, -122.084000
│ https://www.openstreetmap.org/#map=15/37.42200/-122.08400
├── DESTINATION: 37.999443, -122.324501
│ https://www.openstreetmap.org/#map=15/37.99944/-122.32450
案例二:通过 deeplink 接管维基百科账号
再看维基百科安卓应用。为了在应用内浏览维基页面,它注册了 wikipedia:// 这个 deeplink。正常的长这样:wikipedia://wikipedia.org/wiki/PoC。但主机名解析里有个逻辑 bug,能让我们加载非维基的 URL。
private fun handleIntent(intent: Intent) {
if (Intent.ACTION\_VIEW == intent.action && intent.data != null) {
// TODO: handle special cases of non-article content, e.g. shared reading lists.
intent.data?.let {
if (it.authority.orEmpty().endsWith(WikiSite.BASE\_DOMAIN)) {
// Pass it right along to PageActivity
val uri = Uri.parse(it.toString().replace(\"wikipedia://\", WikiSite.DEFAULT\_SCHEME + \"://\"))
startActivity(Intent(this, PageActivity::class.java)
.setAction(Intent.ACTION\_VIEW)
.setData(uri))
}
}
}
}
用 endsWith 判断域名,意味着 evil-wikipedia.org 也能过检查。于是我们可以用 wikipedia:// deeplink 把用户引到任意网站,用户还以为自己在维基百科页面上。更糟的是,攻击者能在应用的 WebView 里执行任意 JavaScript——这是一个相当危险的入口,能通往平时被认为安全的环境。
而且这个漏洞模式在同一个应用里出现了两次,不是一次:
// SharedPreferenceCookieManager.kt:101
if (domain.endsWith(domainSpec)) {
buildCookieList(cookieList, cookiesForDomainSpec, null)
}
第二段代码判断的是某个页面该不该带上 wikipedia.org 的 cookie。两个问题串起来,就能把维基页面所有长效 cookie 全泄露出去。合起来就是一个完整的账号接管攻击:
- 受害者在浏览器里打开一个恶意网页,点了个带 deeplink 的链接。
- 维基百科安卓应用自动打开,加载一个以 wikipedia.org 结尾的攻击者页面,比如 evil-wikipedia.org。受害者以为是维基页面,应用自动把 cookie 发了出去。
攻击者拿到的是用户名、长效 token,以及跨所有维基媒体项目(各语言维基、Commons、Wikidata、Meta 等)都有效的 session token。
这两个例子说明一件事:LLM 能找出的不只是通用 bug 类型,也包括影响严重的逻辑漏洞。
LLM 很会找漏洞,但估不准严重性
找漏洞这块 LLM 确实行——行到会找出一堆影响不大的低危 bug。我很多次看到 AI 返回的问题需要非常特殊的状态组合,现实里几乎不可能触发。甚至明确告诉它别报低危漏洞,它照报不误。所以每一条发现都得由懂移动应用的安全研究员人工过一遍。
另一个问题是严重性估错。一个漏洞的真实影响往往会被各种缓解因素压低。比如安卓应用里一个路径遍历,但文件路径被限制在外部存储,这个问题的相对严重性就很低。这类缓解因素 LLM 不专门提示它\"写个 PoC\"是看不出来的——这意味着不光找漏洞要跑多轮,做概念验证也要跑多轮,逼着 LLM 真的去尝试利用。而模型的可用性和速度摆在那儿,花在这些可能没啥影响的问题上的时间就是纯浪费。
即使这样,LLM 还是会搞错。举个例子:如果应用同时用内部存储和外部存储的数据,通常内部存储的数据优先级更高。LLM 可能会假设通过路径遍历写入的外部存储数据能改掉应用的实际数据,但如果内部存储会覆盖掉我们控制的外存数据,那就根本不存在漏洞。这类复杂行为导致误报,等模型的上下文窗口更大、推理能力更强,误报会减少。但现在唯一的解法是给 LLM 一个调试器,让它把 PoC 和原始代码都跑一遍;或者靠研究员在提示词里专门点名让它查这些问题。
LLM 对 API 行为的理解真的不错
任何一个专攻某门语言的安全研究员,脑子里都有一张代码模式表:哪些函数安全,哪些不安全。比如 Go 里的 path.Clean 就远比 filepath.Clean 危险,是很多影响 Windows 版流行产品的漏洞源头。
让我们意外的是,即使拿不到语言源码,LLM 对各种语言里常见安全 API 的行为理解得相当好。我们让它基于漏洞报告生成的大部分 PoC,几乎不需要在本机做修改——这说明它对历史漏洞利用和 API 行为有相当深的知识储备。
关于结果的一点说明
写这篇文章的时候,我们在移动应用里找到了 24 个安卓漏洞。不少是路径遍历这种比较简单的问题,但也有一批严重的,上面讲的就在其中。安卓应用安全整体做得比较扎实,所以漏洞出现的位置基本都在研究员的预期之内——比如 WebView 里的跨应用脚本执行,或者暴露出来的 JavaScript bridge。
我们认为 AI 驱动的安全研究,是目前保护开源项目最好的方式之一。这套方法对 Web 应用、移动应用、桌面应用都适用。
写在最后
安全应该是所有开源维护者的头等大事。未来几年里 AI 会成为每个维护者的必备工具,开发和安全的场景都一样。seclab-taskflow-agent[1]能让你几分钟内就跑起来,也欢迎贡献你找到的有意思的提示词、工具和漏洞挖掘机制。
拿这套任务流对着你自己的应用跑一遍,算是迈向 AI 辅助安全的第一步。说实话,这一步比很多人想的要低。
参考资料
[1] https://github.com/GitHubSecurityLab/seclab-taskflow-agent
[2] https://github.blog/security/how-we-found-24-android-vulnerabilities-using-our-open-source-ai-security-agent/
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论