คำอธิบายของคำสั่งเพื่อตรวจสอบ shellshock


32

นี่คือคำสั่งที่ฉันใช้ตรวจสอบ bash shell เพื่อหาข้อผิดพลาดของ Shellshock:

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

ใครช่วยอธิบายคำสั่งโดยละเอียดได้ไหม?


4
โปรดดูเพิ่มเติมที่: unix.stackexchange.com/q/157329/70524 - คำตอบของ Fixee อาจช่วยได้
muru

คำตอบ:


45

คำตอบนี้เป็นที่มาของบทความเดิมในนิตยสาร Fedoraโดยแมทธิวมิลเลอร์ได้รับใบอนุญาตภายใต้Creative Commons Attribution-Share Alike 4.0ใบอนุญาต

ให้ฉันอธิบาย:

env x='() { :;}; echo OOPS' bash -c :

สิ่งนี้จะพิมพ์“ OOPS” บนระบบที่มีช่องโหว่ แต่จะออกจากโหมดเงียบหากมีการติดตั้ง bash

env x='() { :;}; echo OOPS' bash -c "echo this is a test"

สิ่งนี้จะพิมพ์“ OOPS” บนระบบที่มีช่องโหว่ แต่พิมพ์“this is a test”ถ้า bash ได้รับการติดตั้งแล้ว

และคุณอาจเคยได้ยินว่ามีบางอย่างเกี่ยวกับตัวแปรสภาพแวดล้อม แต่ทำไมโค้ดในตัวแปรสภาพแวดล้อมจึงถูกเรียกใช้งาน? ก็ไม่ควรที่จะเป็น - แต่เนื่องจากคุณสมบัติที่ฉันอยากจะเรียกว่าฉลาดเกินไปสำหรับความดีของตัวเองมีบางห้องสำหรับข้อบกพร่อง Bash คือสิ่งที่คุณเห็นว่าเป็นพรอมต์เทอร์มินัล แต่ก็เป็นภาษาสคริปต์และมีความสามารถในการกำหนดฟังก์ชั่น คุณทำสิ่งนี้:

$ Ubuntu()  { echo "Ubuntu is awesome."; }

แล้วคุณมีคำสั่งใหม่ โปรดทราบว่าที่echoนี่ยังไม่ได้เปิดใช้งานจริง มันเพิ่งถูกบันทึกเป็นสิ่งที่จะเกิดขึ้นเมื่อเราเรียกใช้คำสั่งใหม่ของเรา สิ่งนี้จะมีความสำคัญในไม่กี่นาที!

$ Ubuntu
 Ubuntu is awesome.

ที่เป็นประโยชน์! แต่สมมุติว่าด้วยเหตุผลบางอย่างเราจำเป็นต้องเรียกใช้อินสแตนซ์ใหม่ของ bash เป็น subprocess และต้องการรันคำสั่งใหม่ที่ยอดเยี่ยมของฉันภายใต้นั้น คำสั่งbash -c somecommandทำสิ่งนี้อย่างแน่นอน: รันคำสั่งที่กำหนดในเชลล์ใหม่:

$ bash -c Ubuntu
  bash: Ubuntu: command not found

โอ เสียใจ เด็กไม่ได้สืบทอดนิยามของฟังก์ชัน แต่มันทำหน้าที่เป็นสภาพแวดล้อม - ชุดของคู่ของคีย์ - ค่าที่ถูกเอ็กซ์พอร์ตจากเชลล์ (นี่เป็นแนวคิดที่เข้าใจง่ายทั้งหมดหากคุณไม่คุ้นเคยกับสิ่งนี้ให้เชื่อใจฉันตอนนี้) และมันกลับกลายเป็นว่า bash สามารถส่งออกฟังก์ชั่นได้เช่นกัน ดังนั้น:

$ export -f Ubuntu
$ bash -c Ubuntu
  Ubuntu is awesome.

ซึ่งเป็นสิ่งที่ดีและดี - ยกเว้นว่ากลไกที่นี้จะสำเร็จเป็นหลบ sorta โดยพื้นฐานแล้วเนื่องจากไม่มีเวทมนตร์ Linux / Unix สำหรับการทำหน้าที่ในตัวแปรสภาพแวดล้อม, ฟังก์ชั่นการส่งออกจริงเพียงแค่สร้างตัวแปรสภาพแวดล้อมปกติที่มีคำนิยามฟังก์ชั่น จากนั้นเมื่อเชลล์ตัวที่สองอ่านสภาพแวดล้อม“ ขาเข้า” และพบตัวแปรที่มีเนื้อหาที่ดูเหมือนฟังก์ชั่นมันจะประเมินค่า

ในทฤษฎีนี้เป็นความปลอดภัยอย่างสมบูรณ์เพราะจำได้กำหนดฟังก์ชั่นไม่จริงรันมัน ยกเว้น - และนี่คือสาเหตุที่เรามาที่นี่ - มีข้อผิดพลาดในโค้ดที่การประเมินไม่หยุดเมื่อถึงจุดสิ้นสุดของนิยามฟังก์ชัน มันแค่ทำไปเรื่อย ๆ

export -fที่ไม่เคยจะเกิดขึ้นเมื่อฟังก์ชั่นที่เก็บไว้ในตัวแปรสภาพแวดล้อมที่ทำถูกต้องตามกฎหมายด้วย แต่ทำไมต้องเป็น legit? ผู้โจมตีสามารถสร้างตัวแปรสภาพแวดล้อมเก่า ๆ ขึ้นมาได้และถ้ามันดูเหมือนฟังก์ชั่นเชลล์ bash ใหม่จะคิดว่ามันเป็น!

ดังนั้นในตัวอย่างแรกของเรา:

env x='() { :;}; echo OOPS' bash -c "echo this is a test"

envคำสั่งคำสั่งทำงานกับชุดตัวแปรที่กำหนด ในกรณีนี้เรากำลังตั้งค่าxบางอย่างที่ดูเหมือนฟังก์ชั่น ฟังก์ชั่นเป็นเพียง:คำสั่งเดียวซึ่งจริงๆแล้วเป็นคำสั่งง่ายๆที่ถูกนิยามว่าไม่ทำอะไรเลย แต่หลังจากsemi-colonที่สัญญาณสิ้นสุดของคำนิยามฟังก์ชั่นมีechoคำสั่ง ไม่ควรอยู่ที่นั่น แต่ไม่มีอะไรหยุดเราจากการทำ

จากนั้นคำสั่งที่กำหนดให้ทำงานกับสภาพแวดล้อมใหม่นี้คือเชลล์ทุบตีใหม่อีกครั้งด้วยคำสั่ง“ echo this is a test” หรือ“ ไม่ทำอะไรเลย:” หลังจากนั้นคำสั่งจะจบการทำงานโดยไม่เป็นอันตรายอย่างสมบูรณ์

แต่ - โอ๊ะโอ! เมื่อเชลล์ใหม่นั้นเริ่มต้นขึ้นและอ่านสภาพแวดล้อมมันจะเข้าสู่xตัวแปรและเนื่องจากดูเหมือนว่าเป็นฟังก์ชันจึงประเมินค่า คำจำกัดความของฟังก์ชั่นถูกโหลดอย่างไม่เป็นอันตราย - จากนั้นโหลดที่เป็นอันตรายของเราจะถูกเรียกใช้เช่นกัน ดังนั้นหากคุณเรียกใช้ข้างต้นในระบบที่มีช่องโหว่คุณจะได้รับการ“OOPS”พิมพ์กลับมาที่คุณ หรือผู้โจมตีอาจทำสิ่งที่เลวร้ายยิ่งกว่าการพิมพ์สิ่งต่างๆ


1
Muchas gracias สำหรับคำอธิบายที่ยอดเยี่ยมว่าทำไมงานนี้
Doug R.

2
โปรดทราบว่าenvไม่จำเป็น คุณจะได้รับผลเดียวกัน (ผ่าน / ไม่ผ่านขึ้นอยู่กับว่าทุบตีได้รับการปรับปรุง) x='() { :;}; echo OOPS' bash -c "echo this is a test"โดยใช้คำสั่งโดยไม่ได้: นี่เป็นเพราะก่อนหน้าคำสั่งที่มีการกำหนดตัวแปรส่งผ่านตัวแปรนั้นและค่าของมันลงbash -c "..."ในสภาพแวดล้อมของคำสั่ง ( ในกรณีนี้)
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

1
... แต่อาจมีความจำเป็นในบางส่วนของแพทช์ล่าสุด สิ่งที่อยู่ในฟลักซ์
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

4
@DennisWilliamson ไม่ว่าจะenvมีความจำเป็นหรือไม่ถูกกำหนดโดยเชลล์ที่จะรันการทดสอบไม่ใช่เชลล์ที่กำลังทดสอบ (สิ่งเหล่านี้อาจเหมือนกันแม้กระทั่งตอนนี้เรากำลังทดสอบว่า bash ประมวลผลสภาพแวดล้อมของตัวเองอย่างไร) เชลล์สไตล์ Bourne ยอมรับNAME=value commandไวยากรณ์ หอยแบบ C (เช่นcsh, tcsh) ไม่ทำ ดังนั้นการทดสอบจึงพกพาได้มากกว่านี้ด้วยenv(บางครั้งก็สร้างความสับสนเกี่ยวกับการทำงาน)
Eliah Kagan

2

ในเวอร์ชันที่ไม่ตรงกันbashจะเก็บนิยามฟังก์ชันที่เอ็กซ์พอร์ตเป็นตัวแปรสภาวะแวดล้อม

จัดเก็บฟังก์ชั่นxเป็น

$ x() { bar; }
$ export -f x

และตรวจสอบคำจำกัดความของมันว่า

$ env | grep -A1 x
x=() {  bar
}

ดังนั้นหนึ่งสามารถใช้ประโยชน์จากสิ่งนี้โดยการกำหนดตัวแปรสภาพแวดล้อมของเขาเองและตีความพวกเขาเป็นคำจำกัดความของฟังก์ชั่น ตัวอย่างเช่นenv x='() { :;}'จะถือว่าเป็น

x() { :;
}

คำสั่งตรวจสอบ shellshock ทำอะไรได้บ้าง

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

จากman env,

  1. env - เรียกใช้โปรแกรมในสภาพแวดล้อมที่มีการปรับเปลี่ยน

  2. :ทำอะไร 0แต่ทางออกที่มีสถานะออก ดูเพิ่มเติม

  3. เมื่ออินสแตนซ์ใหม่ของ bash ที่ไม่ตรงกันที่เปิดตัวเป็นbash -c "echo this is a test"ตัวแปรสภาพแวดล้อมที่สร้างขึ้นจะถือว่าเป็นฟังก์ชันและโหลด ดังนั้นหนึ่งได้รับการส่งออก

    อ่อนแอ
    นี่คือการทดสอบ

หมายเหตุ:เสียงสะท้อนภายนอกคำจำกัดความของฟังก์ชันได้รับการดำเนินการโดยไม่คาดคิดในระหว่างการเริ่มต้นระบบ bash คำจำกัดความของฟังก์ชั่นเป็นเพียงขั้นตอนหนึ่งในการรับการประเมินผลและหาประโยชน์ที่จะเกิดขึ้นการกำหนดฟังก์ชันเองและตัวแปรสภาพแวดล้อมที่ใช้นั้นเป็นเรื่องที่ต้องการ เชลล์มองไปที่ตัวแปรสภาพแวดล้อมเห็น x ซึ่งดูเหมือนว่าเป็นไปตามข้อ จำกัด ที่รู้เกี่ยวกับนิยามของฟังก์ชั่นที่มีลักษณะอย่างไรและทำการประเมินบรรทัดโดยไม่ได้ตั้งใจดำเนินการ echo (ซึ่งอาจเป็นคำสั่งใด ๆ เป็นอันตรายหรือไม่) . ดูสิ่งนี้ด้วย


ฉันยังพบว่าฟังก์ชัน bash ที่กำหนดไว้หากส่งออกถูกประเมินในเชลล์ลูกในเวอร์ชันทุบตีของ patch ดูสิ่งนี้: chayan @ chayan: ~ / testr $ test () {echo "any"; }; การส่งออกทดสอบ f; bash -c test Ouput: อะไรดังนั้นคำตอบของคุณค่อนข้างไม่ถูกต้อง คำอธิบายของ kasiyA เกี่ยวกับข้อผิดพลาดขณะที่การขยายตัวแปรเกินคำจำกัดความนั้นถูกต้องฉันคิดว่า
heemayl

@ heemayl พฤติกรรมนี้เป็นธรรมชาติ แต่ถ้าคุณพยายามที่คุณจะเห็นที่การส่งออกenv test='() { echo "anything"; }' bash -c "echo otherthing" otherthingนั่นคือการแก้ไขในแพทช์ รู้สึกฟรีถ้าฉันยังไม่ชัดเจน
souravc

โปรดทำให้ฉันชัดเจนอีกครั้ง ในความคิดเห็นสุดท้ายของคุณเราได้กำหนดฟังก์ชั่นพื้นฐานแล้วบอกให้ทุบตีเพื่อรันเสียงสะท้อน ในตัวอย่างนี้เราไม่ได้เรียกใช้ฟังก์ชันใน bash สิ่งนี้จะไม่ได้ผลลัพธ์เดียวกันในทั้งทุบตีปะและไม่ปะ? ฉันมีความเห็นว่าข้อผิดพลาดโดยทั่วไปเป็นทุบตีกำลังดำเนินการคำสั่งที่วางไว้หลังจากนิยามฟังก์ชั่นในขณะที่ฟังก์ชั่นไม่เคยเรียกที่ใดก็ได้ในภายหลังเช่นถ้าเราทำเช่นนี้ env test = '() {echo "อะไร"; }; echo "foo" 'bash -c "echo otherthing" โปรดอธิบายฉันในบริบทนี้
heemayl

@ heemayl ฉันได้แก้ไขคำตอบของฉันหวังว่าตอนนี้มันชัดเจน คุณถูกต้องในตัวอย่างในความคิดเห็นล่าสุดของเราเราไม่ได้เรียกว่าฟังก์ชั่น แต่ความแตกต่างก็คือในตัวunpatched bashคุณสามารถเรียกใช้ฟังก์ชั่นได้ตามที่นิยามไว้ แต่ในตัวปะbashแก้คำนิยามนั้นไม่ได้อยู่ที่นั่น
souravc

@heemayl: ไม่ถูกต้อง Bash ที่ได้รับการแก้ไขจะยังคงผ่านการกำหนดฟังก์ชันลงในสภาพแวดล้อมของเด็ก ความแตกต่างที่แพตช์ทำคือรหัสที่ตามหลังฟังก์ชั่นการกำหนด ( echo vulnerable) จะไม่ถูกประมวลผล โปรดทราบว่าในแพ็ตช์ล่าสุดฟังก์ชั่นที่ส่งผ่านจะต้องมีคำนำหน้าเฉพาะ ( env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test") บางคนแพทช์เมื่อเร็ว ๆ นี้อาจจะใช้แทนการใช้ครั้งแรก%% ()
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.