การเจลเบรก iPhone 4 ตอนที่ 1: การหาช่องทางเริ่มต้น
(axleos.com)- gala เป็นโปรเจ็กต์ที่ลงมือสร้างการเจลเบรก iOS 4 สำหรับ iPhone 4 โดยตรง และตอนที่ 1 มุ่งเน้นไปที่กระบวนการได้มาซึ่ง การรันโค้ดเริ่มต้น โดยอาศัยช่องโหว่ใน SecureROM ของอุปกรณ์รุ่นเก่า
- การบูตของ iOS เริ่มจาก SecureROM ตรวจสอบ LLB หรือ iBSS แล้วแต่ละขั้นจะตรวจสอบขั้นถัดไปต่อเป็น ห่วงโซ่ความเชื่อถือ และ SecureROM ไม่สามารถถูกแทนที่ด้วยการอัปเดตหลังการผลิตได้
- limera1n โจมตี SecureROM ของ A4 SoC กับอุปกรณ์ที่อยู่ในโหมด DFU ระหว่างรอรับ iBSS โดยดูเหมือนว่าการแครชที่พบจากการทำ USB control message fuzzing จะนำไปสู่ heap overflow และการรันเชลล์โค้ด
- โดยอ้างอิง SecureROM dumper ของ pod2g มีการนำโฟลว์ที่ใช้พื้นที่สื่อสาร
0x84000000และคำขออ่าน USB0xA1:2เพื่อดึง SecureROM dump และค่าดีบักกลับมายังโฮสต์มาสร้างใหม่ - มีการสร้างไปป์ไลน์ที่เขียนเพย์โหลดด้วย Rust แล้วดึงเชลล์โค้ดออกจาก
__TEXT,__textของ Mach-O มารัน แต่เมื่อสตริงแบบสแตติกถูกวางไว้ใน__constจึงจำเป็นต้องใช้ การอ้างแอดเดรสแบบสัมพันธ์กับ instruction pointer และการจัดวางด้วยแอสเซมบลี
จุดเริ่มต้นของโปรเจ็กต์เจลเบรก iPhone 4
- gala เป็นโปรเจ็กต์สำหรับสร้าง การเจลเบรก iOS 4 สำหรับ iPhone 4 และเอกสารนี้คือส่วนที่ 1 “Gaining Entry”
- ประสบการณ์ก่อนหน้านี้ในการพัฒนา iOS tweak ต่อเนื่องมาจนถึงการแจกจ่ายผ่าน Cydia, การปรับเปลี่ยนฟังก์ชันของ SpringBoard, การใช้งาน Objective-C runtime โดยตรง และการทำรีเวิร์สเอนจิเนียริงไบนารีปิดซอร์ส
- เป้าหมายของการเขียนเจลเบรกด้วยตัวเองคือเพื่อทำความเข้าใจว่ากระบวนการเจลเบรกทำงานจริงอย่างไร
- งานนี้พึ่งพาความรู้ที่ p0sixninja และ axi0mX เผยแพร่เป็นโอเพนซอร์สอย่างมาก
การเลือก iPhone รุ่นเก่าและช่องโหว่ Boot ROM
- ขั้นตอนแรกคือซื้อ iPhone 4 และ iPhone 3GS จาก eBay
- เนื่องจาก Xcode รุ่นใหม่ไม่ยอมให้กำหนดเป้าไปยัง iOS เวอร์ชันเก่า เส้นทางการสร้างและติดตั้งแอปแบบยุค 2010 จึงถูกปิดตายอย่างรวดเร็ว
- มีการพิจารณาติดตั้ง Mac OS X และ Xcode รุ่นเก่าใน VM เช่นกัน แต่สุดท้ายก็หยุดไว้
- ยังไม่ชัดเจนว่า Apple จะยังเซ็นไบนารีสำหรับเป้าหมาย iOS รุ่นเก่าอยู่หรือไม่
- ทางเลือกคือมุ่งโจมตี ช่องโหว่ใน Boot ROM โดยตรง
- สามารถลองได้ด้วยโค้ดที่โต้ตอบกับอุปกรณ์ผ่าน USB จากเครื่องโฮสต์ โดยไม่ต้องใช้ toolchain เก่าหรือ VM
- ในหัวข้อ
Vulnerabilities and Exploitsของ iPhone Wiki พบโค้ดเอ็กซ์พลอยต์ limera1n
SecureROM และห่วงโซ่ความเชื่อถือของการบูต iOS
- ตามคำศัพท์ของ Apple, SecureROM คือขั้นแรกของกระบวนการบูต iOS และเป็นตัวเริ่มขั้นตอนบูตถัดไป
- SecureROM สามารถโหลดได้สององค์ประกอบ
- ในการบูตปกติ จะบูต
Low Level Bootloaderหรือ LLB จากดิสก์พาร์ทิชันใน NOR - หากเชื่อมต่อกับคอมพิวเตอร์ผ่าน USB ในโหมด DFU ก็สามารถรับบูตโหลดเดอร์
iBoot Single Stageหรือ iBSS ระหว่างกระบวนการRestore iPhoneได้
- ในการบูตปกติ จะบูต
- SecureROM จะตรวจสอบว่า LLB หรือ iBSS เป็นอิมเมจที่เชื่อถือได้และมีลายเซ็นจาก Apple หรือไม่
- หลังจากนั้น LLB และ iBSS ก็จะตรวจสอบขั้นตอนถัดไปที่ตนโหลดเช่นกัน จนเกิดเป็น ห่วงโซ่ความเชื่อถือ
- เนื่องจาก SecureROM เป็นขั้นแรก จึงไม่ได้ถูกตรวจสอบโดยขั้นก่อนหน้า และถูกสลักไว้ในหน่วยความจำแบบอ่านอย่างเดียวตั้งแต่การผลิต
- ขั้นตอนอื่น ๆ สามารถถูกแทนที่ได้ด้วยการอัปเดต iOS
- ช่องโหว่ใน SecureROM เวอร์ชันใดจะคงอยู่ถาวรในอุปกรณ์ที่ผลิตมาพร้อมเวอร์ชันนั้น
การได้มาซึ่งการรันโค้ดบนอุปกรณ์ DFU ด้วย limera1n
- limera1n คือเอ็กซ์พลอยต์ SecureROM ที่ geohot เปิดเผยในปี 2010 และถูกแพ็กเป็นเครื่องมือเจลเบรกชื่อเดียวกัน
- สามารถใช้ limera1n ได้ตอนที่อุปกรณ์ในโหมด DFU กำลังรอรับ iBSS จากโฮสต์ผ่าน USB
- เพราะ SecureROM ที่รวมอยู่ใน A4 SoC มีช่องโหว่ iPhone 4 จึงเป็นเป้าหมายที่เหมาะสม
- กลไกการทำงานที่แน่ชัดของ limera1n ยังไม่ได้ถูกอธิบายไว้อย่างสมบูรณ์ในที่สาธารณะ
- geohot บอกว่าไม่รู้ว่าทำไมมันถึงทำงาน
- p0sixninja ได้คาดเดาทฤษฎีไว้
- การแครชถูกค้นพบจากการทำ USB control message fuzzing และดูคล้าย race condition ที่นำไปสู่ heap overflow ซึ่งทำให้สามารถฉีดและรันเชลล์โค้ดได้
การอ่านหน่วยความจำจากอุปกรณ์ในโหมด DFU
- SecureROM dumper ของ pod2g เป็นตัวอย่างอ้างอิงที่แสดงทั้งการติดตั้ง limera1n, ตัวอย่างเพย์โหลด และวิธีอ่านหน่วยความจำผ่าน USB
- SecureROM dumper จะคัดลอกหน่วยความจำ
0x0ที่แมป SecureROM อยู่ไปยังพื้นที่รับข้อมูล USB แล้วให้โฮสต์อ่านข้อมูลผ่าน USB control message - โฟลว์ที่เข้าใจได้มีดังนี้
- MMU ของ A4 แมปจุดเริ่มต้นของ SRAM ไว้ที่
0x84000000 - โฮสต์สามารถส่ง iBSS image เป็นชิ้น ๆ ด้วยแพ็กเก็ตควบคุม USB ที่มี
request type 0x21,request ID 1 - ข้อมูลนี้จะถูกคัดลอกลง SRAM ตั้งแต่
0x84000000และ SecureROM จะเก็บตัวนับภายในเพื่อติดตามตำแหน่งคัดลอกของแพ็กเก็ตถัดไป - อุปกรณ์ยังตอบสนองต่อแพ็กเก็ตควบคุม
request type 0xA1,request ID 2และจะส่งเนื้อหาหน่วยความจำของ0x84000000กลับไปยังโฮสต์
- MMU ของ A4 แมปจุดเริ่มต้นของ SRAM ไว้ที่
- ความสามารถในการอ่านนี้มีประโยชน์มากเมื่อสามารถรันโค้ดบนอุปกรณ์ได้แล้ว
- เพย์โหลดจะคัดลอกข้อมูลที่ต้องการไปยัง
0x84000000 - โฮสต์สามารถดึงข้อมูลนั้นกลับมาได้ด้วยคำขออ่าน
A1:2
- เพย์โหลดจะคัดลอกข้อมูลที่ต้องการไปยัง
- สไลด์จากงาน Hack In the Box Malaysia ปี 2013 ของ p0sixninja ระบุว่า SecureROM dumper ของ pod2g ใช้ SHAtter เป็นฐาน แต่ยูทิลิตีจริงใช้การติดตั้ง limera1n
- มีความสำเร็จในการทำ SecureROM dump ด้วยการติดตั้ง limera1n ของตัวเอง
การดีบักเพย์โหลดด้วย 0x84000000
- หลังได้การรันโค้ดแล้ว สิ่งที่ต้องตรวจสอบคือเชลล์โค้ดรันอยู่ตรงไหน สแตกอยู่ตรงไหน และเชลล์โค้ดกำลังเขียนทับหน่วยความจำใดบ้าง
- มีการนำโฟลว์การอ่านของ SecureROM dumper มาใช้ซ้ำสำหรับแสดงผลดีบัก
- เพย์โหลดจะคัดลอกค่า instruction pointer และ stack pointer ไปยัง
0x84000000 - โค้ดฝั่งโฮสต์จะอ่านค่ากลับมาด้วยวิธีเดียวกัน
- วิธีนี้ทำหน้าที่เสมือน
print()แบบง่าย ๆ ผ่าน memory dump
- เพย์โหลดจะคัดลอกค่า instruction pointer และ stack pointer ไปยัง
- สคริปต์อัตโนมัติจะดัมพ์เวิร์ดไม่กี่ตัวแรกของ
0x84000000หลังรันเอ็กซ์พลอยต์แล้วแสดงในหน้าต่างเอาต์พุต - ค่าที่ตรวจสอบได้แสดงตำแหน่งการรันของเชลล์โค้ดและตำแหน่งของสแตก
- instruction pointer อยู่ใกล้
0x8402b048 - stack pointer คือ
0x8403bfa0 - stack pointer อยู่ภายในพื้นที่สแตกปกติที่ SecureROM ตั้งค่าไว้ และ instruction pointer อยู่ในพื้นที่อิมเมจที่รับเข้ามา
- instruction pointer อยู่ใกล้
เพย์โหลด Rust และการดึงเชลล์โค้ดจาก Mach-O
- แทนที่จะเขียนเพย์โหลดด้วยแอสเซมบลีล้วน มีการจัดระบบบิลด์ที่สร้าง เพย์โหลด Rust แล้วแปลงเป็นเชลล์โค้ด
- Rust เลิกซัพพอร์ตเป้าหมาย
armv7-apple-iosไปแล้วตั้งแต่ต้นปี 2020 แต่ยังสามารถสลับไปใช้ toolchain รุ่นเก่าที่รองรับได้ด้วยrustup - เมื่อคอมไพล์ด้วยภาษาระดับสูง จะได้ไบนารีที่มีทั้งเมทาดาทา ข้อมูลการตั้งค่าพื้นที่แอดเดรสเสมือน symbol table และข้อมูลของลิงเกอร์ ไม่ได้มีแค่ machine code ดิบ
- สำหรับเอ็กซ์พลอยต์ ต้องการเพียงไบต์ที่จะฉีดเข้าไปในหน่วยความจำแล้วกระโดดไปทำงานเท่านั้น จึงไม่ต้องใช้ Mach-O ทั้งไฟล์ แต่ใช้เพียงเซกชัน
__textของเซกเมนต์__TEXT - strongarm เป็นไลบรารีวิเคราะห์ Mach-O และถูกใช้ในระบบบิลด์เพื่อพาร์ส Mach-O แล้วดึงเซกชัน
__TEXT,__textออกเป็นไฟล์ - ไบต์ของไฟล์ที่ดึงออกมาจะกลายเป็นเชลล์โค้ดที่ limera1n ใช้รันบนอุปกรณ์
ปัญหาลิงเกอร์และข้อมูลสแตติก
- ไบนารีทั่วไปใช้โครงสร้างพื้นฐานของ OS และข้อตกลงเรื่องสัญลักษณ์จุดเข้าอย่าง
startหรือ_mainแต่สำหรับการใช้งานเชลล์โค้ดนี้ไม่จำเป็นต้องมีสัญลักษณ์เหล่านั้น - ลิงเกอร์จะรายงานข้อผิดพลาดโดยปริยายหากไม่มี
_mainหรือstart - สามารถสร้างไฟล์ Mach-O ที่ไม่ใช้ dyld ได้ด้วยการผสมตัวเลือก
-U _main,-U start,-static - ในตอนแรก strongarm ไม่สามารถจัดการไบนารีที่ไม่มี load command
LC_DYLD_INFOและโยน exception ออกมา- ไบนารีนี้ไม่มี
LC_DYLD_INFOเพราะไม่ได้ใช้ dyld - มีการเพิ่มแพตช์ ให้ strongarm รองรับกรณีนี้
- ไบนารีนี้ไม่มี
- เมื่อเพิ่มสตริงแบบสแตติกลงในโค้ด Rust เพย์โหลดกลับพัง
- สตริงสแตติกที่คอมไพล์แล้วจะถูกวางไว้ใน
__const - กระบวนการดึงเชลล์โค้ดเก็บไว้แค่
__TEXT,__textดังนั้นข้อมูล__constจึงไม่ได้ถูกโหลดเข้าไปในหน่วยความจำ - ผลคือโค้ดพยายามอ่านสตริงจากแอดเดรสที่ไม่ได้แมปและแครช
- สตริงสแตติกที่คอมไพล์แล้วจะถูกวางไว้ใน
- วิธีแก้คือรวมข้อมูลสแตติกไว้ภายใน
__TEXT,__textและใช้ การอ้างแอดเดรสแบบสัมพันธ์กับ instruction pointer เพื่อไม่ต้องสมมติแอดเดรสโหลดที่ตายตัว - วิธีที่ใช้อยู่ตอนนี้คือกำหนดสตริงในแอสเซมบลีแล้วส่งแอดเดรสของมันเข้าสู่ entrypoint ของเพย์โหลด Rust
ไปป์ไลน์การรันที่เสร็จสมบูรณ์ในตอนที่ 1
- ไปป์ไลน์สุดท้ายทำงานตามลำดับดังนี้
- แก้ไขเพย์โหลด Rust
- กดปุ่มเพื่อคอมไพล์เพย์โหลด
- ดึงเชลล์โค้ดออกจากไบนารี
- ตัวรันใช้ limera1n รันเพย์โหลดบน iPhone ในโหมด DFU ที่เชื่อมต่ออยู่
- ตัวรันอ่านข้อมูลจาก
0x84000000ที่ใช้เป็นพื้นที่สื่อสารโดยอัตโนมัติ แล้วแสดงเป็น hexdump
- ณ จุดนี้สามารถรันโค้ดตามต้องการบนอุปกรณ์ได้แล้ว
- การรันโค้ดตามต้องการทำให้ในทางทฤษฎีสามารถทำอะไรได้มากมาย แต่การทำให้อุปกรณ์ทำสิ่งที่น่าสนใจจริง ๆ ยังเป็นอีกขั้นตอนหนึ่งต่างหาก
- ขั้นต่อไปจะต่อเนื่องไปยัง Part 2: Bypassing the Bootchain
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
หลังจากอ่านอย่างเดียวมาหลายปี ในที่สุดก็สมัครบัญชี Hacker News เพื่อมาพูดสิ่งนี้ ขอบคุณที่เรียบเรียงเรื่องที่เป็น กล่องดำลึกลับ สำหรับผู้คนจำนวนมากมายาวนานได้แบบนี้
ยังจำได้ชัดว่าตอนเจลเบรก iPod 4G ที่รัน iOS 4 เครียดมากแค่ไหนตอนมองข้อความในเทอร์มินัลไหลขึ้นมาเป็นแถบ ๆ หลังจากนั้นตอนพักเที่ยงที่โรงเรียนก็ช่วยทำให้เครื่องของเพื่อน ๆ ด้วย และกังวลว่าจะพลาดจนทำโทรศัพท์พังกลายเป็น เครื่องทับกระดาษราคาเป็นร้อยดอลลาร์
พอมองย้อนกลับไปหลังผ่านมาหลายปี “เวทมนตร์” ของการเจาะกำแพง Apple แล้วรันโค้ดของผู้ใช้ได้นี่แหละที่ทำให้ผมหลงใหลการเขียนโปรแกรม และรู้สึกขอบคุณทุกคนที่เกี่ยวข้องอย่างยิ่ง
ขอบคุณมากสำหรับบทความ ต้องเข้าใจลึกจริง ๆ ถึงจะอธิบายแนวคิดที่ซับซ้อนแบบนี้ให้ง่ายได้ อ่านแล้วนึกถึงความทรงจำดี ๆ ตอนนั่งแฮ็ก โปรเจกต์เจลเบรก จนดึกดื่น
อ่านเพลินมากตลอดทั้งบทความ โดยเฉพาะเพราะผมยังไม่ค่อยถนัด การทำวิศวกรรมย้อนกลับโค้ดเนทีฟ
ดูเหมือนนี่จะเป็น การเจลเบรกแบบ tethered เพราะใช้กลไกกู้คืนระบบเพื่อทำลาย chain of trust แล้วบูต iOS ที่ถูกแก้ไข ถ้าอย่างนั้นก็สงสัยว่าเจลเบรกแบบ untethered ทำงานอย่างไร มันเป็นวิธีที่ไม่แตะต้องและไม่ข้าม secure boot chain เลย แต่ exploit โปรเซสที่มีสิทธิ์หรือไม่มีสิทธิ์ในระบบที่กำลังรันอยู่ แล้วค่อยยกระดับสิทธิ์แยกต่างหากใช่ไหม แล้วทำ persistence อย่างไร และแพตช์การตรวจลายเซ็นของเคอร์เนลได้อย่างไรโดยไม่แตะการตรวจลายเซ็นของ bootloader กับตัวเคอร์เนลเอง
บทความยอดเยี่ยมจริง ๆ ดีใจที่เห็นว่ายังมีส่วนร่วมในคอมมูนิตี้อยู่
ขอบคุณที่ทำสิ่งนี้ขึ้นมา ผมมี iPhone 4s ที่มีรูปพิเศษอยู่เยอะมาก แต่บังเอิญลืม PIN เลยอยู่ในสภาพที่ต้องรอมาหลายปีแล้ว
ถ้าไม่ใช่เพราะรูป ก็คงรีเซ็ตเครื่องไปแล้ว สงสัยว่าสิ่งนี้จะใช้รีเซ็ต PIN แล้วคัดลอกรูปออกมาได้ไหม
แก้ไข: ผมอาจเข้าใจผิดก็ได้ ใน [0] ยังบอกด้วยว่ามีช่วงหนึ่งที่มีแค่ที่เก็บ Mail เท่านั้นที่ถูกเข้ารหัส และค่าเริ่มต้นเปลี่ยนใน iOS 7 ดังนั้นถ้า iPhone รัน iOS <= 6 วิธีนี้อาจทำให้เข้าถึงเครื่องและคัดลอกรูปได้ เครื่องมือใน [1] อาจช่วยได้
[1] https://code.google.com/archive/p/iphone-dataprotection/
[0] https://darthnull.org/ios-encryption/
เป็นบทความที่ดีมากจริง ๆ แต่ฉากที่อินเทอร์เฟซ iOS รุ่นเก่าโชว์ความรุ่งโรจน์ของ ดีไซน์แบบ skeuomorphic ทำเอาผมรู้สึกขัดใจขึ้นมาเลย ทำให้รู้สึกอีกครั้งว่าไม่ชอบ John Ive ขนาดไหน
บางที Jony น่าจะออกแบบที่พักข้อมืออะลูมิเนียมคมเหมือนใบมีดต่อไป มากกว่ามาดูแลซอฟต์แวร์
อ่านช่วงต้น ๆ หลายตอนแล้วสนุกมาก การตามเรื่องจากมุมมองแบบนี้เจ๋งดี ผมเองก็อ่านซอร์สโค้ดเยอะมากเพื่อหาว่าคนอื่นสร้างสิ่งอย่าง exploit กันอย่างไร ดีใจที่มีคนอื่นทำแบบนั้นเหมือนกัน
ยังไม่ได้อ่าน แต่ตั้งตารอเลย ทวีค ที่ไล่มาตอนต้นผมเคยใช้ทั้งหมด และอยากบอกว่าขอบคุณที่สร้างมันขึ้นมา การเจลเบรก iOS ยุคแรก ๆ สนุกมากจริง ๆ
ดีมากเลย พยายามจะลองรันดู แต่น่าเสียดายที่เครื่องเก่าของผมบูตไม่ขึ้นตั้งแต่แรก
ตอนนั้นผมก็ทำทวีคเหมือนกัน และรู้สึกว่าเจลเบรกเป็นเหมือน มนตร์ดำ อ่านบทความนี้แล้วก็ยังรู้สึกแบบนั้นอยู่ในระดับหนึ่ง
ขอบคุณมากจริง ๆ ที่เรียบเรียงเรื่องนี้ ผมสนใจเรียนรู้เนื้อหาแบบนี้มาก โดยเฉพาะอยากเรียนรู้วิธี “ปลดปล่อย” กล้องรักษาความปลอดภัย Wi-Fi ราคาถูกอย่าง dafang-hacks ด้วยเฟิร์มแวร์ที่ปรับแต่งเอง หรือสร้าง exploit ใหม่เพื่อรูทแท็บเล็ต Kindle Fire
แต่บทความที่ลงรายละเอียดกระบวนการนั้นกลับหายากอย่างน่าประหลาดใจ