Temukan dan perbaiki kerentanan file biner di Linux - dengan utilitas checksec dan kompiler gcc



Gambar: Gambar Buku Arsip Internet. Diubah oleh Opensource.com. CC BY-SA 4.0



Setelah mengkompilasi kode sumber yang sama, kita mungkin mendapatkan binari yang berbeda. Itu tergantung pada flag mana yang kita berikan ke tangan kompiler. Beberapa tanda ini memungkinkan Anda untuk mengaktifkan atau menonaktifkan sejumlah properti biner yang terkait dengan keamanan.



Beberapa dari mereka diaktifkan atau dinonaktifkan oleh kompiler secara default. Inilah bagaimana kerentanan dapat muncul dalam file biner yang tidak kita sadari.



Checksec adalah utilitas sederhana untuk menentukan properti mana yang disertakan pada waktu kompilasi. Dalam artikel ini saya akan memberi tahu Anda:



  • cara menggunakan utilitas checksec untuk menemukan kerentanan;
  • cara menggunakan kompiler gcc untuk memperbaiki kerentanan yang ditemukan.


Menginstal checksec



Untuk Fedora OS dan sistem berbasis RPM lainnya:



$ sudo dnf install checksec
      
      





Untuk sistem berbasis Debian gunakan apt.



Mulai cepat dengan checksec



Utilitas checksec terdiri dari satu file skrip, yang, bagaimanapun, cukup besar. Berkat transparansi ini, Anda dapat mengetahui perintah sistem mana untuk mencari kerentanan dalam binari yang dijalankan di bawah tenda:



$ file /usr/bin/checksec

/usr/bin/checksec: Bourne-Again shell script, ASCII text executable, with very long lines

$ wc -l /usr/bin/checksec

2111 /usr/bin/checksec
      
      





Mari kita jalankan checksec pada utilitas penjelajahan direktori (ls):



$ checksec --file=/usr/bin/ls

<strong>RELRO           STACK CANARY      NX            PIE             RPATH     RUNPATH      Symbols       FORTIFY Fortified       Fortifiable    FILE</strong>

Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   No Symbols        Yes   5       17              /usr/bin/ls

      
      





Dengan menjalankan perintah di terminal, Anda akan menerima laporan tentang properti berguna apa yang dimiliki biner ini dan apa yang tidak.  



Baris pertama adalah kepala tabel, yang mencantumkan berbagai properti keamanan - RELRO, STACK CANARY, NX, dan seterusnya. Baris kedua menunjukkan nilai properti ini untuk biner utilitas ls.



Halo biner!



Saya akan mengkompilasi biner dari kode C paling sederhana:



#include <stdio.h>

int main()

{

        printf(«Hello World\n»);

        return 0;

}

      
      





Harap dicatat bahwa sejauh ini saya belum mengirimkan satu flag pun ke kompiler, dengan pengecualian -o (ini tidak penting, tetapi hanya memberi tahu di mana harus menampilkan hasil kompilasi):



$ gcc hello.c -o hello

$ file hello

hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

$ ./hello

Hello World
      
      





Sekarang saya akan menjalankan utilitas checksec untuk biner saya. Beberapa properti berbeda dari properti



ls (     ):

$ checksec --file=./hello

<strong>RELRO           STACK CANARY      NX            PIE             RPATH     RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE</strong>

Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   85) Symbols       No    0       0./hello

      
      





Checksec memungkinkan Anda untuk menggunakan berbagai format output, yang dapat Anda tentukan dengan opsi --output. Saya akan memilih format JSON dan membuat output lebih deskriptif dengan utilitas jq :



$ checksec --file=./hello --output=json | jq

{

  «./hello»: {

    «relro»: «partial»,

    «canary»: «no»,

    «nx»: «yes»,

    «pie»: «no»,

    «rpath»: «no»,

    «runpath»: «no»,

    «symbols»: «yes»,

    «fortify_source»: «no»,

    «fortified»: «0»,

    «fortify-able»: «0»

  }

}

      
      





Analisis (checksec) dan eliminasi (gcc) kerentanan



File biner yang dibuat di atas memiliki beberapa properti yang menentukan, katakanlah, tingkat kerentanannya. Saya akan membandingkan properti file ini dengan properti biner ls (juga tercantum di atas) dan menjelaskan bagaimana melakukannya menggunakan utilitas checksec. 



Untuk setiap item, saya juga akan menunjukkan cara menghilangkan kerentanan yang ditemukan.



1. Simbol debug



Saya akan mulai sederhana. Simbol tertentu termasuk dalam biner pada waktu kompilasi. Simbol-simbol ini digunakan dalam pengembangan perangkat lunak: mereka diperlukan untuk debugging dan perbaikan bug.



Simbol debug biasanya dihapus dari versi biner yang dirilis pengembang untuk penggunaan umum. Ini tidak mempengaruhi pengoperasian program dengan cara apa pun. Pembersihan ini (dilambangkan dengan kata strip ) sering dilakukan untuk menghemat ruang, karena file menjadi lebih ringan setelah karakter dihapus. Dan dalam perangkat lunak berpemilik, karakter ini sering dihapus juga karena penyerang memiliki kemampuan untuk membacanya dalam format biner dan menggunakannya untuk tujuan mereka sendiri.



Checksec menunjukkan bahwa simbol debug ada di biner saya, tetapi tidak ada di file ls. 



$ checksec --file=/bin/ls --output=json | jq | grep symbols

    «symbols»: «no»,

$ checksec --file=./hello --output=json | jq | grep symbols

    «symbols»: «yes»,
      
      







Menjalankan perintah file dapat menunjukkan hal yang sama. Karakter tidak dilucuti.



$ file hello

hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, <strong>not stripped</strong>
      
      





Cara kerja checksec



Mari kita jalankan perintah ini dengan opsi --debug:



$ checksec --debug --file=./hello

      
      





Karena utilitas checksec adalah satu skrip panjang, Anda dapat menggunakan fungsi Bash untuk memeriksanya. Mari kita tampilkan perintah yang dijalankan skrip untuk file hello saya:



$ bash -x /usr/bin/checksec --file=./hello
      
      





Berikan perhatian khusus pada echo_message - keluaran pesan tentang apakah biner berisi simbol debug:



+ readelf -W --symbols ./hello

+ grep -q '\.symtab'

+ echo_message '\033[31m96) Symbols\t\033[m  ' Symbols, ' symbols=«yes»' '«symbols»:«yes»,'
      
      





Utilitas checksec menggunakan perintah readelf dengan tanda khusus --simbol untuk membaca file biner. Ini mencetak semua simbol debug dalam biner. 



$ readelf -W --symbols ./hello
      
      





Dari isi bagian .symtab, Anda dapat mengetahui jumlah simbol yang ditemukan:



$ readelf -W --symbols ./hello | grep -i symtab
      
      





Cara menghapus simbol debug setelah kompilasi



Utilitas strip akan membantu kami dalam hal ini.



$ gcc hello.c -o hello

$
 

$ file hello

hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, for GNU/Linux 3.2.0, <strong>not stripped</strong>

$
 

$ strip hello

$
 

$ file hello

hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, for GNU/Linux 3.2.0, <strong>stripped</strong>
      
      





Cara menghapus simbol debug pada waktu kompilasi



Saat mengkompilasi, gunakan flag -s:



$ gcc -s hello.c -o hello

$

$ file hello

hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=247de82a8ad84e7d8f20751ce79ea9e0cf4bd263, for GNU/Linux 3.2.0, <strong>stripped</strong>

      
      





Anda juga dapat memverifikasi bahwa simbol telah dihapus menggunakan utilitas checksec:



$ checksec --file=./hello --output=json | jq | grep symbols

    «symbols»: «no»,

      
      





2. kenari



Canary (informan) adalah nilai "rahasia" yang disimpan di tumpukan antara buffer dan data kontrol. Mereka digunakan untuk melindungi dari serangan buffer overflow: jika nilai-nilai ini diubah, maka ada baiknya membunyikan alarm. Saat aplikasi diluncurkan, tumpukannya sendiri dibuat untuk itu. Dalam hal ini, itu hanya struktur data dengan operasi push dan pop. Penyerang dapat menyiapkan data berbahaya dan menuliskannya ke tumpukan. Dalam hal ini, buffer mungkin meluap dan tumpukan mungkin rusak. Di masa depan, ini akan menyebabkan crash program. Analisis nilai kenari memungkinkan Anda dengan cepat memahami bahwa peretasan telah terjadi dan mengambil tindakan.



$ checksec --file=/bin/ls --output=json | jq | grep canary

    «canary»: «yes»,

$

$ checksec --file=./hello --output=json | jq | grep canary

    «canary»: «no»,

$

 ,    canary,  checksec   :

$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
      
      





Nyalakan kenari



Untuk melakukan ini, saat kompilasi, kami menggunakan flag -stack-protector-all :



$ gcc -fstack-protector-all hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep canary

    «canary»: «yes»,

      
      





Sekarang checksec dapat memberi tahu kami dengan hati nurani yang jelas bahwa mekanisme kenari aktif:



$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'

     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (3)

    83: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@@GLIBC_2.4

$

      
      





3. PI



Properti PIE yang diaktifkan memungkinkan kode yang dapat dieksekusi ditempatkan secara sewenang-wenang di memori terlepas dari alamat absolutnya:



PIE (Position Independent Executable) - kode yang dapat dieksekusi secara independen. Kemampuan untuk memprediksi di mana dan area memori apa yang berada di ruang alamat suatu proses berperan di tangan penyerang. Program pengguna dimuat dan dieksekusi dari alamat memori virtual proses yang telah ditentukan kecuali jika dikompilasi dengan opsi PIE. Menggunakan PIE memungkinkan sistem operasi memuat bagian kode yang dapat dieksekusi ke dalam potongan memori yang berubah-ubah, membuatnya jauh lebih sulit untuk dipecahkan.



$ checksec --file=/bin/ls --output=json | jq | grep pie

    «pie»: «yes»,

$ checksec --file=./hello --output=json | jq | grep pie

    «pie»: «no»,

      
      





Seringkali properti PIE hanya disertakan saat mengkompilasi pustaka. Pada output di bawah ini, hello ditandai sebagai LSB yang dapat dieksekusi dan file libc (.so) perpustakaan standar ditandai sebagai objek bersama LSB:



$ file hello

hello: ELF 64-bit <strong>LSB executable</strong>, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

$ file /lib64/libc-2.32.so

/lib64/libc-2.32.so: ELF 64-bit <strong>LSB shared object</strong>, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4a7fb374097fb927fb93d35ef98ba89262d0c4a4, for GNU/Linux 3.2.0, not stripped

      
      





Checksec mendapatkan informasi ini seperti ini:



$ readelf -W -h ./hello | grep EXEC

  Type:                              EXEC (Executable file)

      
      





Jika Anda menjalankan perintah yang sama untuk perpustakaan, Anda akan melihat DYN alih-alih EXEC:



$ readelf -W -h /lib64/libc-2.32.so | grep DYN

  Type:                              DYN (Shared object file)

      
      





Nyalakan PIE



Saat mengkompilasi program, Anda perlu menentukan flag berikut:



$ gcc -pie -fpie hello.c -o hello
      
      





Untuk memastikan bahwa properti PIE diaktifkan, jalankan perintah berikut:



$ checksec --file=./hello --output=json | jq | grep pie

    «pie»: «yes»,

$
      
      





Sekarang file biner kami (halo) akan mengubah jenisnya dari EXEC ke DYN:



$ file hello

hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bb039adf2530d97e02f534a94f0f668cd540f940, for GNU/Linux 3.2.0, not stripped

$ readelf -W -h ./hello | grep DYN

  Type:                              DYN (Shared object file)

      
      





4. NX



Sistem operasi dan alat prosesor memungkinkan Anda untuk secara fleksibel mengonfigurasi hak akses ke halaman memori virtual. Dengan mengaktifkan properti NX (No Execute), kita dapat mencegah data diinterpretasikan sebagai instruksi prosesor. Seringkali, dalam serangan buffer overflow, penyerang mendorong kode ke tumpukan dan kemudian mencoba mengeksekusinya. Namun, dengan mencegah kode dari mengeksekusi di segmen memori ini, serangan tersebut dapat dicegah. Dalam kompilasi normal menggunakan gcc, properti ini diaktifkan secara default:



$ checksec --file=/bin/ls --output=json | jq | grep nx

    «nx»: «yes»,

$ checksec --file=./hello --output=json | jq | grep nx

    «nx»: «yes»,

      
      





Checksec kembali menggunakan perintah readelf untuk mendapatkan informasi tentang properti NX. Dalam hal ini, RW berarti tumpukan dibaca / ditulis. Tetapi karena kombinasi ini tidak mengandung karakter E, ada larangan untuk mengeksekusi kode dari tumpukan ini:



$ readelf -W -l ./hello | grep GNU_STACK

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

      
      





Nonaktifkan NX 



Tidak disarankan untuk menonaktifkan properti NX, tetapi Anda dapat melakukannya seperti ini:



$ gcc -z execstack hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep nx

    «nx»: «no»,

      
      





Setelah kompilasi, kita akan melihat bahwa izin tumpukan telah berubah menjadi RWE:



$ readelf -W -l ./hello | grep GNU_STACK

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





5. RELRO



Dalam binari yang terhubung secara dinamis, GOT (Global Offset Table) khusus digunakan untuk memanggil fungsi dari perpustakaan. Tabel ini direferensikan oleh biner ELF (Executable Linkable Format). Ketika perlindungan RELRO (Relocation Read-Only) diaktifkan, GOT menjadi read-only. Ini memungkinkan Anda untuk melindungi dari beberapa jenis serangan yang mengubah catatan tabel:



$ checksec --file=/bin/ls --output=json | jq | grep relro

    «relro»: «full»,

$ checksec --file=./hello --output=json | jq | grep relro

    «relro»: «partial»,

      
      





Dalam hal ini, hanya satu dari properti RELRO yang diaktifkan, jadi checksec mengeluarkan nilai "parsial". Checksec menggunakan perintah readelf untuk menampilkan pengaturan. 



$ readelf -W -l ./hello | grep GNU_RELRO

  GNU_RELRO      0x002e10 0x0000000000403e10 0x0000000000403e10 0x0001f0 0x0001f0 R   0x1

$ readelf -W -d ./hello | grep BIND_NOW
      
      





Hidupkan perlindungan penuh (FULL RELRO)



Untuk melakukan ini, saat kompilasi, Anda perlu menggunakan flag yang sesuai:



$ gcc -Wl,-z,relro,-z,now hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep relro

    «relro»: «full»,

      
      





Itu saja, sekarang biner kami telah menerima gelar kehormatan FULL RELRO:



$ readelf -W -l ./hello | grep GNU_RELRO

  GNU_RELRO      0x002dd0 0x0000000000403dd0 0x0000000000403dd0 0x000230 0x000230 R   0x1

$ readelf -W -d ./hello | grep BIND_NOW

 0x0000000000000018 (BIND_NOW)    
      
      



      

Fitur checksec lainnya



Topik keamanan dapat dipelajari tanpa henti. Bahkan berbicara tentang utilitas checksec sederhana dalam artikel ini, saya tidak dapat membahas semuanya. Namun, saya akan menyebutkan beberapa kemungkinan yang lebih menarik.



Memeriksa banyak file



Tidak perlu menjalankan perintah terpisah untuk setiap file. Anda dapat menjalankan satu perintah untuk beberapa binari sekaligus:



$ checksec --dir=/usr/bin
      
      





Proses pemeriksaan



Utilitas checksec juga memungkinkan Anda untuk menganalisis keamanan proses. Perintah berikut menampilkan properti dari semua program yang berjalan di sistem Anda (Anda perlu menggunakan opsi --proc-all untuk melakukan ini): 



$ checksec --proc-all
      
      





Anda juga dapat memilih satu proses untuk diperiksa dengan menentukan namanya:



$ checksec --proc=bash
      
      





Pemeriksaan kernel



Demikian pula, Anda dapat menganalisis kerentanan di kernel sistem Anda.



$ checksec --kernel
      
      





Diperingatkan sebelumnya adalah dipersenjatai



Pelajari properti keamanan secara mendetail dan coba pahami apa sebenarnya yang memengaruhi masing-masing properti dan jenis serangan apa yang dapat dicegah. Checksec untuk membantu Anda!






Server cloud dari Macleod cepat dan aman.



Daftar menggunakan tautan di atas atau dengan mengklik spanduk dan dapatkan diskon 10% untuk bulan pertama menyewa server dengan konfigurasi apa pun!






All Articles