XcodeGhost in 2025
背景
在上网冲浪时, 发现一篇文章提到了 XcodeGhost. 想起之前只是了解了大概, 就又去仔细搜索了下 XcodeGhost 事件的细节, 发现 icloud-analysis.com 这个域名目前居然是无主状态, 于是有了接下来的故事.
域名注册
在各种分析文章中, 写的比较好的是安天实验室的这篇, 分析了整个事件的完整时间线和对攻击载荷的分析.
在这篇文章中, 可以发现除了 icloud-analysis.com 这个域名之外, 攻击者还用到了下面这两个域名, 分别投递到了不同版本的 Xcode 里面, 甚至还制作了部分 Unity 的恶意安装包.
crash-analytics.comicloud-diagnostics.com
其中 icloud-analysis.com, icloud-diagnostics.com 在当时仍然处于未被注册状态, 于是直接在 cloudflare 上注册拿下, 倒是没有遇到什么特殊的告警 (.
顺便可以通过微步的 Whois 历史功能, 分析下这三个域名的历史
icloud-analysis.com
- 2015-02-25 被攻击者注册
- 2015-10-04 被 shadowserver takeover, 解析到 sinkhole
- 2021-08-28 疑似域名未续费过期, 微步这个 whois 历史有点抽象, 可能更早就已经过期
- 2021-09-07 被 New Ventures Services, Corp 购买, 根据搜索可以得知这是一个靠捡这种过期域名赚钱的公司
- 2022-09-03 域名第二次到期
- 2022-11-23 被未知所有者通过 key-systems.net 注册
- 2023-11-23 域名第三次到期
- 2024-03-05 被姓名 yunfei lin, 邮箱 linzixin0723@gmail.com 通过 value-domain.com 购买, 通过搜索邮箱可以搜到其名下还有很多域名, 疑似也是炒域名的
- 2025-03-05 域名第四次到期
crash-analytics.com
- 2015-08-26 被攻击者注册, 迷惑的是注册的时候就没开隐私保护, 姓名 (andy wang wang), 邮箱 (778560441@qq.com), 手机号 (13276422520), 地址 (shiji building jinan,jinan,shandong,CHINA) 直接漏出来了
- 2016-08-26 域名到期
- 2016-11-13 被 virustracker.info sinkhole (virustracker 自己好像都倒闭了…?)
- 2023-11-13 域名第二次到期
- 2024-01-29 被未知所有者通过 realtimeregister 注册
- 2025-03-21 转移到 key-systems.net 注册局, 通过 NS 服务器可以知道被淘阿网所有, 经典炒域名的站
icloud-diagnostics.com
- 2015-05-06 被攻击者注册
- 2015-09-21 最抽象的一集, 域名的隐私保护被关掉了. 可能攻击者手滑了? 直接把姓名 (Huaxian Tao) + 手机号 (13276422520) + QQ 邮箱 (778560441@qq.com) + 地址 (No. 21 Haiyang Building,QD,China,QD,Shandong,China) 全暴露出来了, 与 crash-analytics.com 对的上
- 2016-05-07 域名到期
- 2016-07-24 同上, 被 virustracker.info sinkhole
- 2023-07-24 域名第二次到期
看下来比较难绷的点有
- 攻击者自己开盒, 邮箱和电话感觉比较真
- 安全机构自身难保, 并且在一定期限后都停止了 sinkhole
- 域名过期后大概率被炒域名机构买下, 然后需要高价赎回
搭建 C2 (伪) 服务器
拿下了域名之后, 最想要知道的莫过于在距离 2015 年已经 10 年的现在, 真的还有这么老的设备在运行这么老的应用程序么?
为此, 我们自然需要搭一个 C2 服务器来看看到底有没有请求. 实际上, 社区在当年就有人根据恶意代码写了对应的服务器. 但是我们并不真的需要进行什么恶意操作, 只是想收集 XcodeGhost 发送的遥测数据. 并且还想要尽量的节省预算, 毕竟如果用国内服务器的话, 流量估计是一笔不小的钱. 这自然让我想到了互联网活菩萨 Cloudflare 的 Serverless 产品 Workers, 可以直接免费使用, 完全可以写一个脚本记录所有 http 请求, 然后存在数据库里面即可 (这真的不是 Cloudflare 的广告).
稍微翻一下文档 + vibe coding 可以得到下面的代码
1import { Buffer } from 'node:buffer';
2
3export default {
4 async fetch(request, env) {
5 try {
6 // 获取请求信息
7 const url = new URL(request.url);
8 const method = request.method;
9 const headers = JSON.stringify(Object.fromEntries(request.headers));
10 const clientIP = request.headers.get('CF-Connecting-IP') || 'unknown';
11
12 // 读取请求 body
13 let body = '';
14 if (method !== 'GET' && method !== 'HEAD') {
15 const arrayBuffer = await request.arrayBuffer();
16 const uint8Array = new Uint8Array(arrayBuffer);
17 body = Buffer.from(uint8Array).toString('base64');
18 }
19
20 // 保存到 D1 数据库
21 const stmt = env.DB.prepare(`
22 INSERT INTO requests (method, url, headers, body, ip_address)
23 VALUES (?, ?, ?, ?, ?)
24 `);
25
26 await stmt.bind(method, url.toString(), headers, body, clientIP).run();
27
28 // 返回成功响应
29 } catch (error) {
30 console.error('Error saving request:', error);
31 }
32 return Response.redirect("https://github.com/XcodeGhostSource/XcodeGhost", 302);
33 }
34}
需要注意, 为了用 node:buffer 这个 package, 需要在 workers 设置里的 Compatibility flags 打开 nodejs_compat 才行.
不过剧透一下, 最后还是氪了一个月的 Paid 套餐. 没想到数据量这么大, 导致送的 D1 数据库额度不够了 = =
数据分析
整个 Worker 从 8 月 21 日到 9 月 21 日, 在这两个域名下都挂了一个月, 排除爬虫请求, 收到了超乎想象的 1847830 条有效请求. 大部分请求来自 icloud-analysis.com, icloud-diagnostics.com 只贡献了 10 条有效请求. 当然这么多请求不代表有这么多设备, XcodeGhost 的遥测数据在每次应用 Launch, Resign, Terminate 等请求时都会发送一次. 导致切到后台这个操作可能就会触发一次请求. 不过话又说回来, 由于 cloudflare 本身在中国大陆访问就是不稳定的, 可能会导致部分数据丢失.
XcodeGhost 发送到 C2 的请求是 DES 对称加密过的, 由于没有用非对称加密, 所以解密起来不是很难, 可以参考下面的脚本
1from Crypto.Cipher import DES
2from Crypto.Util.Padding import pad, unpad
3import re
4import base64
5import json
6
7data = base64.b64decode('XXXX')
8
9des = DES.new(key=b'stringWithFormat'[:8], mode=DES.MODE_ECB)
10data = unpad(des.decrypt(data), block_size=8)[8:].decode()
11
12print(data)
解密出来的样例结果如下
1{
2 "country" : "CN",
3 "os" : "10.3.4",
4 "type" : "iPhone5,1",
5 "app" : "网易云音乐",
6 "name" : "iPhone",
7 "idfv" : "0017D07D-F091-4ECB-8BEB-8B3DB6E13288",
8 "timestamp" : "1756046349",
9 "bundle" : "com.netease.cloudmusic",
10 "status" : "resignActive",
11 "version" : "2.7.2",
12 "language" : "zh-Hans"
13}
对几个字段分析了一下, 统计的数据如下
country + language + 客户端 IP
有高达 82 个不同的 country, 但是通过对应记录的 language 可以发现实际上语言还是中文, 我没搞过 iOS 的开发, 但是这个 country 估计是来自自己设置的选项.
1['AC', 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AX', 'BG', 'BR', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CF', 'CH', 'CL', 'CN', 'CO', 'CX', 'DE', 'DG', 'DK', 'DZ', 'ES', 'ET', 'FR', 'GB', 'GM', 'GP', 'GY', 'HK', 'IE', 'IL', 'IN', 'IS', 'IT', 'JP', 'KR', 'KW', 'KZ', 'LA', 'LI', 'MK', 'MM', 'MN', 'MO', 'MX', 'MY', 'NG', 'NL', 'NO', 'NZ', 'OM', 'PH', 'PK', 'QA', 'RU', 'RW', 'SA', 'SG', 'TH', 'TJ', 'TM', 'TR', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'VI', 'VN', 'ZA']
相比之下, 语言以及客户端 IP 的可信程度更高, 其中语言共有 113 种, 包括但不限于 🇷🇺, 🇸🇦, 🇬🇧 等
1['ar', 'ar-AE', 'ar-KW', 'ar-SA', 'da', 'de', 'de-AT', 'de-DE', 'en', 'en-AU', 'en-CA', 'en-CN', 'en-ET', 'en-GB', 'en-HK', 'en-MM', 'en-NG', 'en-PH', 'en-SA', 'en-TH', 'en-TW', 'en-US', 'es', 'es-CL', 'es-CO', 'es-ES', 'es-MX', 'es-US', 'fr', 'fr-CA', 'fr-FR', 'he', 'is-CN', 'it', 'it-IT', 'ja', 'ja-CN', 'ja-JP', 'ja-US', 'ko', 'ko-CN', 'ms', 'nb', 'nb-NO', 'pt', 'pt-PT', 'ru', 'ru-AM', 'ru-CN', 'ru-RU', 'ru-TJ', 'ru-TM', 'ru-UA', 'ru-US', 'th', 'th-CN', 'th-TH', 'ug-CN', 'ug-US', 'vi', 'vi-VN', 'zh-Hans', 'zh-Hans-AC', 'zh-Hans-AD', 'zh-Hans-AF', 'zh-Hans-AG', 'zh-Hans-AI', 'zh-Hans-AL', 'zh-Hans-AO', 'zh-Hans-AQ', 'zh-Hans-AR', 'zh-Hans-AU', 'zh-Hans-AX', 'zh-Hans-BR', 'zh-Hans-CA', 'zh-Hans-CF', 'zh-Hans-CN', 'zh-Hans-CX', 'zh-Hans-DE', 'zh-Hans-DZ', 'zh-Hans-ES', 'zh-Hans-GB', 'zh-Hans-GM', 'zh-Hans-GP', 'zh-Hans-GY', 'zh-Hans-HK', 'zh-Hans-IS', 'zh-Hans-IT', 'zh-Hans-JP', 'zh-Hans-KR', 'zh-Hans-MK', 'zh-Hans-MM', 'zh-Hans-MO', 'zh-Hans-MY', 'zh-Hans-NZ', 'zh-Hans-OM', 'zh-Hans-QA', 'zh-Hans-SG', 'zh-Hans-TM', 'zh-Hans-TR', 'zh-Hans-TW', 'zh-Hans-US', 'zh-Hans-VN', 'zh-Hans-ZA', 'zh-Hant', 'zh-Hant-CN', 'zh-Hant-GB', 'zh-Hant-HK', 'zh-Hant-MO', 'zh-Hant-TW', 'zh-Hant-US', 'zh-HK', 'zh-TW']
共有 127229 个独立的 IP, 通过 IP 可以确定确实是有外国人中招的. 通过对应的 bundle 字段, 使用的也是 com.zhiliaoapp.musically, com.mobivio.cutecutpro, com.ilegendsoft.MBrowser 这种国外应用.
应用
这个可能是最准确的中招列表了 (
1['cairot', 'cn.12306.rails12306', 'cn.com.10jqka.IHexin', 'cn.com.10jqka.iHexinFee', 'cn.com.10jqka.ipad', 'cn.com.cdzq.ths', 'cn.com.doudizhu.happy', 'cn.com.qdqdjoys.jl', 'cn.net.hzcaifeng.yb', 'com.17zuoye.homework', 'com.aemobile.games.sudoku', 'com.apple.AppStore', 'com.apple.MobileAddressBook', 'com.apple.Preferences', 'com.apple.springboard', 'com.arcsoft.Perfect365', 'com.arkids.poketzoo', 'com.autonavi.amap', 'com.baidu.BaiduMobile', 'com.baidu.TingIPhone', 'com.barhatgames.lol.erolabs', 'com.brandy.scys', 'com.brightlabs.quicksave', 'com.caixin.magazineapp', 'com.candy.yy', 'com.cherrygame.majiang', 'com.cn.greenbrowser', 'com.csair.MBP', 'com.dandan.DongHuaDuoDuo', 'com.dayup11.LaiDianGuiShuDiFree', 'com.degoo.icemommy', 'com.diary.mood', 'com.DragonGame.fruitworlds', 'com.dtcsolutions.dtc', 'com.dw.fs.PP', 'com.flyhuang.kangkang', 'com.gemd.iting', 'com.haomee.video', 'com.hiddensweet.bubbleshooterhdfree', 'com.hmzl.hmxx', 'com.htzq.ths.iphone', 'com.iflytek.iflyinput', 'com.ilegendsoft.MBrowser', 'com.ilegendsoft.MBrowserPro', 'com.intsig.camcard.lite', 'com.intsig.CamScannerLite', 'com.jailbreak.kk', 'com.jingling.bssj', 'com.kdanmobile.ipad.PDFReader', 'com.kdanmobile.ipad.pdfreaderlite', 'com.kdanmobile.PDFReaderLite', 'com.KKGOO.kk', 'com.konka.MultiscreeninteractionV3.0', 'com.luobocn.carrotfantasy2', 'com.luomao.GamePlayer', 'com.lyw.dmbj5', 'com.mobileventures.LittleFarmers', 'com.mobivio.cutecut', 'com.mobivio.cutecutpro', 'com.my.laugheveryday', 'com.mystylinglounge.eyelashes-makeup', 'com.mystylinglounge.promhairsalon', 'com.netease.cloudmusic', 'com.netease.videoHD', 'com.ng.simulator', 'com.octInn.br', 'com.olimsoft.oplayer', 'com.olimsoft.oplayer.hd', 'com.olimsoft.oplayer.hd.lite', 'com.olimsoft.oplayer.lite', 'com.pingan.PAMobileStockHigh', 'com.rovio.scn.baba', 'com.rovio.tcn.baba', 'com.s5game.fishsaga', 'com.shoujiduoduo.ringtone', 'com.shoujiduouod.ergeduoduoipad', 'com.ss.iphone.ugc.Aweme', 'com.starsea.wblock', 'com.stockradar.radar1', 'com.taofang.iphone', 'com.tapinfinity.PhotoshopHuDongJiaoCheng', 'com.teiron.pphelperns', 'com.telecom-guoling.feiin', 'com.tencent.mt2', 'com.tencent.qjnn', 'com.tencent.xin', 'com.tiger515.lobby', 'com.tinmanarts.JoJoTiezhi', 'com.tinmanarts.zuokezhenmafan', 'com.tongbu.wanji', 'com.toprankapps.secretphotofree', 'com.ttpod.music', 'com.tuyoo.chinesechess', 'com.ucweb.iphone', 'com.umonistudio.tapTile', 'com.uniview.app.smb.phone.ezview', 'com.wangfan.myChevy', 'com.weiying.Wvod', 'com.winzip.ios', 'com.WXTool.WXTool', 'com.wxxm.erpaoshou', 'com.xbzq.iphone.20101224', 'com.xiachufang.recipe', 'com.xianqing.ExcavatorCN', 'com.xianqing.parking3dcn', 'com.xianqing.Parking3DHD', 'com.xianqing.parking3dhdcn', 'com.xiaojukeji.didi', 'com.xiaoxiaov', 'com.xiaoyun.solitaire1124', 'com.xiaoyun.spiderpro', 'com.yeahworld.defendempire', 'com.YgCitylgMac.iPhone', 'com.yoho.buy', 'com.zhiliaoapp.musically', 'com.zhiliaoapp.musically.SQV9Z2C579', 'com.zhiliaoapp.musically.VQR5NX8778', 'com.zyzq.ths.iphone', 'linfengkun.NaviOne', 'net.beautyincorporated.fitnesssalon', 'net.tbet.qx', 'P02.tencent.xin', 'ph.spinnr.Spinnr', 'tongpengfei.piper', 'WiMax.WiMax-4G']
对应的请求次数如下, 可以看到大部分都是来自网易云音乐, 也比较合理, 毕竟这么老的设备, 估计就是拿来当离线播放器来用了. 其他的联网应用真的还有能用的么…
11651352 com.netease.cloudmusic
2110874 cn.com.10jqka.ipad
325326 com.apple.springboard
416339 cn.com.10jqka.IHexin
510035 com.luobocn.carrotfantasy2
69751 cn.com.doudizhu.happy
72743 cairot
82491 com.tencent.xin
92127 com.ilegendsoft.MBrowser
101498 com.htzq.ths.iphone
111424 com.gemd.iting
12955 com.tuyoo.chinesechess
13871 com.rovio.scn.baba
14696 com.ss.iphone.ugc.Aweme
15625 com.cn.greenbrowser
16487 com.cherrygame.majiang
17472 com.ilegendsoft.MBrowserPro
18387 com.autonavi.amap
19374 com.winzip.ios
20270 com.s5game.fishsaga
21266 com.hiddensweet.bubbleshooterhdfree
22261 com.kdanmobile.ipad.pdfreaderlite
23253 com.xiaoyun.solitaire1124
24180 com.starsea.wblock
25171 com.ttpod.music
26146 com.olimsoft.oplayer
2792 com.zhiliaoapp.musically
2877 com.baidu.TingIPhone
2973 ph.spinnr.Spinnr
3064 com.toprankapps.secretphotofree
3162 com.arcsoft.Perfect365
3262 com.iflytek.iflyinput
3362 com.xianqing.Parking3DHD
3457 com.olimsoft.oplayer.hd.lite
3556 cn.net.hzcaifeng.yb
3656 net.tbet.qx
3755 com.aemobile.games.sudoku
3855 com.dandan.DongHuaDuoDuo
3954 com.umonistudio.tapTile
4053 com.kdanmobile.ipad.PDFReader
4152 com.dtcsolutions.dtc
4249 cn.12306.rails12306
4344 com.xiaoyun.spiderpro
4442 com.xiachufang.recipe
4539 com.netease.videoHD
46... 剩下的请求次数比较少, 不写了
比较抽象的是还有 com.apple.springboard, 这个应该是 app 启动器? 不知道是怎么混进去的, 估计是来自的越狱的用户装了魔改版 springboard, 而恰巧这个做越狱应用的人用了被感染的 Xcode, 非常神奇了.
OS
大部分来自经典的 6.1.3,
1695007 6.1.3
2362126 9.3.6
3226928 7.1.2
4142910 10.3.4
583410 6.1.6
677440 12.5.7
735197 8.4
834599 8.0
932042 8.4.1
1018677 9.3.5
1111467 8.2
1211281 6.1.4
139226 8.3
147980 10.3.3
157511 12.5.5
165427 7.1.1
175411 7.0.4
185410 7.0.6
194839 8.0.2
204519 8.1.3
214308 8.1.2
224270 6.1
233837 6.0.1
24...
比较抽象的是在后面还有个请求了 10 次的 26.0, 手机型号是 iPhone 16, IP 归属是加拿大, 大受震撼.jpg, 不知道这是越狱之后改的系统属性, 还是是有人没事用脚本往这个地址发假请求?
机型
大部分都是经典 iPhone 4 系列, 真是老当益壮, 距离 14 年停产已经 11 年了
11027889 iPhone4,1
2153069 iPhone3,1
3122860 iPhone5,2
486142 iPod4,1
550750 iPhone3,2
649124 iPhone7,2
739761 iPhone3,3
835278 iPhone5,3
934477 iPad2,4
1027171 iPhone7,1
1127103 iPad4,7
1226750 iPhone6,2
1323244 iPad2,1
1420315 iPad3,4
1516310 iPad2,5
1615320 iPad4,1
1715097 iPad4,4
1813670 iPad3,1
1910569 iPhone5,1
209581 iPhone5,4
217362 iPad2,2
227322 iPhone6,1
236297 iPad3,3
243517 iPad5,3
253134 iPod5,1
262238 iPad3,6
271679 iPad2,7
281276 iPhone2,1
29700 iPod7,1
30504 iPhone8,2
31486 iPhone8,1
32423 iPad4,3
33417 iPad5,4
34409 iPad4,9
35363 iPhone9,1
36220 iPhone8,4
37188 iPad14,1
38171 iPad4,5
39167 iPad4,2
40152 iPhone12,8
41145 iPad3,5
42116 iPhone9,2
4392 iPhone13,1
4444 iPad3,2
45...
主机名 + 请求时间
以 8 月 29 日一天按小时的请求数量, 可以看出来还是符合中国人的作息的, 可以印证数据的真实性. 如果真的有人闲得没事用脚本往 C2 地址发假请求, 也没有达到可以影响统计结果的程度.
12025-08-29 00:00:00.000 3802
22025-08-29 01:00:00.000 2374
32025-08-29 02:00:00.000 1210
42025-08-29 03:00:00.000 848
52025-08-29 04:00:00.000 504
62025-08-29 05:00:00.000 554
72025-08-29 06:00:00.000 730
82025-08-29 07:00:00.000 1121
92025-08-29 08:00:00.000 1846
102025-08-29 09:00:00.000 3585
112025-08-29 10:00:00.000 4322
122025-08-29 11:00:00.000 3632
132025-08-29 12:00:00.000 3428
142025-08-29 13:00:00.000 4007
152025-08-29 14:00:00.000 4809
162025-08-29 15:00:00.000 3284
172025-08-29 16:00:00.000 3492
182025-08-29 17:00:00.000 3506
192025-08-29 18:00:00.000 3047
202025-08-29 19:00:00.000 3633
212025-08-29 20:00:00.000 3959
222025-08-29 21:00:00.000 4617
232025-08-29 22:00:00.000 5350
242025-08-29 23:00:00.000 5233
252025-08-30 00:00:00.000 3796
另外, 主机名也是很有活人感, 除了默认的 iPhone, 比如有类似 XXX我们复合吧T^T, XXX是sb, XXX的萌萌4s, 苹果16promax 这类抽象名称, 还是挺真实的. 基本可以判断这些数据大部分不是机器人刷的.
存活客户端数据级
由于 idfv 这个字段不同供应商开发的 app 获取的值不一样, 因此只能统计大致数量级, 这里以网易云音乐为例, 独特的 idfv 数量为 29818, 也就是说目前全世界存活的仍然可以受到 XcodeGhost 影响的终端仍然有大约 3w 之多.
总结
难以想象, 在 XcodeGhost 风波 10 年过去之后, 仍然有万级别的受害者仍然受到该漏洞影响, 好在这些用户估计只是把这些老设备当作音乐播放器, 就算真的有人劫持 DNS 尝试再利用这个后门, 也再无法掀起更大的波浪. 更有意思的我觉得还是这些废弃 C2 域名的善后措施, 这些购买域名的安全机构有些自身难保, 有些则在没有预告的情况下默默离开. 如果真的还有受影响的受害者, 此时又会暴露在危险之下, 不知道未来是否有更好的善后措施, 比如永久暂停某个域名的注册?
另外, 这两个域名我未来将会永久 302 到 https://github.com/XcodeGhostSource/XcodeGhost, 就让这件事漫漫消逝在历史长河中吧.