Saya perlu menyembunyikan beberapa argumen sensitif ke program yang saya jalankan, tetapi saya tidak memiliki akses ke kode sumber. Saya juga menjalankan ini pada server bersama sehingga saya tidak dapat menggunakan sesuatu seperti hidepid
karena saya tidak memiliki hak sudo.
Inilah beberapa hal yang telah saya coba:
export SECRET=[my arguments]
, diikuti dengan panggilan ke./program $SECRET
, tetapi ini sepertinya tidak membantu../program `cat secret.txt`
manasecret.txt
berisi argumen saya, tetapi yang maha kuasaps
mampu mengendus rahasiaku.
Apakah ada cara lain untuk menyembunyikan argumen saya yang tidak melibatkan intervensi admin?
ps
tidak melakukan sesuatu yang ajaib untuk "mengendus rahasia Anda". Lagi pula, program yang ditulis secara wajar sebagai gantinya harus menawarkan opsi baris perintah untuk membaca rahasia dari file yang ditentukan atau dari stdin alih-alih menganggapnya langsung sebagai argumen.Jawaban:
Seperti dijelaskan di sini , Linux menempatkan argumen program di ruang data program, dan membuat pointer ke awal area ini. Inilah yang digunakan oleh
ps
dan seterusnya untuk menemukan dan menunjukkan argumen program.Karena data berada dalam ruang program, ia dapat memanipulasinya. Melakukan ini tanpa mengubah program itu sendiri melibatkan memuat shim dengan
main()
fungsi yang akan dipanggil sebelum utama sebenarnya dari program. Shim ini dapat menyalin argumen asli ke ruang baru, lalu menimpa argumen asli sehinggaps
hanya akan melihat nuls.Kode C berikut melakukan ini.
Tidak dimungkinkan untuk melakukan intervensi
main()
, tetapi Anda dapat melakukan intervensi pada fungsi standar C library__libc_start_main
, yang selanjutnya disebut main. Kompilasi file inishim_main.c
seperti yang tercantum dalam komentar di awal, dan jalankan seperti yang ditunjukkan. Saya telah meninggalkanprintf
kode sehingga Anda memeriksa apakah itu benar-benar dipanggil. Misalnya, jalankankemudian lakukan
ps
dan Anda akan melihat perintah kosong dan args ditampilkan.Masih ada sedikit waktu di mana perintah args dapat terlihat. Untuk menghindari ini, Anda bisa, misalnya, mengubah shim untuk membaca rahasia Anda dari file dan menambahkannya ke argumen yang diteruskan ke program.
sumber
/proc/pid/cmdline
akan menunjukkan rahasianya (sama seperti ketikacurl
mencoba menyembunyikan kata sandi yang diberikan pada baris perintah). Saat Anda menggunakan LD_PRELOAD, Anda bisa membungkus utama sehingga rahasia disalin dari lingkungan ke argumen yang diterima utama. Seperti panggilanLD_PRELOAD=x SECRET=y cmd
tempat Anda meneleponmain()
denganargv[]
menjadi[argv[0], getenv("SECRET")]
/proc/pid/environ
. Ini mungkin ditimpa dengan cara yang sama seperti args, tetapi meninggalkan jendela yang sama./proc/pid/cmdline
adalah publik,/proc/pid/environ
bukan. Ada beberapa sistem di manaps
(setuid dieksekusi di sana) mengekspos lingkungan dari setiap proses, tapi saya tidak berpikir Anda akan menemukan apa pun saat ini. Lingkungan umumnya dianggap cukup aman . Tidak aman untuk mengorek dari proses dengan cairan yang sama, tetapi itu sering dapat membaca memori proses dengan cairan yang sama, jadi tidak banyak yang bisa Anda lakukan tentang itu.main
metode program yang dibungkus juga menghilangkan variabel lingkungan untuk menghindari kebocoran yang tidak disengaja pada proses anak. Atau pembungkus bisa membaca semua argumen baris perintah dari file.Baca dokumentasi antarmuka baris perintah aplikasi yang dipermasalahkan. Mungkin ada opsi untuk memasok rahasia dari file alih-alih sebagai argumen secara langsung.
Jika itu gagal, ajukan laporan bug terhadap aplikasi dengan alasan bahwa tidak ada cara aman untuk memberikan rahasia padanya.
Anda selalu dapat dengan hati-hati (!) Menyesuaikan solusi dalam jawaban meuh dengan kebutuhan spesifik Anda. Berikan perhatian khusus pada komentar Stéphane dan tindak lanjutnya.
sumber
Jika Anda perlu menyampaikan argumen ke program untuk membuatnya bekerja, Anda akan kurang beruntung tidak peduli apa yang Anda lakukan jika Anda tidak dapat menggunakan
hidepid
pada procfs.Karena Anda menyebutkan ini adalah skrip bash, Anda harus sudah memiliki kode sumber, karena bash bukan bahasa yang dikompilasi.
Jika gagal, Anda mungkin dapat menulis ulang cmdline proses menggunakan
gdb
atau serupa dan bermain-main denganargc
/argv
begitu sudah dimulai, tetapi:Saya benar-benar hanya merekomendasikan mendapatkan kode sumber, atau berbicara dengan vendor untuk mendapatkan kode yang dimodifikasi. Memberikan rahasia pada baris perintah dalam sistem operasi POSIX tidak kompatibel dengan operasi yang aman.
sumber
Ketika suatu proses mengeksekusi perintah (melalui
execve()
panggilan sistem), memorinya dihapus. Untuk meneruskan beberapa informasi di eksekusi,execve()
panggilan sistem membutuhkan dua argumen untuk itu:argv[]
danenvp[]
array.Itu adalah dua array string:
argv[]
berisi argumenenvp[]
berisi definisi variabel lingkungan sebagai string dalamvar=value
format (berdasarkan konvensi).Saat kamu melakukan:
(di sini menambahkan tanda kutip yang hilang di sekitar ekspansi parameter).
Anda mengeksekusi
cmd
dengan rahasia (value
) yang dilewati diargv[]
danenvp[]
.argv[]
akan ada["cmd", "value"]
danenvp[]
sesuatu seperti[..., "PATH=/bin:...", "HOME=...", ..., "SECRET=value", "TERM=xterm", ...]
. Ascmd
tidak melakukan apa pungetenv("SECRET")
atau yang setara untuk mengambil nilai rahasia dari ituSECRET
variabel lingkungan itu, meletakkannya di lingkungan tidak berguna.argv[]
adalah pengetahuan umum. Itu ditunjukkan dalam output darips
.envp[]
saat ini tidak. Di Linux, ini terlihat di/proc/pid/environ
. Ini ditunjukkan dalam outputps ewww
pada BSD (dan dengan procps-ngps
di Linux), tetapi hanya untuk proses yang berjalan dengan uid efektif yang sama (dan dengan lebih banyak pembatasan untuk executable setuid / setgid). Mungkin terlihat di beberapa log audit, tetapi log audit tersebut hanya dapat diakses oleh administrator.Singkatnya, lingkungan yang diteruskan ke yang dapat dieksekusi dimaksudkan untuk bersifat pribadi atau paling tidak sama privatnya dengan memori internal suatu proses (yang dalam beberapa keadaan proses lain dengan hak istimewa juga dapat mengakses dengan debugger misalnya dan dapat juga akan dibuang ke disk).
Karena
argv[]
pengetahuan publik, perintah yang mengharapkan data yang dirahasiakan pada baris perintahnya rusak oleh desain.Biasanya, perintah yang perlu diberi rahasia, memberi Anda antarmuka lain untuk melakukannya, seperti melalui variabel lingkungan. Contohnya:
Atau melalui deskriptor file khusus seperti stdin:
(
echo
sedang dibangun, itu tidak ditampilkan dalam output ofps
)Atau file, seperti
.netrc
untukftp
dan beberapa perintah lain atauBeberapa aplikasi seperti
curl
(dan itu juga pendekatan yang diambil oleh @meuh di sini ) mencoba untuk menyembunyikan kata sandi yang mereka terimaargv[]
dari mencongkel mata (pada beberapa sistem dengan menimpa bagian memori di manaargv[]
string disimpan). Tapi itu tidak benar-benar membantu dan memberikan janji keamanan palsu. Yang meninggalkan jendela di antaraexecve()
dan menimpa di manaps
masih akan menunjukkan rahasianya.Misalnya, jika penyerang tahu bahwa Anda menjalankan skrip yang melakukan
curl -u user:somesecret https://...
(misalnya dalam tugas cron), yang harus ia lakukan adalah mengusir dari cache (banyak) perpustakaan yangcurl
menggunakan (misalnya dengan menjalankan ash -c 'a=a;while :; do a=$a$a;done'
) jadi untuk memperlambat startup-nya, dan bahkan melakukan yang sangat tidak efisienuntil grep 'curl.*[-]u' /proc/*/cmdline; do :; done
sudah cukup untuk menangkap kata sandi itu dalam pengujian saya.Jika argumen adalah satu-satunya cara Anda bisa meneruskan rahasia ke perintah, mungkin masih ada beberapa hal yang bisa Anda coba.
Pada beberapa sistem, termasuk versi Linux yang lebih lama, hanya beberapa byte pertama (4096 pada Linux 4.1 dan sebelumnya) dari string yang
argv[]
dapat di -query.Di sana, Anda bisa melakukan:
Dan rahasianya akan disembunyikan karena melewati 4096 byte pertama. Sekarang orang yang telah menggunakan metode itu harus menyesal sekarang karena Linux sejak 4.2 tidak lagi memotong daftar argumen di
/proc/pid/cmdline
. Perhatikan juga bahwa ini bukan karena tidakps
akan menampilkan lebih dari byte byte perintah (seperti pada FreeBSD yang sepertinya terbatas pada 2048) yang tidak bisa digunakan oleh pengguna API yang samaps
untuk mendapatkan lebih banyak. Namun pendekatan itu valid pada sistem di manaps
satu-satunya cara bagi pengguna biasa untuk mengambil informasi itu (seperti ketika API diistimewakan danps
ditetapkan atau digunakan untuk menggunakannya), tetapi masih berpotensi tidak menjadi bukti di masa depan di sana.Pendekatan lain adalah dengan tidak meneruskan rahasia
argv[]
tetapi menyuntikkan kode ke dalam program (menggunakangdb
atau$LD_PRELOAD
hack) sebelummain()
dimulai yang memasukkan rahasia ke dalam yangargv[]
diterima dariexecve()
.Dengan
LD_PRELOAD
, untuk executable yang non-setuid / setgid yang terhubung secara dinamis pada sistem GNU:Kemudian:
Pada titik tidak akan
ps
menunjukkan dips -opid,args
sana (-opid,args
menjadi rahasia dalam contoh ini). Perhatikan bahwa kami mengganti elemenargv[]
array pointer , bukan mengesampingkan string yang ditunjukkan oleh pointer tersebut, itulah sebabnya modifikasi kami tidak ditampilkan dalam outputps
.Dengan
gdb
, masih untuk executable yang non-setuid / setgid yang terhubung secara dinamis dan pada sistem GNU:Masih dengan
gdb
, pendekatan spesifik non-GNU yang tidak bergantung pada executable yang dihubungkan secara dinamis atau memiliki simbol debug dan harus bekerja untuk ELF yang dapat dieksekusi di Linux setidaknya bisa menjadi:Pengujian dengan executable yang terhubung secara statis:
Ketika executable mungkin statis, kami tidak memiliki cara yang dapat diandalkan untuk mengalokasikan memori untuk menyimpan rahasia, jadi kami harus mendapatkan rahasia dari tempat lain yang sudah ada dalam memori proses. Itu sebabnya lingkungan adalah pilihan yang jelas di sini. Kami juga menyembunyikan
SECRET
env var itu ke proses (dengan mengubahnya keSECRE=
) untuk menghindari kebocoran jika proses memutuskan untuk membuang lingkungannya untuk beberapa alasan atau menjalankan aplikasi yang tidak dipercaya.Itu juga berfungsi pada Solaris 11 (asalkan gdb dan GNU binutils diinstal (Anda mungkin harus mengganti nama
objdump
menjadigobjdump
).Pada FreeBSD (setidaknya x86_64, saya tidak yakin apa itu 24 byte pertama (yang menjadi 16 ketika gdb (8.0.1) interaktif menunjukkan ada bug di gdb di sana) pada stack), ganti
argc
danargv
definisi dengan:(Anda mungkin juga perlu menginstal
gdb
paket / port karena versi yang sebelumnya datang dengan sistem kuno).sumber
Yang mungkin Anda lakukan adalah
kemudian, dengan anggapan Anda sedang menulis
./program
di C (atau orang lain melakukannya, dan dapat mengubah atau memperbaikinya untuk Anda), gunakan getenv (3) dalam program itu, mungkin sebagaidan setelah itu
export
kamu jalankan saja./program
di shell yang sama. Atau nama variabel lingkungan dapat diteruskan ke sana (dengan menjalankan./program --secret-var=SECRET
dll ...)ps
tidak akan memberi tahu tentang rahasia Anda, tetapi proc (5) masih dapat memberikan banyak informasi (setidaknya untuk proses lain dari pengguna yang sama).Lihat juga ini untuk membantu merancang cara yang lebih baik dalam menyampaikan argumen program.
Lihat jawaban ini untuk penjelasan yang lebih baik tentang globbing dan peran shell.
Mungkin Anda
program
memiliki beberapa cara lain untuk mendapatkan data (atau menggunakan komunikasi antar-proses dengan lebih bijaksana) daripada argumen program biasa (tentu saja harus, jika itu dimaksudkan untuk memproses informasi sensitif). Baca dokumentasinya. Atau mungkin Anda menyalahgunakan program itu (yang tidak dimaksudkan untuk memproses data rahasia).Menyembunyikan data rahasia sangat sulit. Tidak melewatinya melalui argumen program tidak cukup.
sumber
./program
, sehingga paruh pertama jawaban ini tampaknya tidak relevan.