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!