Kompilasi kode sumber menghasilkan biner. Selama kompilasi, Anda dapat memberikan flag ke kompiler untuk mengaktifkan atau menonaktifkan properti tertentu pada biner. Beberapa properti ini relevan dengan keamanan.
Checksec adalah alat kecil yang bagus (dan skrip shell) yang, di antara fungsi lainnya, mengidentifikasi properti keamanan yang dibangun ke dalam biner saat dikompilasi. Kompilator mungkin mengaktifkan beberapa properti ini secara default, dan Anda mungkin harus memberikan tanda khusus untuk mengaktifkan yang lain.
Artikel ini menjelaskan cara menggunakan checksec untuk mengidentifikasi properti keamanan pada biner, termasuk:
- Perintah dasar yang digunakan checksec untuk menemukan informasi tentang properti keamanan
- Cara mengaktifkan properti keamanan menggunakan GNU Compiler Collection (GCC) saat mengompilasi biner sampel
Instal checksec
Untuk menginstal checksec di Fedora dan sistem berbasis RPM lainnya, gunakan:
$ sudo dnf install checksec
Untuk distro berbasis Debian, gunakan yang setara dengan apt
perintah.
Skrip shell
Checksec adalah skrip shell file tunggal, meskipun agak besar. Keuntungannya adalah Anda dapat membaca skrip dengan cepat dan memahami semua perintah sistem yang berjalan untuk menemukan informasi tentang binari atau yang dapat dieksekusi:
$ file /usr/bin/checksec
/usr/bin/checksec:Bourne-Again shell script, teks ASCII dapat dieksekusi, dengan garis yang sangat panjang
$ wc -l /usr /bin/checksec
2111 /usr/bin/checksec
Ambil checksec untuk drive dengan biner yang mungkin Anda jalankan setiap hari:ls
yang ada di mana-mana memerintah. Format perintahnya adalah checksec --file=
diikuti oleh path absolut dari ls
biner:
$ checksec --file =/ usr / bin / ls
relro tumpukan canary nx pie rahkan runpath simbol fortify fortified file borden 5 17 /usr/bin/ls
Ketika Anda menjalankan ini di terminal, Anda melihat kode warna yang menunjukkan apa yang baik dan apa yang mungkin tidak. Saya katakan "mungkin" karena meskipun ada sesuatu yang berwarna merah, itu tidak selalu berarti hal-hal yang buruk—itu mungkin hanya berarti vendor distro membuat beberapa pengorbanan saat mengkompilasi binari.
Baris pertama menyediakan berbagai properti keamanan yang biasanya tersedia untuk biner, seperti RELRO
, STACK CANARY
, NX
, dan seterusnya (saya jelaskan secara rinci di bawah). Baris kedua menunjukkan status properti ini untuk biner yang diberikan (ls
, pada kasus ini). Misalnya, NX enabled
berarti beberapa properti diaktifkan untuk biner ini.
Biner sampel
Untuk tutorial ini, saya akan menggunakan program "hello world" berikut sebagai contoh biner.
#include
int main()
{
printf("Hello World\n");
return 0;
}
Perhatikan bahwa saya tidak memberikan gcc
dengan tanda tambahan apa pun selama kompilasi:
$ gcc hello.c -o hello
$ file hello
hello:ELF 64-bit LSB yang dapat dieksekusi, x86-64, versi 1 (SYSV), tertaut secara dinamis, penerjemah / lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, untuk GNU/Linux 3.2.0, tidak dilucuti
$ ./hello
Halo DuniaJalankan biner melalui checksec. Beberapa properti berbeda dengan
ls
perintah di atas (di layar Anda, ini mungkin ditampilkan dengan warna merah):$ checksec --file =. / / hello 0./halo
$Mengubah format keluaran
Checksec memungkinkan berbagai format keluaran, yang dapat Anda tentukan dengan
--output
. Saya akan memilih format JSON dan menyalurkan output kejq
utilitas untuk pencetakan cantik.Untuk mengikuti, pastikan Anda memiliki
jq
diinstal karena tutorial ini menggunakan format output ini untuk dengan cepat mengambil properti tertentu dari output dan melaporkanyes
atauno
pada setiap:$ checksec --file=./hello --output=json | jq
{
"./hello":{
"relro":"partial",
"canary":"tidak",
"nx":" ya",
"pie":"tidak",
"rpath":"tidak",
"runpath":"tidak",
"simbol":"ya" ,
"fortify_source":"tidak",
"fortified":"0",
"fortify-able":"0"
}
}Menelusuri properti keamanan
Selengkapnya tentang keamanan
- Panduan pengkodean defensif
- Webinar:Mengotomatiskan keamanan sistem dan kepatuhan dengan sistem operasi standar
- 10 lapisan keamanan kontainer Linux
- Buku mewarnai SELinux
- Artikel keamanan lainnya
Biner di atas mencakup beberapa properti keamanan. Saya akan membandingkan biner itu dengan ls
biner di atas untuk memeriksa apa yang diaktifkan dan menjelaskan bagaimana checksec menemukan informasi ini.
1. Simbol
Saya akan mulai dengan yang mudah dulu. Selama kompilasi, simbol-simbol tertentu disertakan dalam biner, sebagian besar untuk debugging. Simbol-simbol ini diperlukan saat Anda mengembangkan perangkat lunak dan memerlukan beberapa siklus untuk men-debug dan memperbaiki berbagai hal.
Simbol-simbol ini biasanya dilucuti (dihapus) dari biner terakhir sebelum dirilis untuk penggunaan umum. Ini tidak mempengaruhi eksekusi biner dengan cara apapun; itu akan berjalan seperti halnya dengan simbol. Stripping sering dilakukan untuk menghemat ruang, karena biner agak lebih ringan setelah simbol dilucuti. Dalam perangkat lunak sumber tertutup atau berpemilik, simbol sering kali dihilangkan karena memiliki simbol ini dalam biner membuatnya agak mudah untuk menyimpulkan cara kerja bagian dalam perangkat lunak.
Menurut checksec, simbol ada dalam biner ini, namun tidak ada di ls
biner. Anda juga dapat menemukan informasi ini dengan menjalankan file
perintah pada program—Anda melihat not stripped
di output menjelang akhir:
$ checksec --file=/bin/ls --output=json | jq | grep simbol
"simbol":"tidak",
$ checksec --file=./hello --output=json | jq | simbol grep
"simbol":"ya",
$ file halo
halo:LSB 64-bit ELF yang dapat dieksekusi, x86-64, versi 1 (SYSV), tertaut secara dinamis , interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, untuk GNU/Linux 3.2.0, tidak dihapus
Bagaimana checksec menemukan informasi ini? Nah, ini menyediakan --debug
yang praktis opsi untuk menunjukkan fungsi mana yang dijalankan. Oleh karena itu, menjalankan perintah berikut akan menunjukkan kepada Anda fungsi mana yang dijalankan dalam skrip shell:
$ checksec --debug --file=./hello
Dalam tutorial ini, saya mencari perintah dasar yang digunakan untuk menemukan informasi ini. Karena ini adalah skrip shell, Anda selalu dapat memanfaatkan fitur Bash. Perintah ini akan menampilkan setiap perintah yang dijalankan dari dalam skrip shell:
$ bash -x /usr/bin/checksec --file=./hello
Jika Anda men-scroll output, Anda akan melihat echo_message
diikuti oleh kategori properti keamanan. Berikut adalah laporan checksec tentang apakah biner berisi simbol:
+ readelf -W --symbols ./hello
+ grep -q '\.symtab'
+ echo_message '\033[31m96) Simbol\t\033[m ' Simbol, ' simbol ="ya"' '"simbol":"ya",'
Untuk menyederhanakan ini, checksec menggunakan readelf
utilitas untuk membaca biner dan menyediakan --symbols
khusus flag yang mencantumkan semua simbol dalam biner. Kemudian ia mengambil nilai khusus, .symtab
, yang memberikan jumlah entri (simbol) yang ditemukannya. Anda dapat mencoba perintah berikut pada biner uji yang Anda kompilasi di atas:
$ readelf -W --symbols ./hello
$ readelf -W --symbols ./hello | grep -i symtab
Cara menghapus simbol
Anda dapat menghapus simbol setelah kompilasi atau selama kompilasi.
- Kompilasi pos: Setelah kompilasi, Anda dapat menggunakan
strip
utilitas pada biner untuk menghapus simbol. Konfirmasikan itu berfungsi menggunakanfile
perintah, yang sekarang menampilkan output sebagaistripped
:$ gcc hello.c -o hello
$
$ file hello
hello:ELF 64-bit LSB dapat dieksekusi, x86-64, versi 1 (SYSV) , terkait secara dinamis, penerjemah /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, untuk GNU/Linux 3.2.0, tidak dilucuti
$
$ strip hello
$
$ file hello
hello:ELF 64-bit LSB executable, x86-64, versi 1 (SYSV), tertaut secara dinamis, interpreter /lib64/ld-linux-x86-64.so .2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, untuk GNU/Linux 3.2.0, dihilangkan
$
Cara menghapus simbol selama kompilasi
Alih-alih menghapus simbol secara manual setelah kompilasi, Anda dapat meminta kompiler untuk melakukannya untuk Anda dengan memberikan -s
argumen:
$ gcc -s hello.c -o hello
$
$ file hello
hello:ELF 64-bit LSB yang dapat dieksekusi, x86-64, versi 1 (SYSV), terhubung secara dinamis , interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=247de82a8ad84e7d8f20751ce79ea9e0cf4bd263, untuk GNU/Linux 3.2.0, dihilangkan
$
Setelah menjalankan kembali checksec, Anda dapat melihat symbols
ditampilkan sebagai no
:
$ checksec --file=./hello --output=json | jq | grep simbol
"simbol":"tidak",
$
2. burung kenari
Canary adalah nilai yang diketahui yang ditempatkan di antara buffer dan data kontrol di tumpukan untuk memantau buffer overflows. Ketika sebuah aplikasi dijalankan, dua jenis memori diberikan padanya. Salah satunya adalah tumpukan , yang merupakan struktur data dengan dua operasi:push
, yang menempatkan data ke dalam tumpukan, dan pop
, yang menghapus data dari tumpukan dalam urutan terbalik. Masukan berbahaya dapat meluap atau merusak tumpukan dengan masukan yang dibuat khusus dan menyebabkan program mogok:
$ checksec --file=/bin/ls --output=json | jq | grep canary
"canary":"yes",
$
$ checksec --file=./hello --output=json | jq | grep canary
"canary":"tidak",
$
Bagaimana cara checksec mengetahui apakah biner diaktifkan dengan kenari? Menggunakan metode di atas, Anda dapat mempersempitnya dengan menjalankan perintah berikut di dalam skrip shell:
$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
Aktifkan kenari
Untuk melindungi dari kasus ini, kompilator menyediakan -stack-protector-all
flag, yang menambahkan kode ekstra ke biner untuk memeriksa buffer overflows tersebut:
$ gcc -fstack-protector-all hello.c -o hello
$ checksec --file=./hello --output=json | jq | grep canary
"canary":"ya",
Checksec menunjukkan bahwa properti sekarang diaktifkan. Anda juga dapat memverifikasi ini dengan:
$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
2:0000000000000000 0 FUNC DEFAULT GLOBAL UND __stack_chk_fail@GLIBC_2.4 (3)
0000_OBNCAL 0000@ $
3. PIE
PIE adalah singkatan dari executable posisi-independen. Seperti namanya, itu adalah kode yang ditempatkan di suatu tempat di memori untuk dieksekusi terlepas dari alamat absolutnya:
$ checksec --file=/bin/ls --output=json | jq | grep pie
"pie":"ya",
$ checksec --file=./hello --output=json | jq | grep pie
"pie":"tidak",
Seringkali, PIE diaktifkan hanya untuk perpustakaan dan bukan untuk program baris perintah yang berdiri sendiri. Pada output di bawah ini, hello
ditampilkan sebagai LSB executable
, sedangkan, libc
pustaka standar (.so
) file ditandai dengan LSB shared object
:
$ file hello
halo:ELF 64-bit LSB yang dapat dieksekusi, x86-64, versi 1 (SYSV), tertaut secara dinamis, juru bahasa /lib64/ld-linux-x86-64.so.2, BuildID[ sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, untuk GNU/Linux 3.2.0, tidak dilucuti
$ file /lib64/libc-2.32.so
/lib64/libc-2.32.so:ELF 64-bit objek bersama LSB, x86-64, versi 1 (GNU/Linux), tertaut secara dinamis, juru bahasa /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4a7fb374097fb927fb93d35ef98ba89262d0c4a4, untuk GNU/Linux 3.2.0, tidak dilucuti
Checksec mencoba menemukan informasi ini dengan:
$ readelf -W -h ./hello | grep EXEC
Jenis: EXEC (File yang dapat dieksekusi)
Jika Anda mencoba perintah yang sama pada pustaka bersama alih-alih EXEC
, Anda akan melihat DYN
:
$ readelf -W -h /lib64/libc-2.32.so | grep DYN
Jenis: DYN (Berkas objek bersama)
Aktifkan PIE
Untuk mengaktifkan PIE pada program pengujian, kirim argumen berikut ke kompiler:
$ gcc -pie -fpie hello.c -o hello
Anda dapat memverifikasi PIE diaktifkan menggunakan checksec:
$ checksec --file=./hello --output=json | jq | grep pie
"pie":"ya",
$
Itu harus ditampilkan sebagai PIE yang dapat dieksekusi dengan jenis yang diubah dari EXEC
ke DYN
:
$ file hello
hello:ELF 64-bit LSB pie executable, x86-64, versi 1 (SYSV), tertaut secara dinamis, interpreter /lib64/ld-linux-x86-64.so.2, BuildID [sha1]=bb039adf2530d97e02f534a94f0f668cd540f940, untuk GNU/Linux 3.2.0, tidak dilucuti
$ readelf -W -h ./hello | grep DYN
Jenis: DYN (Berkas objek bersama)
4. NX
NX adalah singkatan dari "non-executable." Ini sering diaktifkan pada tingkat CPU, sehingga sistem operasi dengan NX diaktifkan dapat menandai area memori tertentu sebagai tidak dapat dieksekusi. Seringkali, eksploitasi buffer-overflow menempatkan kode pada tumpukan dan kemudian mencoba mengeksekusinya. Namun, membuat area yang dapat ditulis ini tidak dapat dieksekusi dapat mencegah serangan tersebut. Properti ini diaktifkan secara default selama kompilasi reguler menggunakan gcc
:
$ checksec --file=/bin/ls --output=json | jq | grep nx
"nx":"ya",
$ checksec --file=./hello --output=json | jq | grep nx
"nx":"ya",
Checksec menentukan informasi ini dengan perintah di bawah ini. RW
menjelang akhir berarti tumpukan dapat dibaca dan ditulis; karena tidak ada E
, itu tidak dapat dieksekusi:
$ readelf -W -l ./hello | grep GNU_STACK
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
Nonaktifkan NX untuk tujuan demo
Ini tidak disarankan, tetapi Anda dapat menonaktifkan NX
saat mengkompilasi program dengan menggunakan -z execstack
argumen:
$ gcc -z execstack hello.c -o hello
$ checksec --file=./hello --output=json | jq | grep nx
"nx":"tidak",
Setelah kompilasi, tumpukan menjadi dapat dieksekusi (RWE
), yang memungkinkan kode berbahaya untuk dieksekusi:
$ readelf -W -l ./hello | grep GNU_STACK
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10
5. RELRO
RELRO adalah singkatan dari Relokasi Read-Only. Biner Executable Linkable Format (ELF) menggunakan Global Offset Table (GOT) untuk menyelesaikan fungsi secara dinamis. Saat diaktifkan, properti keamanan ini membuat GOT dalam biner hanya-baca, yang mencegah beberapa bentuk serangan relokasi:
$ checksec --file=/bin/ls --output=json | jq | grep relro
"relro":"full",
$ checksec --file=./hello --output=json | jq | grep relro
"relro":"partial",
Checksec menemukan informasi ini dengan menggunakan perintah di bawah ini. Di sini, salah satu properti RELRO diaktifkan; oleh karena itu, biner menunjukkan "sebagian" saat memverifikasi melalui checksec:
$ readelf -W -l ./hello | grep GNU_RELRO
GNU_RELRO 0x002e10 0x00000000000403e10 0x0000000000403e10 0x0001f0 0x0001f0 R 0x1
$ readelf -W -d ./hello | grep BIND_NOW
Aktifkan RELRO penuh
Untuk mengaktifkan RELRO penuh, gunakan argumen baris perintah berikut saat mengompilasi dengan gcc
:
$ gcc -Wl,-z,relro,-z,sekarang hello.c -o hello
$ checksec --file=./hello --output=json | jq | grep relro
"relro":"penuh",
Sekarang, properti kedua juga diaktifkan, membuat program RELRO penuh:
$ readelf -W -l ./hello | grep GNU_RELRO
GNU_RELRO 0x002dd0 0x00000000000403dd0 0x0000000000403dd0 0x000230 0x000230 R 0x1
$ readelf -W -d ./hello | grep BIND_NOW
0x0000000000000018 (BIND_NOW)
6. Perkuat
Fortify adalah properti keamanan lain, tetapi di luar cakupan artikel ini. Saya akan belajar bagaimana checksec memverifikasi fortify di binari dan bagaimana itu diaktifkan dengan gcc
sebagai latihan untuk Anda atasi.
$ checksec --file=/bin/ls --output=json | jq | grep -i forti
"fortify_source":"yes",
"fortified":"5",
"fortify-able":"17"
$ checksec --file=./hello --output=json | jq | grep -i forti
"fortify_source":"no",
"fortified":"0",
"fortify-able":"0"
Fitur checksec lainnya
Topik keamanan tidak pernah berakhir, dan meskipun tidak mungkin untuk membahas semuanya di sini, saya ingin menyebutkan beberapa fitur lagi dari checksec
perintah yang membuatnya menyenangkan untuk digunakan.
Berjalan melawan banyak biner
Anda tidak harus memberikan setiap biner ke checksec satu per satu. Sebagai gantinya, Anda dapat memberikan jalur direktori tempat beberapa binari berada, dan checksec akan memverifikasi semuanya untuk Anda sekaligus:
$ checksec --dir=/usr/bin
Proses
Selain binari, checksec juga bekerja pada program selama eksekusi. Perintah berikut menemukan properti keamanan dari semua program yang berjalan di sistem Anda. Anda dapat menggunakan --proc-all
jika Anda ingin memeriksa semua proses yang berjalan, atau Anda dapat memilih proses tertentu dengan menggunakan namanya:
$ checksec --proc-all
$ checksec --proc=bash
Properti kernel
Selain aplikasi userland checksec yang dijelaskan dalam artikel ini, Anda juga dapat menggunakannya untuk memeriksa properti kernel yang dibangun ke dalam sistem Anda:
$ checksec --kernel
Cobalah
Checksec adalah cara yang baik untuk memahami properti userland dan kernel apa yang diaktifkan. Pelajari setiap properti keamanan secara mendetail, dan coba pahami alasan pengaktifan setiap fitur dan jenis serangan yang dicegahnya.