Jailbreak Switch 2: Rantai Exploit yang Tembus Secure Boot
Jailbreak Switch 2 menggabungkan overflow interpreter BASIC, bug path fs, dan race loader. Ini pelajaran soal rantai exploit dan secure boot.

Konsol baru dikirim dengan microkernel yang diperkeras, pointer authentication di setiap return address, memori execute-only, control-flow integrity, dan boot chain yang ditandatangani. Dua minggu kemudian, seorang hobiis sudah menjalankan native code sembarang sebagai layanan filesystem, proses paling tepercaya di perangkat itu. Itulah kisah jailbreak publik pertama Switch 2, dan seharusnya membuat setiap engineer yang membangun sistem aman sedikit tidak nyaman. Bukan karena mitigasinya gagal, sebagian besar justru bekerja persis seperti yang dirancang, tetapi karena exploit ini tidak perlu mengalahkan mereka secara langsung. Ia memutarinya, satu bug logika dalam satu waktu.
Saya sudah bertahun-tahun di sisi defensif keamanan infrastruktur, dan pola di sini sering saya temui di review insiden produksi lebih banyak dari yang saya mau: rantai bug yang masing-masing tidak terlalu mengesankan, dan tiap bug hanya memberi cukup privilege untuk mencapai tahap berikutnya. Pijakan awalnya bahkan bukan di Switch 2 sendiri. Itu adalah bug memory corruption di game Switch 1, yaitu interpreter SmileBASIC, yang berjalan dalam mode kompatibilitas mundur. Dari sana rantai naik melalui layanan filesystem, memanfaatkan race di program loader, dan berakhir dengan kemampuan menjalankan native code di bawah identitas sysmodule mana pun. Setiap mata rantai layak diperhatikan, karena masing-masing terkait dengan kesalahan yang pernah saya lihat dilakukan tim di sistem server juga.
Mengapa Pintu Browser Tertutup, dan Pintu Game Tidak
WebKit adalah target klasik pertama untuk jailbreak konsol, dan peneliti memang mendapat pijakan di sana lewat captive portal dan n-day. Tapi jalurnya buntu dengan cepat. Stack browser Switch 2 dibungkus tiga mitigasi yang saling melengkapi dengan sangat efektif: execute-only memory (XOM) berarti meskipun kamu punya read/write sembarang, kamu tetap tidak bisa menemukan gadget kode yang berguna; pointer authentication (PAC) berarti kamu tidak bisa memalsukan code pointer tanpa signing oracle; dan CFI berarti pointer yang sah sekalipun tidak lolos pengecekan tipe di sebagian besar call site. Menembus salah satu saja sudah jadi proyek riset. Menembus ketiganya sekaligus, dari sandbox JavaScript, adalah karier.
Jadi serangan beralih ke penyewa paling lemah di mesin itu: game Switch 1 pihak ketiga. Logikanya dingin dan tepat. Binary game dibangun oleh studio, bukan oleh tim keamanan Nintendo, sehingga jauh lebih kecil kemungkinannya dikompilasi dengan stack mitigasi lengkap. Switch 1 memang tidak pernah punya PAC, jadi apa pun yang berjalan di lingkungan kompatibilitasnya ikut mewarisi kelemahan itu. Lebih baik lagi, root of trust Switch 1 sudah dibobol bertahun-tahun lalu, artinya kode game-nya bisa didekripsi dan diaudit secara offline. SmileBASIC, interpreter BASIC C++ raksasa yang sudah pernah dieksploitasi di 3DS, adalah target lunak yang jelas.
Ada pelajaran di sini yang berlaku jauh melampaui konsol: postur keamananmu adalah postur keamanan dari kode yang paling sedikit diperkeras yang kamu setujui untuk dijalankan. Kompatibilitas mundur adalah attack surface yang kamu warisi, bukan yang kamu pilih. Model keamanan Xbox belajar hal ini dengan susah payah di tahun 2000-an. Exploit saved-game di judul yang tidak diperkeras menjadi celah yang membobol kernel jauh lebih ketat, dan cerita itu pernah kami bahas di apa yang diajarkan hack Xbox asli tentang model keamanan hardware. Dua puluh tahun kemudian, trik yang sama masih berhasil.
Integer Overflow yang Membuka Pintu Pertama
Bug SmileBASIC adalah integer overflow klasik dalam bounds checking, jenis yang ada di setiap checklist secure code review, dan jenis yang tetap saja lolos ke produksi. Perintah penghapusan array di interpreter memvalidasi argumennya seperti ini:
// intent: ensure the removed range is inside the array
if (position + count <= array.length) {
memmove(backing + position * 8, // start of the gap
backing + (position + count) * 8, // elements after the gap
(length - position) * 8); // bytes to copy
}
Panggil REMOVE R, &H60000000, &H3FFFFFFF pada array empat elemen, dan position + count membungkus menjadi 0x9FFFFFFF, yang sebagai nilai signed 32-bit adalah angka sangat negatif, jelas "lebih kecil" dari panjangnya. Perkalian dengan 8 juga ikut overflow, dan akhirnya kamu mengeksekusi memmove(backing, backing - 8, 32). Perintah itu menampilkan error out-of-memory setelahnya, tapi penyalinannya sudah terjadi. Dan bagian indahnya: 8 byte tepat sebelum array SmileBASIC mana pun menyimpan pointer ke array itu sendiri. Setelah penghapusan, R[0] ditafsirkan sebagai string yang field panjangnya sebenarnya berisi pointer tadi, yaitu string yang panjangnya astronomis dan bisa kamu baca serta tulis. Read/write sembarang, dibungkus rapi seperti kado oleh tata letak memori interpreter itu sendiri.
Kalau kamu menulis C atau C++ untuk mencari nafkah, pandangi check itu sebentar. position + count <= length adalah idiom bounds-check paling umum di kode sistem, dan salah setiap kali penjumlahannya bisa overflow. Bentuk yang benar adalah position <= length && count <= length - position, atau aritmetika yang dicek. Saya pernah menemukan varian bug ini di packet parser di pekerjaan sebelumnya dan di storage engine open-source. Bug ini lolos code review karena kelihatannya jelas benar. Ini adalah celah spesifikasi-implementasi dalam bentuk mini: spesifikasinya berkata "validasi rentangnya", implementasinya memvalidasi sesuatu yang bersebelahan dengan rentang itu, dan selisihnya bisa dieksploitasi. Kami pernah menulis tentang celah spesifikasi-implementasi, tempat bug bersarang. Interpreter konsol hanyalah tempat bug-bug ini ditemukan oleh remaja yang termotivasi, bukan oleh fuzzer.
Eskalasi ke Layanan Filesystem dengan Overflow Penanganan Path
Read/write di userspace dalam proses game tidak banyak gunanya sendirian, karena desain microkernel Switch berarti setiap layanan adalah proses terpisah dengan permukaan IPC sendiri. Target yang berharga adalah fs, sysmodule filesystem bawaan, karena alasan yang rekursif dan menyenangkan: fs adalah komponen yang menyajikan kode yang sudah didekripsi ke loader. Kuasai fs dan kamu bisa membuang kode semua sysmodule lain untuk dianalisis offline. Quartermaster benteng itu sendiri yang menyerahkan cetak birunya padamu.
Bug-nya adalah heap overflow di path normalization. Perintah IPC GetEntryType menormalisasi argumen path-nya, dan path yang mengandung komponen parent-directory dengan backslash, yaitu /..\, masuk ke helper yang mengalokasikan buffer tetap 0x301 byte lalu menyalin path ke dalamnya tanpa pengecekan panjang yang memadai. Path yang cukup panjang akan meluap ke objek heap di sebelahnya. Komentar si peneliti saat menemukan ini hanya satu kata: "lol."
"lol" itu seharusnya terasa menyakitkan, karena path normalization adalah jenis kode plumbing yang membosankan dan tidak pernah mendapat pengawasan keamanan seperti yang didapat kode kriptografi. Exploit ini mengubah overflow menjadi read/write sembarang penuh dengan merusak objek cache tetangga yang dirty bit-nya mengalihkan I/O file lewat pointer yang dikendalikan penyerang, sebuah primitif heap-grooming yang rapi. Lalu, dengan memindai memori, exploit menemukan objek koneksi prosesnya sendiri di tabel fs dan menulis ulang process ID yang tersimpan menjadi 1, memberi proses game "FullPermission" atas filesystem. Perhatikan apa yang baru terjadi: tidak ada satu pun pengecekan kriptografi yang dibobol. Model permission ditegakkan oleh data di memori, dan penyerang bisa menulis memori.

Melewati Pemeriksaan Tanda Tangan dengan Menukar Filesystem di Tengah Jalan
Mata rantai paling cerdik adalah yang mengalahkan code signing tanpa menyentuh satu kunci pun. Program loader (ldr) memverifikasi dua tanda tangan sebelum menjalankan apa pun: tanda tangan Nintendo atas metadata permission proses dan kunci developer, serta tanda tangan developer atas hash header arsip konten. Secara teori, hash itu secara transitif mengunci setiap byte executable. Dalam praktik, ada celah: tugas fs adalah memastikan filesystem yang disajikannya benar-benar cocok dengan hash yang sudah dilaporkannya, dan penyerang punya read/write sembarang di dalam fs.
Jadi exploit menunggu sampai loader meminta filesystem executable dan fs sudah menyerahkan hash dan tanda tangan yang valid. Setelah itu ia menukar objek filesystem di balik handle IPC loader dengan objek buatan yang menyajikan file metadata bertanda tangan asli tetapi executable pengganti yang sembarang. Pemeriksaan tanda tangan lolos karena yang diperiksa adalah byte yang tidak perlu dimodifikasi penyerang. Waktunya diatur dengan menulis ulang handle yang ditunggu fs untuk koneksi loader menjadi event yang dikendalikan penyerang dari proses game, sehingga race condition berubah menjadi interposisi yang deterministik.
Rantai kriptografinya sebenarnya kokoh dari hash header hingga isi executable, di atas kertas. Satu-satunya mata rantai yang hanya berupa asumsi runtime, yaitu 'proses yang menyajikan file itu jujur', justru itulah yang jebol.
Ini adalah bug time-of-check/time-of-use yang menyamar, dan ini pelajaran paling bisa dipindahkan ke konteks lain di seluruh tulisan ini. Setiap kali komponen A memvalidasi data dan komponen B kemudian bertindak berdasarkan data itu lewat referensi yang bisa berubah, kamu punya jendela tukar. Saya pernah meninjau sistem deployment internal yang memvalidasi digest image container, lalu melakukan pull berdasarkan tag dari registry saat rollout. Bug yang sama, topi yang berbeda. Perbaikannya di kedua kasus sama: validasi di titik penggunaan, atau berikan konsumen objek yang immutable dan sudah terverifikasi, bukan handle ke sesuatu yang harus dia percayai tetap jujur oleh pihak ketiga. Desain defensif yang berasumsi setiap perantara sudah terkompromi bukanlah paranoia. Di mesin yang sudah bisa sebagian ditulis penyerang, itu sekadar pemodelan yang akurat. Itulah inti argumen di rekayasa defensif untuk sistem yang tahan terhadap bencana, dan exploit ini adalah studi kasus yang bersih.
Meminjam Handle Kernel dan Menambal fs dari Dalam
Trik terakhirnya kecil dan indah. Untuk menambal kode proses fs itu sendiri, exploit memerlukan handle kernel ke proses tersebut. Ia mendapatkannya dengan menimpa field handle 4-byte di memori dengan nilai ajaib 0xffff8001, yang oleh kernel ditafsirkan sebagai "handle proses saat ini". Proses game memanggil API jinak, menerima kembali handle proses miliknya sendiri, dan mengirimkannya ke proses nakal yang berjalan dengan permission sysmodule pemuat kode. Proses itu lalu menggunakan panggilan kernel yang sah untuk memetakan dan menambal kode fs. Setiap operasi individual diotorisasi. Komposisinya adalah kompromi penuh atas proses paling tepercaya di perangkat.
Kalau ini terdengar familiar, itu karena masalah confused deputy ada di mana-mana begitu kamu mulai mencari: aturan sudo yang mengizinkan binary jinak dengan config yang bisa ditulis, role IAM cloud yang bisa meneruskan dirinya ke layanan yang lebih kuat, dan sistem build yang menandatangani apa pun yang diberikan job CI. Kami sudah membahas sisi privilege escalation dari pola ini di sejarah privilege escalation di Unix. Mekanismenya berubah, bentuk bugnya tidak. Handle, capability, dan token hanya sekuat integritas memori yang menyimpannya.
Kesalahan yang Terus Dilakukan Desainer Secure Boot
Mundur sedikit dan polanya konsisten di seluruh rantai ini. Pola yang sama ada di balik sebagian besar breach enterprise serius yang pernah saya tinjau: inti yang terverifikasi bertahan, dan segala sesuatu di sekitarnya tidak. Boot ROM Nintendo, skema tanda tangan, dan mitigasi kernel-nya baik-baik saja. Yang jebol adalah bounds check interpreter, buffer path-normalization, field permission yang disimpan di memori yang bisa ditulis, jendela TOCTOU antara dua layanan tepercaya, dan tabel handle yang mengambil pointer kernel dari struktur yang bisa ditulis userspace. Tidak satu pun dari ini eksotis. Semuanya jenis hal yang lolos review karena setiap bagian terlihat wajar secara lokal.
- Audit kode yang membosankan. Path normalizer, pengecekan panjang, dan tabel handle adalah tempat rantai exploit benar-benar dimulai, bukan kriptografinya. Alokasikan waktu review sebanding dengan keterjangkauan oleh penyerang, bukan dengan kecanggihan algoritmanya.
- Perlakukan setiap celah mitigasi sebagai peta jalan. Jika satu proses di sistem tidak punya PAC/CFI, misalnya lapisan kompatibilitas, binary pihak ketiga, atau interpreter lama, anggap itu titik masuknya dan modelkan apa yang bisa dijangkaunya.
- Hilangkan trust-by-position. Komponen yang memvalidasi data lalu menyerahkan handle yang bisa diubah ke hilir sudah menciptakan jendela tukar. Berikan objek yang immutable dan bisa memverifikasi dirinya sendiri, atau verifikasi ulang saat digunakan.
- Anggap memori yang bisa ditulis di mana pun sebagai memori yang bisa ditulis di mana saja. Flag permission, field PID, dan nilai handle yang disimpan di memori yang bisa dijangkau penyerang adalah bagian dari attack surface-mu, bukan mekanisme penegakannya.
Kesimpulan tidak nyaman lainnya ada di sisi tooling. Exploit ini dikembangkan dengan agen AI yang diberi akses fisik ke hardware lewat perangkat KVM-over-IP: video masuk, input controller lewat USB, dan gadget tuas Bluetooth untuk menekan tombol power setelah setiap crash. Beberapa instans agen menggarap permukaan serangan berbeda secara paralel, sepanjang waktu, selama dua minggu. Apa pun pendapatmu tentang riset keamanan berbantuan AI, ekonomi penemuan kerentanan di hardware tertutup sudah berubah. Bug yang dulu butuh ahli yang sabar kini butuh ahli yang sabar dan mampu mengawasi tiga asisten yang tidak pernah lelah. Jika threat model-mu berasumsi "tidak ada yang mau repot membalik-rekayasa sysmodule ini", asumsi itu sudah kedaluwarsa bulan ini.
Rantai Itulah Produknya
Godaan terbesar saat membaca tulisan jailbreak adalah menganggapnya daftar kesalahan Nintendo. Coba baca sebagai cermin. Setiap sistem yang pernah saya bantu pertahankan punya padanan SmileBASIC (komponen lama yang tidak ada yang memperkeras), padanan buffer path (kode plumbing yang melampaui asumsi awalnya), dan padanan race loader (validasi yang mempercayai perantara yang bisa diubah). Keunggulan penyerang bukan kejeniusan di satu langkah. Mereka berpikir dalam rantai, sementara defender berpikir dalam komponen.
Jadi latihan untuk timmu minggu ini bukan "bisakah seseorang memalsukan tanda tangan kita". Melainkan: pilih layanan internal yang paling tepercaya, anggap penyerang sudah punya write sembarang di proses paling lemah yang berkomunikasi dengannya, lalu telusuri rantainya ke depan. Di mana eskalasi pertama mendarat? Apa yang bisa dijangkau identitas itu? Kamu pasti akan segera menemukan sysmodule fs-mu sendiri. Lebih baik kamu yang menemukannya daripada orang yang punya KVM, tuas Bluetooth, dan dua minggu kesabaran.


