Menghindari Terjadinya Lubang Keamanan Saat Mengembangkan Sebuah Aplikasi - Bagian 1

ArticleCategory:

Software Development

AuthorImage:

[image of the authors]

TranslationInfo:

Original in fr Frédéric Raynal, Christophe Blaess, Christophe Grenier

fr to en Georges Tarbouriech

en to id Razmal Djamal

AboutTheAuthor:

Christophe Blaess adalah seorang aeronautics engineer independen. Beliau seorang penggemar Linux dan banyak menghabiskan kerjanya pada system Linux ini. Beliau bertugas sebagai koordinator untuk publikasi alih bahasa dari halaman manual dari Linux Documentation Project.

Christophe Grenier adalah mahasiswa tahun ke 5 pada ESIEA, dimana dia bekerja sebagai sysadmin juga. Dia sangat berhasrat pada keamanan komputer .

Frédéric Raynal menggunakan Linux, sertifikasi tanpa (software atau yang lain) hak patent. Selain itu, Anda mesti melihat Dancer in the Dark : selain itu Björk yang hebat, film ini bisa membuat Anda tak bergerak (Saya tidak bisa berkata lebih tanpa memperlihatkan penutupannya, seluruh tragis dan kesenangan).

Abstract

Artikel ini adalah bagian pertama dari tulisan berseri mengenai jenis utama dari lubang keamanan pada sebuah aplikasi. Kami akan menunjukkan cara untuk menghindari kemunculan lubang keamanan tersebut dengan merubah sedikit kebiasaan pembuatan program Anda.

ArticleIllustration

[article illustartion]

ArticleBody

Perkenalan

Tidak membutuhkan lebih dari 2 minggu sebelum aplikasi besar yang termasuk bagian dari sebagian besar distribusi Linux menghadirkan lubang keamanan yang mengizinkan, sebagai contoh, user lokal menjadi root. Mengesampingkan kualitas yang hebat dari kebanyakan software ini, memastikan keamanan dari sebuah program adalah sebuah kerja keras : yang seharusnya tidak mengizinkan para penjahat untuk mendapatkan keuntungan ilegal dari kekayaan system .Ketersediaan dari kode sumber aplikasi adalah sesuatu yang baik, lebih banyak penghargaan oleh para programmer, tetapi gangguan terkecil dari software adalah menjadi terlihat untuk semua orang. Lebih jauh lagi, pendeteksian dari gangguan-gangguan tersebut muncul secara acak dan orang-orang yang menemukan gangguan tersebut tidak selalu punya perhatian yang baik. .

Dari sisi sysadmin , kerja harian mereka terdiri dari membaca daftar-daftar masalah keamanan dan sesegera mungkin melakukan update terhadap paket-paket yang terlibat dengan masalah tersebut. Untuk seorang programmer ini bisa menjadi sebuah pelajaran yang baik untuk mencoba beberapa masalah keamanan karena menghindari terjadinya lubang keamanan sejak awal adalah metode paling disarankan untuk memperbaiki lobang keamanan tersebut. Kami akan mencoba untuk memaparkan beberapa kebiasaan "klasik" yang berbahaya dan menyediakan solusi untuk menurunkan resikonya. Kami tidak akan berbicara masalah-masalah keamanan jaringan karena masalah jaringan tersebut muncul dari kesalahan konfigurasi (script-script cgi-bin yang berbahaya, ...) atau dari lubang system yang memperbolehkan DOS (Denial Of Service) type serangan yang menghalangi mesin untuk listen kepada client-nya sendiri. Masalah seperti ini mengacu ke sysadmin atau ke para pengembang kernel. Tetapi para programmer aplikasi mesti melindungi kode mereka segera setelah kode mengarah ke account external data. Beberapa versi dari pine, acroread, netscape, access,...telah mengizinkan elevated access atau kebocoran informasi untuk beberapa kondisi tertentu.Dan sebenarnya secure programming adalah urusan semua orang.

Seri artikel ini menunjukkan metode-metode yang bisa digunakan untuk merusak system Unix. Kami hanya bisa memaparkan metode-metode tersebut atau berkata sedikit tentang metode tersebut, tapi kami menyediakan penjelasan lengkap untuk membuat orang-orang mengerti resiko-resikonya. Dikarenakan, ketika mencari kesalahan program atau mengembangkan program Anda sendiri, Anda akan bisa untuk menghindari atau memperbaiki kesalahan-kesalahan ini. Untuk setiap lubang kesalahan yang kita diskusikan, kami akan mengambil pendekatan yang sama. Kami mulai dengan detail bagaimana kesalahan terjadi. Selanjutnya, kami akan memperlihatkan cara untuk menghindarinya. Untuk semua contoh kami akan menggunakan lubang keamanan yang masih tersebar luas pada software sekarang ini.

Artikel pertama ini bercerita tentang kebutuhan dasar untuk memahami lubang keamanan, yang menjadi titik dari privileges dan pada bit Set-UID atau Set-GID. Selanjutnya, kami menganalisa lubang berdasarkan pada fungsi system() dikarenakan hal ini lebih mudah untuk dipahami.

Kami juga akan sering menggunakan program C yang kecil untuk menggambarkan apa yang sedang kita bicarakan. Bagaimanapun, pendekatan-pendekatan yang dipaparkan pada seri artikel ini bisa di aplikasikan dengan bahasa pemrograman lain : perl, java, shell scripts... Beberapa lubang keamanan bergantung pada bahasanya, tetapi ini tidak benar untuk semua seperti yang akan kita lihat dengan fungsi system().

Privileges

Pada system Unix, para pengguna (user) tidaklah sama, begitu pula dengan aplikasi. Akses pada node-node file system - dan menuruti periferal mesin - bermuara pada kontrol identitas secara langsung. Beberapa user diizinkan untuk melakukan operasi sensitif untuk mengurusi system dalam kondisi yang bagus. Nomer-nomer yang disebut UID (User Identifier) mengizinkan proses pengenalan (identification). Untuk membuat segala sesuatu menjadi lebih mudah, nama user berkorespondensi dengan nomer UID ini, proses asosiasi ini terjadi pada file /etc/passwd

Kode UID 0, dengan nama default-nya root, bisa mengakses segalanya pada system. Dia bisa membuat, merubah, dan menghapus seluruh system node, tapi dia juga bisa dengan baik mengurusi konfigurasi secara fisik dari mesin, melakukan mounting pada partisi, mengaktifkan kartu interface jaringan dan merubah konfigurasinya (IP address), atau menggunakan system call seperti mlock() untuk beraksi pada memori fisik, atau sched_setscheduler() untuk mengganti mekanisme permintaan system. Pada artikel yang akan datang kita akan mempelajari fitur dari Posix.1e yang memperbolehkan pembatasan terhadap privileges dari sebuah aplikasi yang dijalankan sebagai root, tapi sekarang, mari kita asumsikan the super-user bisa melakukan segala hal pada mesin.

Serangan yang akan kita paparkan adalah yang dari dalam, dari user ber-otorisasi pada mesin, mencoba untuk meningkatkan hak pakai yang tidak dia punyai. Di sisi lain, serangan pada jaringan ada pula yang dari luar, datang dari orang-orang yang mencoba untuk terhubung ke mesin yang mana mereka tidak diijinkan untuk itu..

Untuk menggunakan hak pakai cadangan untuk pemakai yang lain tanpa tercatat sebagai pemakai tersebut, seseorang mesti mempunyai minimal kesempatan untuk berbicara ke aplikasi yang dijalankan dibawah UID korban. Ketika sebuah aplikasi - sebuah proses - berjalan pada Linux, maka dia mempunyai sebuah identitas yang jelas. Pertama, program mempunyai sebuah atribut yang disebut RUID (RealUID) berkoresponden ke user ID yang menjalankannya. Data ini di urusi oleh kernel dan bisanya tidak bisa diubah. Begitu atribut menyelesaikan informasi tersebut :field pada EUID (Effective UID)berkoresponden ke identitas yang kernel bawa ke account user ketika mengurusi hak akses (membuka file,system-calls cadangan).

Untuk mendapatkan privileges dari user lain yang berarti semua hal bisa dilakukan dibawah UID user tersebut, dan tidak pada UID yang seharusnya. Tentunya, seorang cracker mencoba untuk mendapatkan ID dari root ,tapi banyak user yang lain juga menarik , dikarenakan mereka bisa memberikan akses ke informasi dari system (news, mail, lp...) atau karena mereka mengijinkan membaca data pribadi (mail, file pribadi, dll) atau mereka dapat digunakan untuk menyembunyikan aktifitas ilegal seperti serangan dari situs yang lain.

Untuk menjalankan aplikasi dengan privileges dari Effective UID yang berbeda dari UID sebenarnya (user yang menjalankannya) file eksekusi harus mempunyai bit tertentu yang di aktifkan, yang disebut Set-UID. Bit ini ditemukan pada atribut file (seperti User execute,read, write bits, anggota group atau yang lain) dan mempunyai nilai oktal 4000. Bit Set-UID diwakili dengan kode s ketika menampilkan hak-hak pakai dengan perintah ls :

>> ls -l /bin/su
-rwsr-xr-x  1 root  root  14124 Aug 18  1999 /bin/su
>> 
 
Perintah "find / -type f -perm +4000" menampilkan daftar dari aplikasi-aplikasi system yang bit Set-UID mereka di set ke 1, atau diaktifkan. Ketika kernel menjalankan applikasi dengan bit Set-UID on, kernel menggunakan identitas EUID si empunya program EUID untuk proses itu. Dengan kata lain ,RUID tidak berubah dan berkorespondensi dengan user yang menjalankan program. Sebagai gambaran, setiap user mempunyai akses ke perintah /bin/su, tetapi perintah ini berjalan dibawah identitas pemilik program dalam hal ini (root) dengan seluruh privileges pada system. Penting untuk dikatakan, bahwa seseorang mesti sangat berhati-hati ketika menulis program dengan atribut seperti ini.

Setiap proses juga mempunyai Effective group ID, EGID, dan tanda pengenal asli disebut RGID (Real GID). Bit Set-GID (2000 dalam octal) dalam hak akses dari file eksekusi , bertanya ke kernel untuk menggunakan identitas group dari pemilik file sebagai EGID dan bukan GID dari user yang menjalankan program. Kombinasi yang serius terkadang muncul dengan Set-GID yang di set ke 1 tapi tanpa bit eksekusi group. Kenyataannya, kejadian ini tidak ada hubungannya dengan privileges yang berhubungan dengan aplikasi, tetapi mengindikasikan bahwa file bisa di block dengan fungsi fcntl(fd, F_SETLK, lock). Biasanya sebuah aplikasi tidak menggunakan bit Set-GID, tapi itu tidak terjadi setiap kali. Beberapa game, sebagai gambaran, menggunakan proses itu utnuk menyimpan score terbesar ke direktori system .

Jenis-Jenis Serangan dan Target-target Yang Potensial

Ada banyak jenis dan type serangan terhadap system. Hari ini kita mempelajari mekanisme untuk menjalankan perintah external dari dan bersama aplikasi. Ini biasanya sebuah shell yang berjalan dibawah identity dari empunya aplikasi. Type kedua dari serangan mengarah ke buffer overflow memberikan penyerang kemampuan untuk menjalankan kode atau instruksi pribadi. Terakhir, Type serangan utama yang ketiga berdasar kepada race condition - selisih waktu antara dua instruksi dimana komponen system berubah (biasanya berupa file) yang mana aplikasi masih percaya bahwa itu berasal dari sumber yang sama.

Dua type serangan pertama biasanya mencoba mengeksekusi shell menggunakan privileges dari empunya aplikasi, sementara type yang ketiga ditargetkan pada mendapatkan hak akses menulis ke file system yang terproteksi. Akses membaca terkadang mengarah ke kelemahan dari keamanan system (file-file pribadi, email, file password /etc/shadow, and file konfigurasi pseudo kernel pada /proc).

Target-target pada serangan keamanan sebagian besar kepada program yang mempunyai bit Set-UID (atau Set-GID) on. Bagaimanapun, ini juga mempengaruhi setiap aplikasi yang berjalan dibawah ID yang berbeda ID dibanding user-nya. Daemon-daemon system mewakili bagian yang besar dari program-program ini. Daemon adalah aplikasi yang bisanya di jalankan saat boot, berjalan di latar belakang tanpa ada terminal kontrol, dan melakukan kerja dengan privilege untuk setiap user. Sebagai contoh, daemon lpd mengijinkan semua user untuk mengirimkan dokumen ke printer, sendmail menerima dan meneruskan surat elektronik, atau apmd bertanya ke Bios mengenai status baterai dari sebuah laptop. Beberapa daemon bertugas terhadap komunikasi dengan user dari luar melalui jaringan (Ftp, Http, Telnet... services). Server bernama inetd mengurusi koneksi-koneksi dari banyak jenis service ini.

Lalu kita bisa memutuskan bahwa program bisa diserang begitu program berkomunikasi - biarpun secara perlahan - kepada user yang berbeda dengan user yang menjalankannya. Saat mengembangkan aplikasi type ini Anda mesti berhati-hati untuk memikirkan resiko-resiko yang dipaparkan oleh function yang akan kita pelajari disini.

Mengubah Level-Level Privileges

Ketika sebuah aplikasi berjalan dengan EUID yang berbeda dibanding RUID-nya, adalah bertujuan untuk menyediakan pemakai privileges yang dia butuhkan tetapi tidak mempunyai privileges tersebut (Hak akses file, system calls cadangan...). Walau begitu privileges tersebut dibutuhkan hanya untuk waktu yang sangat singkat, sebagai contoh ketika membuka sebuah file, dengan kata lain aplikasi dapat berjalan dengan privileges privileges-nya. Menjadi mungkin untuk sementara mengubah EUID aplikasi dengan menggunakan system-call :

  int seteuid (uid_t uid);
Sebuah proses selalu dapat mengubah nilai EUID-nya memberikan salah satu nilai dari RUID. Pada kasus tersebut, UID terdahulu tersimpan pada field yang disebut SUID (Saved UID) yang berbeda dari SID (Session ID) yang berguna untuk pengurusan terminal kontrol . Selalu menjadi mungkin untuk mendapatkan SUID kembali dan menggunakannya sebagai EUID. Tentu saja, program yang mempunyai EUID (root) dapat berubah seketika termasuk EUID dan RUID-nya (begitulah cara /bin/su bekerja).

Untuk mengurangi resiko dari serangan-serangan, disarankan untuk mengubah EUID dan juga mengubah RUID dari user. Ketika ada bagian dari kode membutuhkan privileges yang berhubungan dengan para pemilik file, sangat memungkinkan untuk menempatkan kode dari Saved UID ke EUID. Berikut sebagai contoh :

  
  uid_t e_uid_initial;
  uid_t r_uid;
    
  int
  main (int argc, char * argv [])
  {
    /* Saves the different UIDs */
    e_uid_initial = geteuid ();
    r_uid = getuid ();

    /* limits access rights to the ones of the 
     * user launching the program */
    seteuid (r_uid);
    ...
    privileged_function ();
    ...
  }
  
  void
  privileged_function (void)
  {
    /* Gets initial privileges back */
    seteuid (e_uid_initial);
    ...
    /* Portion needing privileges */
    ...
    /* Back to the rights of the runner */
    seteuid (r_uid);
  }  
 

Metode ini sangat lebih aman dibandingkan dengan semua ketidakberuntungan pada metode-metode umum terdiri dari penggunaan inisialisasi EUID dan pengurangan sementara privileges sesaat sebelum melakukan operasi "beresiko". Bagaimanapun pengurangan privilege ini tidaklah berguna menghadapi serangan buffer-overflow. Seperti yang akan kita lihat pada artikel selanjutnya, serangan serangan ini bertujuan untuk meminta pada aplikasi untuk mengeksekusi instruksi pribadi dan bisa saja mengandung system-calls yang dibutuhkan untuk membuat level privilege menjadi lebih tinggi. Dan pada akhirnya, pendekatan ini akan melindungi program dari perintah-perintah external dan dari kebanyakan race conditions.

Menjalankan Perintah External

Terkadang sebuah aplikasi butuh untuk memanggil perintah atau service external system. Sebuah contoh yang telah dikenal dengan baik seperti perintah mail untuk mengurusi surat elektronik (menjalankan laporan, alarm, statistik, etc) tanpa membutuhkan dialog yang rumit dengan mail system. Solusi yang termudah adalah dengan menggunakan fungsi library :

  int system (const char * command)

Bahaya-Bahaya Dari Fungsi system()

Fungsi ini lebih berbahaya : dia akan memanggil shell untuk menjalankan perintah yang diberikan sebagai argumen. Perilaku shell bergantung pada pilihan dari userr. Sebuah contoh sederhana datang dari lingkungan PATH variabel lingkungan. Mari kita lihat aplikasi yang memanggil fungsi mail . Sebagai gambaran, program berikut ini mengirimkan kode sumbernya kepada pemakai yang menjalankannya :

/* system1.c */

#include <stdio.h>
#include <stdlib.h>

int
main (void)
{
  if (system ("mail $USER < system1.c") != 0)
    perror ("system");
  return (0);
}
Katakanlah program ini ber Set-UID root :
>> cc system1.c -o system1
>> su
Password:
[root] chown root.root system1
[root] chmod +s system1
[root] exit
>> ls -l system1
-rwsrwsr-x  1 root  root  11831  Oct 16  17:25 system1
>>
 
Untuk menjalankan program ini,system menjalankan shell (dengan /bin/sh) dan dengan opsi -c , memberikan instruksi untuk invoke. Lalu shell tersebut menelusuri hirarki direktori berdasarkan pada lingkungan variabel PATH untuk menemukan perintah yang disebut mail. Untuk menguasai program, pemakai hanya harus merubah isi dari variabel ini sebelum menjalankan aplikasi. Sebagai contoh :
  >> export PATH=.
  >> ./system1
 
perhatikan perintah mail hanya pada direktori aktif-nya. Seseorang hanya butuh untuk membuat file eksekusi (sebagai contoh , sebuah script yang menjalankan shell baru) dan memberinya nama mail maka program akan di jalankan dengan EUID dari pemilik aplikasi utama ! Disini, script kami menjalankan /bin/sh. Akan tetapi, karena ini dijalankan dengan merubah arah standard input (seperti inisialisasi perintah mail), kita harus mendapatkannya kembali pada terminal. Lalu kita membuat script berikut :
#! /bin/sh
# "mail" script running a shell
# getting its standard input back.
/bin/sh < /dev/tty
 
Dan inilah hasilnya :
>> export PATH="."
>> ./system1
bash# /usr/bin/whoami
  root
bash# 
 

Tentu saja, solusi pertama mengarah ke pemberian path penuh kepada program, sebagai contoh /bin/mail. Lalu sebuah program baru muncul : aplikasi bersandar pada instalasi system. Jika program /bin/mail biasanya tersedia pada seluruh system, dimana GhostScript, sebagai contoh? (dia ada di /usr/bin, /usr/share/bin, /usr/local/bin ?). Disisi lain, jenis lain dari serangan menjadi mungkin dengan beberapa shell yang sudah lawas : penggunaan dari lingkungan variable IFS. Shell menggunakannya untuk melewatkan kata-kata pada command line. Variabel ini mempunyai karakter pemisah . Default karakter ini adalah spasi, tab dan return. Jika pengguna menambahkan slash /, perintah "/bin/mail" dipahami oleh shell sebagai "bin mail". Sebuah file eksekusi yang disebut bin pada direktorinya sendiri bisa dijalankan hanya dengan mengubah setting PATH, seperti yang telah kita lihat sebelumnya,dan mengizinkan untuk menjalankan program ini dengan EUID aplikasi.

Pada Linux, lingkungan variabel IFS bukan lagi sebuah masalah sejak bash dan pdksh kedua-duanya melengkapinya dengan karakter-karakter default saat startup. Tetapi memikirkan tentang portability dari aplikasi anda harus berhati-hati bahwa beberapa system mungkin lebih sedikit tidak aman menanggapi variabel ini.

Beberapa Lingkungan variabel lain mungkin menyebabkan masalah-masalah yang tidak diharapkan. Sebagai contoh, aplikasi mail membolehkan user-user untuk menjalankan perintah sembari membuat pesan menggunakan urutan escape "~!". Jika user menulis string "~!command" pada awal baris, maka perintah akan berjalan. Program /usr/bin/suidperl digunakan untuk membuat script-script perl bekerja dengan bit Set-UID yang disebut /bin/mail untuk mengirimkan pesan ke root ketika mendeteksi sebuah masalah. Karena /bin/mail ber Set-UID root, panggilan ke /bin/mail dilakukan dengan privileges root dan mengandung nama dari file yang bermasalah. Lalu user dapat membuat sebuah file yang namanya mengandung karakter carriage return diikuti dengan urutan ~!command dan carriage return yang lain. Jika script perl itu memanggil suidperl dan gagal pada masalah low-level yang berkaitan dengan file ini, sebuah pesan akan terkirim melalui identitas root ,berisi urutan escape dari aplikasi mail, dan perintah pada nama file yang dijalankan dengan privileges yang dipunyai root.

Masalah ini seharusnya tidak ada dikarenakan program mail tidak mendukung untuk menerima urutan (escape sequences) ketika berjalan otomatis (bukan dari terminal). Sayangnya, fitur yang tak tercatat dari aplikasi ini (mungkin ketinggalan saat debugging), mengijinkan escape sequences sesaat begitu lingkungan variabel interactive di set. Dan hasilnya? Sebuah lubang keamanan dengan mudahnya di exploitasi (dan ter-exploitasi secara luas) didalam sebuah aplikasi yang seharusnya membuktikan keamanan system . Dan kesalahan terbagi. Pertama, /bin/mail mempunyai opsi tak tercatat terutama menjadi berbahaya saat mengijinkan eksekusi kode hanya memeriksa data yang terkirim, yang seharusnya menjadi kecurigaan utama untuk sebuah aplikasi mail. Kedua, biarpun jika pengembang /usr/bin/suidperl tidak memperhatikan variabel interactive , mereka seharusnya tidak meninggalkan lingkungan eksekusi seperti saat memanggil perintah external , terutama saat menulis program ber-Set-UID root ini.

Kenyataannya, Linux tidak memperdulikan bit Set-UID dan Set-GID ketika menjalankan script-script (baca /usr/src/linux/fs/binfmt_script.c dan /usr/src/linux/fs/exec.c). Tetapi beberapa trik mneginjinkan Anda untuk mem- bypass aturan ini, seperti Perl lakukan dengan script-nya sendiri menggunakan /usr/bin/suidperl untuk mengambil bit-bit tersebut ke account.

Solusi-Solusi

Tidak selamanya mudah untuk menemukan penggantian untuk fungsi system(). Variasi pertama adalah menggunakan system-calls seperti execl() atau execle(). Bagaimanapun, itu akan sedikit berbeda dikarenakan program external program tidak lagi disebut sebagai sebuah sub rutin, selain perintah yang terlibat menggantikan proses yang sedang terjadi. Anda mesti melakukan fork pada proses dan melewatkan argumen pada baris perintah. Kemudian program :

  if (system ("/bin/lpr -Plisting stats.txt") != 0) {
    perror ("Printing");
    return (-1);
  }
 
menjadi :
pid_t pid;
int   status;
  
if ((pid = fork()) < 0) {
  perror("fork");
  return (-1);
}
if (pid == 0) {
  /* child process */
  execl ("/bin/lpr", "lpr", "-Plisting", "stats.txt", NULL);
  perror ("execl");
  exit (-1);
}
/* father process */
waitpid (pid, & status, 0);
if ((! WIFEXITED (status)) || (WEXITSTATUS (status) != 0)) {
  perror ("Printing");
  return (-1);
}
 
Biasanya, kode menjadi lebih berat! Dalam beberapa situasi, menjadi lumayan rumit, sebagi contoh, ketika Anda mesti mengubah arah (redirect) standar input aplikasi seperti pada :
system ("mail root < stat.txt");
 
Begitulah, pengubahan arah ditentukan oleh < dikerjakan melalui shell. Anda dapat melakukan hal yang sama, menggunakan urutan yang rumit seperti pada fork(), open(), dup2(), execl(), dll. Pada kasus tersebut, sebuah solusi yang dapat diterima akan menggunakan fungsi system(), tetapi melakukan konfigurasi ke seluruh lingkungan (environment).

Pada Linux, variabel lingkungan disimpan pada form dari pointer ke tabel karakter : char ** environ. Tabel ini berakhir dengan NULL. String berada diluar dari form "NAME=value".

Kita mulai menghilangkan variabel Lingkungan menggunakan Gnu extension :

    int clearenv (void);
 
atau memaksakan pointer
    extern char ** environ;
 
untuk mengambil nilai NULL . Selanjutnya variabel-variabel lingkungan di inisialisasikan, menggunakan nilai terkontrol, dengan fungsi :
    int setenv (const char * name, const char * value, int remove)
    int putenv(const char *string)
 
sebelum memanggil fungsi system(). Sebagai contoh :
    clearenv ();
    setenv ("PATH", "/bin:/usr/bin:/usr/local/bin", 1);
    setenv ("IFS", " \t\n", 1);
    system ("mail root < /tmp/msg.txt");
 
Jika dibutuhkan, Anda bisa menyimpan isi dari ebberapa variabel yang berguna sebelum membuang lingkungan (HOME, LANG, TERM, TZ,dll.). Isi ,form, ukuran dari variabel-variabel ini mesti diperiksa. Sangatlah penting bahwa Anda membuang seluruh lingkungan sebelum mendefinisikan ulang variabel. Lubang keamanan suidperl tidak seharusnya muncul jika environment telah dibuang dengan baik.

Analoginya, melindungi sebuah mesin dalam jaringan akan menolak seluruh koneksi. Selanjutnya, sysadmin mengaktifkan service yang dibutuhkan atau yang berguna . Dengan cara yang sama, ketika membuat aplikasi ber- Set-UID environment harus bersih baru kemudian diisi dengan variabel yang dibutuhkan.

Verifikasi format parameter dilakukan dengan membandingkan nilai yang diharapkan dengan format yang diizinkan. Jika proses perbandingan sukses maka parameter ter-validasi. Dengan kata lain, ditolak. Jika Anda menjalankan percobaan menggunakan daftar dari nilai-nilai ber-format invalid, resiko dari meninggalkan nilai yang salah akan meningkat dan ini bisa menjadi bencana bagi system.

Kita mesti memahami bahaya pada system() adalah juga bahaya untuk beberapa fungsi seperti popen(), atau dengan system-calls seperti execlp() atau execvp() diambil ke account variabel PATH.

Eksekusi Tidak Langsung Dari Sebuah Perintah

Untuk meningkatkan kemampuan pakai dari program, mudah untuk memberikan user kemampuan untuk mengkonfigurasikan sebagian besar kelakukan software menggunakan macro, sebagai contoh. Untuk mengurusi variabel atau pola generic seperti yang dilakukan oleh shell , terdapat fungsi yang hebat disebut wordexp(). Anda mesti berhati-hati dengan hal ini, karena mengirimkan string seperti $(command) mengizinkan eksekusi dari perintah external yang disebutkan. Memberikan string "$(/bin/sh)" membuat sebuah shell ber-Set-UID. Untuk menghindari hal ini, wordexp() mempunyai atribut yang disebut WRDE_NOCMD yang me-non-aktifkan interpretasi dari urutan $( ) .

Ketika melibatkan perintah external Anda mesti berhati-hati untuk tidak memanggil utility yang menyediakan mekanismen escape ke shell (seperti sequence vi :!command). Sangat susah untuk mendata semua utiliti tersebut, beberapa aplikasi mencurigakan (text editors, file managers...) yang lain sulit untuk dideteksi (seperti yang telah kita lihat /bin/mail) atau mempunyai mode debugging berbahaya.

Kesimpulan

Artikel ini meng-ilustrasikan bermacam-macam aspek :

Artikel selanjutnya akan berbicara mengenai memory, organisasinya, dan pemanggilan fungsinya sebelum meraih buffer overflows. Kita juga akan melihat bagaimana membangun sebuah shellcode.