GNU/Linux >> Belajar Linux >  >> Linux

Izin exec tak terduga dari mmap saat file rakitan disertakan dalam proyek

Linux memiliki domain eksekusi yang disebut READ_IMPLIES_EXEC , yang menyebabkan semua halaman dialokasikan dengan PROT_READ untuk juga diberikan PROT_EXEC . Kernel Linux lama menggunakan ini untuk executable yang setara dengan gcc -z execstack . Program ini akan menunjukkan kepada Anda apakah itu diaktifkan untuk dirinya sendiri:

#include <stdio.h>
#include <sys/personality.h>

int main(void) {
    printf("Read-implies-exec is %s\n", personality(0xffffffff) & READ_IMPLIES_EXEC ? "true" : "false");
    return 0;
}

Jika Anda mengompilasinya bersama dengan .s kosong file, Anda akan melihat bahwa itu diaktifkan, tetapi tanpa itu, itu akan dinonaktifkan. Nilai awal ini berasal dari informasi meta ELF di biner Anda. Lakukan readelf -Wl example . Anda akan melihat baris ini saat mengompilasi tanpa .s kosong berkas:

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10

Tapi yang ini saat Anda mengompilasinya:

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

Perhatikan RWE bukan hanya RW . Alasan untuk ini adalah bahwa linker mengasumsikan bahwa file rakitan Anda memerlukan read-implies-exec kecuali secara eksplisit diberitahu bahwa mereka tidak melakukannya, dan jika ada bagian dari program Anda yang memerlukan read-implies-exec, maka itu diaktifkan untuk seluruh program Anda . File rakitan yang dikompilasi oleh GCC mengatakan bahwa ia tidak memerlukan ini, dengan baris ini (Anda akan melihat ini jika Anda mengompilasi dengan -S ):

    .section        .note.GNU-stack,"",@progbits

Izin bagian default tidak menyertakan ex ec. Lihat bagian ELF dari .section dokumentasi untuk arti dari "flags" dan @attributes.

(Dan jangan lupa untuk beralih ke bagian lain seperti .text atau .data setelah itu .section direktif, jika .s Anda mengandalkan .text karena bagian default di bagian atas file.)

Letakkan baris itu di example.s (dan setiap .s lainnya file dalam proyek Anda). Keberadaan .note.GNU-stack itu bagian akan berfungsi untuk memberi tahu linker bahwa file objek ini tidak bergantung pada tumpukan yang dapat dieksekusi, sehingga linker akan menggunakan RW bukannya RWE pada GNU_STACK metadata, dan program Anda kemudian akan berfungsi seperti yang diharapkan.

Demikian pula untuk NASM, sebuah section direktif dengan flag yang tepat menentukan tumpukan yang tidak dapat dieksekusi.

Kernel Linux modern antara 5.4 dan 5.8 mengubah perilaku pemuat program ELF. Untuk x86-64, tidak ada yang mengaktifkan READ_IMPLIES_EXEC lagi. Paling banyak (dengan RWE GNU_STACK ditambahkan oleh ld ), Anda akan mendapatkan tumpukan itu sendiri dapat dieksekusi, bukan setiap halaman yang dapat dibaca. (Jawaban ini mencakup perubahan terakhir, di 5.8, tetapi pasti ada perubahan lain sebelumnya, karena pertanyaan itu menunjukkan eksekusi kode yang berhasil di .data di x86-64 Linux 5.4)

exec-all (READ_IMPLIES_EXEC ) hanya terjadi untuk executable 32-bit lawas yang tautannya tidak menambahkan GNU_STACK entri header sama sekali. Tapi seperti yang ditunjukkan di sini, ld modern selalu menambahkan itu dengan satu pengaturan atau yang lain, bahkan ketika input .o file tidak memiliki catatan.

Anda tetap harus menggunakan .note ini bagian untuk memberi sinyal tumpukan yang tidak dapat dieksekusi dalam program normal. Tetapi jika Anda berharap untuk menguji kode modifikasi sendiri di .data atau mengikuti beberapa tutorial lama untuk menguji shellcode, itu bukan opsi pada kernel modern.


Sebagai alternatif untuk memodifikasi file rakitan Anda dengan varian direktif bagian khusus GNU, Anda dapat menambahkan -Wa,--noexecstack ke baris perintah Anda untuk membuat file rakitan. Sebagai contoh, lihat bagaimana saya melakukannya di configure musl :

https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a

Saya percaya setidaknya beberapa versi dentang dengan assembler terintegrasi mungkin memerlukannya untuk diteruskan sebagai --noexecstack (tanpa -Wa ), jadi skrip konfigurasi Anda mungkin harus memeriksa keduanya dan melihat mana yang diterima.

Anda juga dapat menggunakan -Wl,-z,noexecstack pada waktu penautan (dalam LDFLAGS ) untuk mendapatkan hasil yang sama. Kerugiannya adalah tidak membantu jika proyek Anda menghasilkan statis (.a ) file pustaka untuk digunakan oleh perangkat lunak lain, karena Anda tidak mengontrol opsi waktu penautan saat digunakan oleh program lain.


Linux
  1. Apa yang Terjadi Saat Saya Mengeksekusi File Di Shell?

  2. Grep Word Dalam File Lalu Salin File?

  3. Ambil Kolom Pertama Dari 2 File Dan Tulis Ke File Ketiga?

  1. Ke Mana File Pergi Saat Perintah Rm Dikeluarkan?

  2. Percepat rsync saat memigrasi server Linux dari baris perintah

  3. Memeriksa file DB Berkeley dari CLI

  1. Salin file di terminal Linux

  2. Cara chmod file berdasarkan hasil dari perintah find

  3. Bagaimana cara menghapus file .fuse_hidden*?