Bagaimana curl melindungi kata sandi agar tidak muncul di output ps?

68

Saya perhatikan beberapa waktu lalu bahwa nama pengguna dan kata sandi yang diberikan curlsebagai argumen baris perintah tidak muncul dalam psoutput (meskipun tentu saja mereka mungkin muncul dalam riwayat bash Anda).

Mereka juga tidak muncul di /proc/PID/cmdline.

(Namun, panjang argumen gabungan nama pengguna / kata sandi dapat diturunkan.)

Demonstrasi di bawah ini:

[root@localhost ~]# nc -l 80 &
[1] 3342
[root@localhost ~]# curl -u iamsam:samiam localhost &
[2] 3343
[root@localhost ~]# GET / HTTP/1.1
Authorization: Basic aWFtc2FtOnNhbWlhbQ==
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: */*



[1]+  Stopped                 nc -l 80
[root@localhost ~]# jobs
[1]+  Stopped                 nc -l 80
[2]-  Running                 curl -u iamsam:samiam localhost &
[root@localhost ~]# ps -ef | grep curl
root      3343  3258  0 22:37 pts/1    00:00:00 curl -u               localhost
root      3347  3258  0 22:38 pts/1    00:00:00 grep curl
[root@localhost ~]# od -xa /proc/3343/cmdline 
0000000    7563    6c72    2d00    0075    2020    2020    2020    2020
          c   u   r   l nul   -   u nul  sp  sp  sp  sp  sp  sp  sp  sp
0000020    2020    2020    0020    6f6c    6163    686c    736f    0074
         sp  sp  sp  sp  sp nul   l   o   c   a   l   h   o   s   t nul
0000040
[root@localhost ~]# 

Bagaimana efek ini dicapai? Apakah ada di suatu tempat dalam kode sumber curl? (Saya menganggap itu adalah curlfitur, bukan psfitur? Atau apakah ini semacam fitur kernel?)


Juga: dapatkah ini dicapai dari luar kode sumber biner yang dapat dieksekusi? Misalnya dengan menggunakan perintah shell, mungkin dikombinasikan dengan izin root?

Dengan kata lain, bisakah saya menutupi argumen agar tidak muncul di /procatau di psoutput (hal yang sama, saya pikir) yang saya sampaikan ke beberapa perintah shell sewenang-wenang ? (Saya kira jawaban untuk ini adalah "tidak" tapi sepertinya layak untuk memasukkan setengah pertanyaan tambahan ini.)

Wildcard
sumber
16
Bukan jawaban, tetapi perhatikan bahwa pendekatan ini tidak aman . Ada jendela perlombaan antara awal program dan membersihkan string argumen di mana setiap pengguna dapat membaca kata sandi. Jangan terima kata sandi sensitif pada baris perintah.
R ..
1
Terkait longgar: Kepada siapa variabel lingkungan termasuk? dan Apakah ada orang dalam praktek yang menggunakan environlangsung untuk mengakses variabel lingkungan? - intinya: daftar argumen, seperti daftar variabel lingkungan, ada dalam memori proses baca / tulis pengguna, dan dapat dimodifikasi oleh proses pengguna.
Scott
1
@ JPhi1618, buat saja karakter pertama dari greppola Anda menjadi kelas karakter. Misalnyaps -ef | grep '[c]url'
Wildcard
1
@ mpy, ini tidak terlalu rumit. Beberapa regex cocok dengan diri mereka sendiri dan beberapa tidak. curlcocok curltetapi [c]urltidak cocok [c]url. Jika Anda perlu lebih detail, ajukan pertanyaan baru dan saya akan dengan senang hati menjawab.
Wildcard

Jawaban:

78

Ketika kernel mengeksekusi suatu proses, itu menyalin argumen baris perintah untuk membaca-tulis memori milik proses (pada stack, setidaknya di Linux). Proses dapat menulis ke memori itu seperti memori lainnya. Saat psmenampilkan argumen, itu membaca kembali apa pun yang disimpan di alamat tertentu dalam memori proses. Sebagian besar program menyimpan argumen asli, tetapi dimungkinkan untuk mengubahnya. The POSIX deskripsips menyatakan bahwa

Tidak ditentukan apakah string yang diwakili adalah versi dari daftar argumen karena diteruskan ke perintah ketika dimulai, atau versi argumen karena mereka mungkin telah dimodifikasi oleh aplikasi. Aplikasi tidak dapat bergantung pada kemampuan untuk memodifikasi daftar argumen mereka dan memiliki modifikasi yang tercermin dalam output ps.

Alasan mengapa hal ini disebutkan adalah bahwa sebagian besar varian unix mencerminkan perubahan, tetapi implementasi POSIX pada jenis sistem operasi lain mungkin tidak.

Fitur ini terbatas penggunaannya karena proses tidak dapat membuat perubahan sewenang-wenang. Paling tidak, panjang total argumen tidak dapat ditingkatkan, karena program tidak dapat mengubah lokasi di mana psakan mengambil argumen dan tidak dapat memperluas area di luar ukuran aslinya. Panjangnya dapat dikurangi secara efektif dengan meletakkan byte nol di akhir, karena argumen adalah string C-style null-terminated (ini tidak bisa dibedakan dari memiliki banyak argumen kosong di akhir).

Jika Anda benar-benar ingin menggali, Anda dapat melihat sumber dari implementasi open-source. Di Linux, sumbernya pstidak menarik, yang Anda akan lihat hanyalah bahwa ia membaca argumen baris perintah dari sistem file proc , di . Kode yang menghasilkan konten file ini ada di dalam kernel, di dalam . Bagian dari memori proses (diakses dengan ) pergi dari alamat ke ; alamat-alamat ini dicatat dalam kernel ketika proses dimulai dan tidak dapat diubah setelahnya./proc/PID/cmdlineproc_pid_cmdline_readfs/proc/base.caccess_remote_vmmm->arg_startmm->arg_end

Beberapa daemon menggunakan kemampuan ini untuk mencerminkan status mereka, misalnya mereka mengubahnya argv[1]menjadi string seperti startingatau availableatau exiting. Banyak varian unix memiliki setproctitlefungsi untuk melakukan ini. Beberapa program menggunakan kemampuan ini untuk menyembunyikan data rahasia. Perhatikan bahwa ini penggunaan terbatas karena argumen baris perintah terlihat saat proses dimulai.

Sebagian besar bahasa tingkat tinggi menyalin argumen ke objek string dan tidak memberikan cara untuk memodifikasi penyimpanan asli. Berikut adalah program C yang menunjukkan kemampuan ini dengan mengubah argvelemen secara langsung.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int i;
    system("ps -p $PPID -o args=");
    for (i = 0; i < argc; i++)
    {
        memset(argv[i], '0' + (i % 10), strlen(argv[i]));
    }
    system("ps -p $PPID -o args=");
    return 0;
}

Output sampel:

./a.out hello world
0000000 11111 22222

Anda dapat melihat argvmodifikasi dalam kode sumber ikal. Curl mendefinisikan fungsi cleanargdalamsrc/tool_paramhlp.c yang digunakan untuk mengubah argumen untuk semua ruang menggunakan memset. Dalam src/tool_getparam.cfungsi ini digunakan beberapa kali, misalnya dengan mereduksi kata sandi pengguna . Karena fungsi dipanggil dari parameter parsing, itu terjadi di awal doa curl, tetapi membuang baris perintah sebelum ini terjadi masih akan menampilkan kata sandi.

Karena argumen disimpan dalam memori proses sendiri, mereka tidak dapat diubah dari luar kecuali dengan menggunakan debugger.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Bagus! Jadi, sehubungan dengan potongan spesifikasi tersebut, saya memahaminya dengan maksud bahwa POSIX-compliant membuat kernel Anda menyimpan argumen baris perintah asli proses di luar memori baca-tulis proses ( selain salinan dalam memori baca-tulis) ? Dan kemudian memiliki psargumen laporan dari sepotong memori kernel, mengabaikan perubahan yang dibuat dalam memori baca-tulis proses? Tetapi (jika saya benar?) Sebagian besar variasi UNIX bahkan tidak melakukan yang pertama, jadi Anda tidak dapat membuat psimplementasi melakukan yang terakhir tanpa modifikasi kernel, karena data asli tidak disimpan di mana pun?
Wildcard
1
@ Kartu Memori Benar. Mungkin ada implementasi Unix yang menjaga yang asli tetapi saya tidak berpikir salah satu yang umum melakukannya. Bahasa C memungkinkan isi argventri diubah (Anda tidak dapat mengatur argv[i], tetapi Anda dapat menulis argv[i][0]sampai argv[i][strlen(argv[i])]), sehingga harus ada salinan dalam memori proses.
Gilles 'SO- stop being evil'
2
Fungsi yang relevan dalam kode sumber curl: github.com/curl/curl/blob/master/src/tool_paramhlp.c#L139
sebasth
4
@ Kartu Memori, Solaris melakukan ini. Baris perintah yang dilihat oleh / usr / ucb / ps adalah proses yang dimiliki (bisa diubah) salinan. Baris perintah yang dilihat oleh / usr / bin / ps adalah salinan yang dimiliki kernel (tidak dapat diubah). Kernel hanya menyimpan 80 karakter pertama. Ada lagi yang terpotong.
BowlOfRed
1
@ Kartu Memori Memang nol tertinggal adalah argumen kosong. Dalam psoutput, banyak argumen kosong sepertinya tidak ada di sana, tapi ya, itu membuat perbedaan jika Anda memeriksa berapa banyak ruang yang ada, dan Anda dapat mengamati lebih langsung dari /proc/PID/cmdline.
Gilles 'SO- stop being evil'
14

Jawaban yang lain menjawab pertanyaan dengan baik secara umum. Untuk secara spesifik menjawab " Bagaimana efek ini dicapai? Apakah ada di suatu tempat dalam kode sumber curl? ":

Di bagian parsing argumen dari kode sumber ikal , -uopsi ditangani sebagai berikut:

    case 'u':
      /* user:password  */
      GetStr(&config->userpwd, nextarg);
      cleanarg(nextarg);
      break;

Dan cleanarg()fungsinya didefinisikan sebagai berikut:

void cleanarg(char *str)
{
#ifdef HAVE_WRITABLE_ARGV
  /* now that GetStr has copied the contents of nextarg, wipe the next
   * argument out so that the username:password isn't displayed in the
   * system process list */
  if(str) {
    size_t len = strlen(str);
    memset(str, ' ', len);
  }
#else
  (void)str;
#endif
}

Jadi kita dapat secara eksplisit melihat bahwa argumen username: password di argvditimpa dengan spasi, seperti yang dijelaskan oleh jawaban lain.

Trauma Digital
sumber
Saya suka bahwa komentar di cleanargnegara secara eksplisit bahwa ia melakukan apa yang ditanyakan pertanyaan!
Floris
3

Suatu proses tidak hanya dapat membaca parameternya tetapi juga menuliskannya.

Saya bukan pengembang jadi saya tidak terbiasa dengan hal ini tetapi mungkin dari luar dengan pendekatan yang mirip dengan perubahan parameter lingkungan:

https://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables

Hauke ​​Laging
sumber
Oke, tetapi menjalankan mis. bash -c 'awk 1 /proc/$$/cmdline; set -- something; awk 1 /proc/$$/cmdline'Menunjukkan bahwa setidaknya dalam shell, pengaturan parameter berbeda dari memodifikasi apa yang dilihat kernel sebagai parameter proses.
Wildcard
4
@Wildcard Argumen posisi dalam skrip shell pada awalnya merupakan salinan dari beberapa argumen baris perintah proses shell. Kebanyakan shell tidak membiarkan skrip mengubah argumen aslinya.
Gilles 'SANGAT berhenti menjadi jahat'
@Gilles, ya, itulah inti komentar saya. :) Bahwa pernyataan umum bahwa suatu proses dapat melakukan itu (kalimat pertama dari jawaban ini) tidak menjawab apakah ini dapat dicapai oleh fitur shell yang ada. Jawaban untuk ini tampaknya "tidak," yang merupakan dugaan saya di bagian paling bawah dari pertanyaan saya.
Wildcard