นี่คือคำสั่งที่ฉันใช้ตรวจสอบ bash shell เพื่อหาข้อผิดพลาดของ Shellshock:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
ใครช่วยอธิบายคำสั่งโดยละเอียดได้ไหม?
นี่คือคำสั่งที่ฉันใช้ตรวจสอบ bash shell เพื่อหาข้อผิดพลาดของ Shellshock:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
ใครช่วยอธิบายคำสั่งโดยละเอียดได้ไหม?
คำตอบ:
คำตอบนี้เป็นที่มาของบทความเดิมในนิตยสาร 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”
พิมพ์กลับมาที่คุณ หรือผู้โจมตีอาจทำสิ่งที่เลวร้ายยิ่งกว่าการพิมพ์สิ่งต่างๆ
env
ไม่จำเป็น คุณจะได้รับผลเดียวกัน (ผ่าน / ไม่ผ่านขึ้นอยู่กับว่าทุบตีได้รับการปรับปรุง) x='() { :;}; echo OOPS' bash -c "echo this is a test"
โดยใช้คำสั่งโดยไม่ได้: นี่เป็นเพราะก่อนหน้าคำสั่งที่มีการกำหนดตัวแปรส่งผ่านตัวแปรนั้นและค่าของมันลงbash -c "..."
ในสภาพแวดล้อมของคำสั่ง ( ในกรณีนี้)
env
มีความจำเป็นหรือไม่ถูกกำหนดโดยเชลล์ที่จะรันการทดสอบไม่ใช่เชลล์ที่กำลังทดสอบ (สิ่งเหล่านี้อาจเหมือนกันแม้กระทั่งตอนนี้เรากำลังทดสอบว่า bash ประมวลผลสภาพแวดล้อมของตัวเองอย่างไร) เชลล์สไตล์ Bourne ยอมรับNAME=value command
ไวยากรณ์ หอยแบบ C (เช่นcsh
, tcsh
) ไม่ทำ ดังนั้นการทดสอบจึงพกพาได้มากกว่านี้ด้วยenv
(บางครั้งก็สร้างความสับสนเกี่ยวกับการทำงาน)
ในเวอร์ชันที่ไม่ตรงกันbash
จะเก็บนิยามฟังก์ชันที่เอ็กซ์พอร์ตเป็นตัวแปรสภาวะแวดล้อม
จัดเก็บฟังก์ชั่นx
เป็น
$ x() { bar; }
$ export -f x
และตรวจสอบคำจำกัดความของมันว่า
$ env | grep -A1 x
x=() { bar
}
ดังนั้นหนึ่งสามารถใช้ประโยชน์จากสิ่งนี้โดยการกำหนดตัวแปรสภาพแวดล้อมของเขาเองและตีความพวกเขาเป็นคำจำกัดความของฟังก์ชั่น ตัวอย่างเช่นenv x='() { :;}'
จะถือว่าเป็น
x() { :;
}
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
จากman env
,
env
- เรียกใช้โปรแกรมในสภาพแวดล้อมที่มีการปรับเปลี่ยน
:
ทำอะไร 0
แต่ทางออกที่มีสถานะออก ดูเพิ่มเติม
เมื่ออินสแตนซ์ใหม่ของ bash ที่ไม่ตรงกันที่เปิดตัวเป็นbash -c "echo this is a test"
ตัวแปรสภาพแวดล้อมที่สร้างขึ้นจะถือว่าเป็นฟังก์ชันและโหลด ดังนั้นหนึ่งได้รับการส่งออก
อ่อนแอ นี่คือการทดสอบ
หมายเหตุ:เสียงสะท้อนภายนอกคำจำกัดความของฟังก์ชันได้รับการดำเนินการโดยไม่คาดคิดในระหว่างการเริ่มต้นระบบ bash คำจำกัดความของฟังก์ชั่นเป็นเพียงขั้นตอนหนึ่งในการรับการประเมินผลและหาประโยชน์ที่จะเกิดขึ้นการกำหนดฟังก์ชันเองและตัวแปรสภาพแวดล้อมที่ใช้นั้นเป็นเรื่องที่ต้องการ เชลล์มองไปที่ตัวแปรสภาพแวดล้อมเห็น x ซึ่งดูเหมือนว่าเป็นไปตามข้อ จำกัด ที่รู้เกี่ยวกับนิยามของฟังก์ชั่นที่มีลักษณะอย่างไรและทำการประเมินบรรทัดโดยไม่ได้ตั้งใจดำเนินการ echo (ซึ่งอาจเป็นคำสั่งใด ๆ เป็นอันตรายหรือไม่) . ดูสิ่งนี้ด้วย
env test='() { echo "anything"; }' bash -c "echo otherthing"
otherthing
นั่นคือการแก้ไขในแพทช์ รู้สึกฟรีถ้าฉันยังไม่ชัดเจน
unpatched bash
คุณสามารถเรียกใช้ฟังก์ชั่นได้ตามที่นิยามไว้ แต่ในตัวปะbash
แก้คำนิยามนั้นไม่ได้อยู่ที่นั่น
echo vulnerable
) จะไม่ถูกประมวลผล โปรดทราบว่าในแพ็ตช์ล่าสุดฟังก์ชั่นที่ส่งผ่านจะต้องมีคำนำหน้าเฉพาะ ( env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test"
) บางคนแพทช์เมื่อเร็ว ๆ นี้อาจจะใช้แทนการใช้ครั้งแรก%%
()