Perfect Bug: Menggunakan Type Confusion di Flash. Bagian 1

Halo lagi! Besok kita akan memulai kelas dalam grup baru di program "Rekayasa Balik" . Secara tradisional, kami membagikan terjemahan materi yang bermanfaat kepada Anda. Ayo pergi!

Penting bagi sebagian penyerang bahwa eksploitasi menjadi sangat andal. Itu harus selalu mengarah pada eksekusi kode ketika diluncurkan pada sistem dengan platform dan versi Flash yang dikenal. Untuk membuatnya, Anda dapat menggunakan bug berkualitas tinggi. Artikel ini menjelaskan penggunaan salah satu bug ini, serta faktor-faktor yang membuatnya sangat cocok untuk operasi yang andal.



Bug

CVE-2015-3077 - masalah kebingungan jenis di Adobe Flash Button dan seter filter MovieClip , yang memungkinkan Anda untuk membingungkan semua jenis filter dengan yang lain. Saya melaporkannya pada awal Desember 2015, dan pada bulan Mei sudah diperbaiki. Bug terjadi karena cracker dapat menimpa konstruktor yang digunakan untuk menginisialisasi objek filter. Kode sampel yang mereproduksi masalah disajikan di bawah ini:



Kode ini agak membingungkan karena penggunaan operator [], yang diperlukan untuk kompilasi di Flash CS. Kode yang setara secara logis (yang bukan fakta yang dikompilasi) diberikan di bawah ini:



Kode ini menetapkan bidang filter objek: Tombol atau MovieClip ke BlurFilter, yang kemudian disimpan langsung di Flash. Konstruktor BlurFilter kemudian ditimpa oleh konstruktor ConvolutionFilter. Setelah itu, pengambil disebut dan objek ActionScript dibuat untuk menyimpan BlurFilter asli. Namun, konstruktor telah ditimpa, sehingga ConvolutionFilter dipanggil. Ini menghasilkan objek bertipe ConvolutionFilter, didukung oleh kembalinya BlueFilter asli.

Pada akhirnya, bidang ConvolutionFilter dapat diakses (baca dan tulis) seolah-olah milik BlurFilter. Demikian pula untuk semua jenis filter lainnya. Ini membuka berbagai manipulasi yang berguna untuk dieksploitasi.

Diagram di bawah ini menunjukkan lokasi objek asli dalam memori yang berpotensi menjadi bingung menggunakan kerentanan ini di 64-bit Linux.



Dalam dua kasus, pointer sebanding dengan bilangan bulat, dan angka floating-point yang dapat dimanipulasi. Ini berarti bahwa pointer dapat dibaca dan ditulis secara langsung. Selain itu, karena bidang objek disusun dan diurutkan berdasarkan ukuran sesuai dengan definisi kelas, mereka selalu berada di tempat yang dapat diprediksi, sehingga penulisan dan pembacaan tidak gagal. Properti ini penting untuk memastikan keandalan eksploitasi.

Eksploitasi

Karena mengeksploitasi masalah ini membutuhkan berulang kali menjalankan jenis kebingungan, saya mulai dengan membuat fungsi utilitas untuk jenis kebingungan, FilterConfuse.confuse . Itu juga merapikan segalanya: mengembalikan konstruktor filter ActionScript kembali ke keadaan normal untuk berulang kali memanggil fungsi yang rentan tanpa mempengaruhi perilaku ActionScript di luar fungsi itu sendiri.
Langkah pertama adalah memotong ASLR dengan mendefinisikan alamat tabel fungsi virtual (secara singkat vtable). Cara ideal untuk ini adalah dengan mengacaukan objek dengan tabel dengan objek di mana ada elemen yang tumpang tindih dengan tabel yang dapat dimanipulasi. Tetapi vtable dari semua objek filter memiliki offset yang sama. Sebagai gantinya, saya menggunakan objek BitmapData di DisplacementMapFilter untuk menentukan alamat vtable.

Untuk menentukan lokasi dalam memori BitmapData objek, saya bingung DisplacementMapFilter dengan BevelFilter. Ini membuat pointer BitmapData disimpan di DisplacementMapFilter sejajar dengan properti warna BevelFilter ( shadowColor , shadowAlpha , highlightColor , dan highlightAlpha ). Properti ini didukung oleh dua bilangan bulat 32-bit (ditampilkan sebagai warna dan hcolor di atas dan di bawah), dan properti warna mengakses 24 bit dari masing-masing integer, sedangkan properti alpha mengakses 8 bit atas. Jika Anda membaca properti ini dan menggabungkannya menggunakan bit aritmatika, Anda dapat mengekstrak alamat BitmapData langsung dari objek.



Kemudian, Anda perlu membaca vtable dari atas objek BitmapData. Untuk ini, saya menggunakan properti matriks objek ConvolutionFilter. Ini disimpan sebagai penunjuk ke array nomor floating point, di mana memori dialokasikan ketika mengatur properti, dan array ActionScript yang mengandung angka-angka ini dikembalikan ketika properti diterima. Dengan mengatur pointer matriks ke objek BitmapData, Anda dapat membaca konten objek ini dari memori sebagai array angka floating-point.

Untuk mengatur pointer, saya mengacaukan objek ConvolutionFilter dengan objek DisplacementMapFilter (bukan DisplacementMapFilter yang sama dengan yang digunakan di atas!) Dan mengatur lokasi BitmapData objek di atas di properti mapPoint . Properti mapPoint adalah titik dengan koordinat bilangan x dan y (p_x dan p_y pada gambar di bawah) yang sesuai dengan pointer matriks di ConvolutionFilter, yang membuatnya mudah untuk mengatur nilai ini. Setelah itu, menjadi mungkin untuk membaca vtable dari objek BitmapData menggunakan array matriks dari objek ConvolutionFilter (perlu dicatat bahwa untuk objek ini harus bingung dengan DisplacementBitmapFilter, dan kemudian bingung kembali dengan ConvolutionFilter).



Pada titik ini, menjadi lebih sulit untuk mempertahankan keandalan eksploit karena penggunaan angka floating point. Nilai vtable_low dan vtable_high dibaca dari matriks ConvolutionFilter sebagai angka floating-point, karena ini adalah tipe array. Namun, sayangnya, tidak setiap nilai pointer yang valid adalah angka floating point yang valid. Ini berarti bahwa membaca nilai akan menghasilkan NaN, atau lebih buruk, nilai numerik yang tidak sepenuhnya benar.

Idealnya, untuk mengatasi masalah ini, Anda perlu mengakses vtable_low dan vtable_high melalui pengambil, yang menafsirkannya sebagai bilangan bulat, tetapi ini bukan karena elemen filter biasanya mengambang karena fungsinya.

Untungnya, mesin virtual AS2 cukup malas untuk menginterpretasikan angka floating point - hanya mengubah nilai menjadi float ketika operasi dilakukan di dalamnya dalam ActionScript. Operasi asli biasanya tidak memerlukan interpretasi, kecuali untuk operasi khusus seperti aritmatika. Ini berarti bahwa ketika menyalin angka floating-point dari array matriks ke vtable_low atau vtable_high, itu akan mempertahankan nilainya dalam memori, bahkan jika itu tidak valid untuk float, sedangkan variabel yang disalin tidak digunakan dalam ActionScript atau untuk melakukan operasi aritmatika dalam bahasa asli kode. Jadi, jika nilai variabel secara instan dikacaukan dengan tipe lain yang mendukung kisaran penuh nilai 32-bit, misalnya int, dijamin sama dengan nilai asli dalam memori array matriks. Oleh karena itu, untuk menghindari ketidakpercayaan dalam eksploitasi, penting untuk melakukan kebingungan tipe sebelum memanipulasi float dalam ActionScript.

Untuk melakukan ini, saya menulis kelas konversi, FloatConverter , menggunakan jenis kebingungan dalam filter untuk mengimplementasikan fungsi integer-to-float dan float-to-integer. Ini membingungkan properti ColorMatrixFilter matriks (jangan bingung dengan properti matriks ConvolutionFilter), yang merupakan seperangkat mengapung bawaan, dengan warna GlowFilter dan properti alfa yang mengakses byte int berbeda.



Dengan cara ini Anda dapat menerapkan konversi float ke int yang andal, tetapi, sayangnya, ini tidak bekerja dengan andal di arah yang berlawanan. Untuk mengakses larik warna di ColorMatrix di ActionScript, seluruh larik disalin, bahkan jika Anda hanya mengakses yang pertama. Saat menyalin array, setiap elemen dikonversi ke Angka, yang mencakup panggilan ke pointer (misalnya, memanggil valueOf dari suatu objek). Karena array warna adalah yang terpanjang dari seluruh kelas GlowFilter, ia akan menumpuk ketika bingung dengan GlowFilter. Ini berarti bahwa konversi dari nilai yang tidak diketahui dari tumpukan ini dapat terjadi, yang akan menyebabkan crash jika mereka merujuk ke pointer tidak valid ketika mengkonversi ke Angka. Oleh karena itu, untuk int-to-float, saya menerapkan float converter menggunakan ConvolutionFilter dan DisplacementMapFilter kebingungan lain, yang merupakan pemain langsung dan tidak memanggil nilai yang tidak diketahui dari heap.



Ini menyelesaikan masalah crash yang disebabkan oleh mengakses nilai-nilai yang tidak dikenal dari heap, tetapi, sayangnya, ada masalah keandalan lain yang terkait dengan float dalam exploit ini. Hal ini disebabkan oleh penerapan pengambil matriks ConvolutionFilter. Semua nilai numerik dalam ActionScript 2 bertipe Number, yang merupakan gabungan dari integer dan pointer menjadi angka ganda. Matriks ConvolutionFilter asli disimpan sebagai array angka floating point, tetapi disalin ke array ActionScript untuk mempertahankan akses ketika pengambil matriks dipanggil, dan nilai-nilai dikonversi menjadi dua kali lipat dalam proses. Kemudian, ketika memanggil konverter float, mereka dikonversi kembali ke angka floating point.

Casting angka floating-point ke angka presisi ganda dan sebaliknya biasanya menyimpan nilainya, tetapi tidak jika nilai float adalah SNaN. Menurut spesifikasi floating point, ada dua jenis NaN: silent NaN (QNaN) dan sinyal NaN (SNaN). Ketika QNaN muncul, tidak ada yang terjadi, tetapi SNaN dalam beberapa kasus melempar pengecualian floating-point. Di x86, mengonversi ganda menjadi float selalu menghasilkan QNaN (bahkan jika ganda berasal dari SNaN) untuk menghindari pengecualian yang tidak terduga.

Oleh karena itu, jika bit yang lebih rendah dari pointer adalah SNaN, itu akan dikonversi ke QNaN, yang berarti bahwa bit pertama (bit mantissa pertama, bit 22) akan ditetapkan ketika seharusnya tidak. Masalah ini dapat dihindari ketika membaca vtable - byte ketiga dari pointer yang mengandung bit pertama dapat dibaca tanpa perataan untuk mengkonfirmasi nilai sekarang. Jadi kode akan membaca tanpa keberpihakan (setelah membaca vtable lagi dengan pointer Bitmap bertambah satu) dan menyesuaikan nilai int jika float ternyata menjadi SNaN.

Menggunakan float converter yang dijelaskan di atas, alamat vtable dapat dikonversi ke integer. Sekarang Anda perlu mendapatkan kode untuk dieksekusi menggunakan alamat ini. Cara mudah untuk memindahkan pointer instruksi adalah menimpa vtable objek (atau pointer ke objek yang memiliki vtable). Ini dapat dilakukan dengan membingungkan array matriks ConvolutionFilter dan BitmapData dari pointer DisplacementFilter.

Akhir dari bagian pertama. Bagian kedua dari terjemahan akan diterbitkan sedikit kemudian, dan sekarang kami menunggu komentar Anda dan kami mengundang semua orang ke kursus rekayasa balik OTUS.

Source: https://habr.com/ru/post/id442640/


All Articles