8 วิธีแฮก Bypass และความปลอดภัยของระบบ FileUpload บนเว็บไซต์

How to Bypass & Secure in FileUpload #1


การทำงานของฟังชั่น move_uploaded_file()

เริ่มต้นเมื่อ php ได้รับ Post Request ที่เข้ารหัสที่เป็นชนิด multipart/form-data มันจะสร้างไฟล์ชั่วคราว และสุ่มชื่อใน temp directory (เช่น. /var/tmp/php6yXOVs) และ php ยังจะเติม global array $_FILES กับข้อมูลเกี่ยวกับไฟล์ที่อัพโหลดแล้ว $_FILES[‘uploadedfile’][‘name’]: ชื่อเดิมของไฟล์บนเครื่องไคลเอ็นต์ $_FILES[‘uploadedfile’][‘type’]: รูปแบบของไฟล์ (MIME type.) $_FILES[‘uploadedfile’][‘size’]: ขนาดของไฟล์ในรูปแบบ bytes $_FILES[‘uploadedfile’][‘tmp_name’]: ชื่อไฟล์ชั่คราวที่ถูกอัพโหลด ที่ถูกเก็บไว้ในเซิฟเวอร์ โดยฟังชั่น move_upload_file จะทำหน้าที่ย้ายไฟล์ชั่วคราว
ไปยังที่อยู่ที่กำหนดโดยนักพัฒนา....

เพื่อสร้างความคุ้นเคยกับคนที่ยังไม่เคยเขียน PHP หรือกำลังเริ่มศึกษา 
(ที่ยังไม่ได้ใช้ Framework)

ด้านล่างนี้อาจเป็นฟอร์มที่ใช้ Upload file 
ที่ยังไม่ได้ที่การตรวจสอบอะไรเลยใน php code


Case 1:File Upload Form ที่ไม่มีการตรวจสอบ 


HTML Form: <form enctype="multipart/form-data" action="uploader.php" method="POST"> 
<input type="hidden" name="MAX_FILE_SIZE" value="100000" /> 
Choose a file to upload: <input name="uploadedfile" type="file" /><br>
<input type="submit" value="Upload File" />
</form> PHP Code: <?php $target_path = "uploads/"; $target_path = $target_path . basename($_FILES['uploadedfile']['name']);

if (move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file " . basename($_FILES['uploadedfile']['name']) . "มีการอัพโหลดแล้ว"; } else { echo "มีข้อผิดพลาดในการอัพโหลดไฟล์, please try again!"; } ?>
ในกรณีอย่างด้านบนนี้ ไฟล์สามารถเข้าถึงใช้ url
ตัวอย่างเช่น : w w w . domain.com/uploads/uploadedfile.jpg




เอาละ พอเข้าใจการทำงานของระบบอัพโหลดไฟล์โดยคร่าว
ด้วยฟังชั่น move_uploaded_file กันไปแล้ว เราไปดู เคสต่อๆไปกันครับ....



Case 2:Mime Type Validation ความผิดพลาดอื่นๆที่พบบ่อยของนักพัฒนาเว็บในการรักษาความปลอดภัยของ upload forms


คือการเช็คแค่ mime type
เมื่อไฟล์อัพโหลดถึง server แล้ว
PHP จะตั้งค่าตัวแปร $_FILES[‘uploadedfile’][‘type’]
ให้เป็น mime-type ที่ Webbrowser ฝั่ง Client ใช้ แต่อย่างไรก็ตามการตรวจสอบ File upload ไม่ได้ขึ้นอยู่กับค่านี้เท่านั้น Attacker สามารถ upload ไฟล์โดยใช้ script ส่งค่าผ่าน HTTP POST request จะสามารถ fake mime-type ได้สำเร็จ




Case 3:Block Dangerous Extensions
การสร้างระบบอัพโหลดไฟล์ด้วยวิธี "blacklist" ข้อเสียอย่างหนึ่งของการใช้วิธีนี้คือ

"นักพัฒนาไม่สามารถรวบรวมนามสกุลทั้งหมดที่ Attacker ใช้ เพื่อนำมาป้องกันได้...."

หากโค้ดรันในโฮสที่ปกติจะยอมรับหลายๆภาษา เช่น Perl , Python , Ruby และอื่นๆ จะทำให้ list ไม่มีที่สิ้นสุด Attacker สามารถ bypass การตรวจสอบดังกล่าวได้โดยการอัพโหลดไฟล์ .htaccess ที่มีเนื้อหาด้านในคล้ายๆกับด้านล่างนี้
AddType application/x-httpd-php .jpg โค้ดด้านบนนี้จะสั่ง Apache web server สามารถรันไฟล์ jpg เหมือนกับเป็นไฟล์ php Attacker สามารถอัพโหลดไฟล์ประเภท jpg ที่มีโค้ดภายในเป็น PHP




Case 4: Double extensions (part 1)

ในเคสนี้จะใช้เทคนิคการตรวจสอบคล้ายๆกันกับในเคสที่ 3
ซึ่งแม้ว่านักพัฒนาจะตรวจสอบนามสกุลที่อยู่บนชื่อไฟล์โดยการแยกประเภทไฟล์ที่ใช้วิธีมองหาจุด "." (dot character) ในชื่อไฟล์ และทำการแยกสติงหลังจากพบอักขระจุด "." (dot character)

ช่องทางที่ใช้ Bypass อาจจะซับซ้อนขึ้นมาบ้างแต่ก็ยังพอมีหนทาง
ขั้นแรกให้ลองดู Apache handles files with multiple extensions.

อ้างอิงจาก Apache manual :
“Files can have more than one extension, and the order of the extensions is normally irrelevant. For example, if the file welcome.html.fr maps onto content type text/html and language French then the file welcome.fr.html will map onto exactly the same information. If more than one extension is given which maps onto the same type of meta-information, then the one to the right will be used, except for languages and content encodings. For example, if .gif maps to the MIME-type image/gif and .html maps to the MIME-type text/html, then the file welcome.gif.html will be associated with the MIME-type text/html.”

ดังนั้นไฟล์ filename.php.123 จะถูกตีความว่าเป็น PHP FILE และสามารถรันไฟล์ได้
การทำงานนี้คือถ้า last extension (ในที่นี้คือ .123) ไม่ได้ระบุในรายการของ mime-types ที่รู้จักไปยัง webserver , นักพัฒนาไม่รู้จักนามสกุลดังกล่าวใน apache ซึ่งอาจเป็นอันตรายมากด้วยเหตุผลหลายประการ

ที่ชัดเจนเลยก็คือ Attacker สามารถ Upload shell.php.123
เหตุผลเพราะ ,สคิปจะคำนวณผลและดูที่ last extension (.123) และสรุปว่านามสกุลนี้ไม่อยู่ในลิสของนามสกุลที่เป็นอันตราย

ในเคสนี้จึงต้องสรุปไว้ว่า "เป็นไปไม่ได้ที่คุณจะคาดการนามสกุลทั้งหมดที่อันตราย"





Case 5: Double extensions (part 2)

วิธีการที่ดีขึ้นในการป้องกันระบบ Upload forms คือการสร้าง White List  ,ในเคสนี้นักพัฒนาระบุ White list เป็นนามสกุลที่ยอมรับ / และไม่ยอมรับนามสกุลที่ไม่ระบุไว้ในรายการ
อย่างไรก็ตาม ในบางกรณี ,

วิธีการนี​​้จะไม่ทำงานตามที่คาดไว้.....
เมื่อ Apache มีการกำหนดค่าในการดำเนินการของ Code php, มี 2 วิธีคือ

  1. คำสั่ง Addhandler
  2. คำสั่ง AddType

ถ้ามีการใช้คำสั่ง Addhandler  ชื่อไฟล์ทั้งหมดที่มีนามสกุล '.php' (รวมถึง .php.jpg)
จะดำเนินการเหมือนเป็น php script. ดังนั้น

ถ้าคุณตั้งค่าไฟล์ที่ประกอบด้วยคำสั่งตามด้านล่างนี้ ทำให้มีความเสี่ยงได้เช่นกัน

AddHandler php5-script .php

Attacker สามารถ bypass upload file 
ด้วยการอัพโหลด ‘filename.php.jpg’ และสามารถรันโค้ด php ได้สำเร็จ




Case 6: Checking the image header

นักพัฒนามักจะตรวจสอบส่วนหัวของภาพโดยใช้ฟังชั่น getimagesize
....ซึ่งถ้าการตรวจสอบ Header ไม่ถูกต้องฟังชั่นจะคืนค่าเป็น "เท็จ" ดังนั้นนักพัฒนามักจะตรวจสอบว่าฟังชั่นนี้จะ Return เป็นจริงหรือเท็จ ทำให้ Attacker ไม่สามารถ upload php shell ที่ฝังอยู่ใน jpg ไฟล์ได้

!แต่วิธีนี้ยังสามารถ Bypass ได้อยู่
นั่นคือถ้าภาพถูกเปิดในโปรแกรม image editor เช่น Gimp อันดับแรกคือจะสามารถแก้ไข image comment เพื่อแทรก php code ดังภาพด้านล่าง

                         สรุปก็คือ Valid header และสามารถ bypass getimagesize



Case 7: Protecting the upload folder with .htaccess

อีกวิธีที่นักพัฒนาก็นิยมทำกัน คือ
การป้องกันโฟลเดอร์ที่ไฟล์จะถูกอัพโหลดขึ้นไปโดยใช้ .htaccess  มักจะมีโค้ดดังต่อไปนี้

AddHandler cgi-script .php .php3 .php4 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi
Options –ExecCGI

และวิธีนี้ก็เป็นอีกวิธีเข้าข่ายการทำ Blacklist ที่ไม่มีความปลอดภัยหากยังวางอยู่ในที่อยู่เดียวกับไฟล์ภาพที่ถูกอัพโหลด...ซึ่งในคู่มือ PHP, ในส่วน move_uploaded_file มีคำเตือนที่ระบุไว้ว่า


"If the destination file already exists , it will be overwritten."


นั่นหมายถึง "ถ้าแฟ้มปลายทางมีอยู่แล้วมันจะถูกเขียนทับ"
ทำให้ไฟล์  .htaccess ที่อยู่ในโฟลเดอร์เดียวกับไฟล์ของคุณจะถูกเขียนทับชัวร์ป่าบ !



Case 8: Client-side validation

อีกชนิดที่พบมากของ Security ที่ใช้ใน fileupload forms
คือการทำ Client-side validation ของไฟล์ที่จะอัพโหลด ,โดยปกติวิธีดังกล่าวเป็นเรื่องธรรมดามากขึ้นใน ASP.NET ,ตั้งแต่ ASP.NET มีการใช้งาน Validation controls ที่ง่าย

ในการ Validation controls ประเภทเหล่านี้
ช่วยให้นักพัฒนาตรวจสอบว่านามสกุลไฟล์ที่ถูกอัพโหลดนั้นคือไฟล์ที่อยู่ในลิสที่อนุญาติให้อัพโหลดได้

  1. <asp:FileUpload ID="FileUpload1" runat="server" /><br /><br />

  2. <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="UploadFile" />
  3. <asp:Label ID="Label1" runat="server"></asp:Label>
  4. <asp:RegularExpressionValidator id="RegularExpressionValidator1" runat="server"
  5. ErrorMessage="Only mp3, m3u or mpeg files are allowed!"
  6. ValidationExpression="^(([a-zA-Z]:)|(\{2}w+)$?)(\(w[w].*))
  7. +(.mp3|.MP3|.mpeg|.MPEG|.m3u|.M3U)$" ControlToValidate="FileUpload1">
  8. </asp:RegularExpressionValidator>
  9. <asp:RequiredFieldValidator 
  10. id="RequiredFieldValidator1" runat="server" ErrorMessage="This is a required 
  11. field!" ControlToValidate="FileUpload1"></asp:RequiredFieldValidator>

จากโค้ดใช้ตรวจสอบให้ผู้ใช้สามารถ Upload .mp3 / .mpeg / .m3u ไปยังเว็บเซอร์เวอร์
ถ้าไม่ตรงกับ 3 ประเภทนี้จะไม่สามารถอัพโหลดได้

แต่ ! เนื่องจากการตรวจสอบนี้ดำเนินการในฝั่ง Client side แน่นอน Attacker จะสามารถหลีกเลี่ยงประเภทของการตรวจสอบนี้ได้  ,เป็นไปได้ที่จะเขียน Script สั้นๆ เพื่อมาทำการตรวจสอบแทนที่สคิปป้องกันโดยเว็บแอพพลิเคชั่น โดยไม่ต้องใช้เว็บเบราเซอร์

สรุปคือ Attacker สามารถใช้ application ส่ง HTTP POST แทนได้นั่นคือไม่ต้องเจอกับการตรวจสอบของ Web Application นั่นเอง








สรุป วิธีการ BYPASS - ข้อเสีย

1.เช็คแค่ mime type

  • สามารถ upload ไฟล์โดยใช้ script ส่งค่าผ่าน HTTP POST request


2.ใช้วิธี "blacklist"

  • นักพัฒนาไม่สามารถรวบรวมนามสกุลทั้งหมดที่ Attacker ใช้
  • หากโค้ดรันในโฮสที่ปกติจะยอมรับหลายๆภาษา เช่น Perl , Python , Ruby และอื่นๆ จะทำให้ list ไม่มีที่สิ้นสุด
  • upload htaccess : code (AddType application/x-httpd-php .jpg ) จะสามารถรันไฟล์ jpg เหมือนกับเป็นไฟล์ php

3.เช็คโดยมองหาจุด "." (dot character) ในชื่อไฟล์

  • filename.php.123 จะถูกตีความว่าเป็นไฟล์ชนิด PHP
  • เป็นไปไม่ได้ที่คุณจะคาดการนามสกุลทั้งหมดที่อันตราย


4.ใช้ getimagesize หวังว่าจะได้ไฟล์ชนิด Image ที่แท้จริง

  • สามารถใช้ Gimp ใส่ Comment ที่มีโค้ด php ลงบนไฟล์ภาพจริง ,และรันโค้ด PHP ได้


5.ใช้ .htaccess ทำ Blacklist และวางไว้ที่โฟลเดอร์เดียวกันกับที่อยู่ของภาพ

  • อาจถูกเขียน .htaccess ทับ !







การป้องกันที่ดีที่สุดที่ควรทำ

สร้าง Whitelist สำหรับ upload forms 
โดยการเขียนเนื้อหาไฟล์ .htaccess ดังตัวอย่างต่อไปนี้

deny from all
<Files ~ “^w+.(gif|jpe?g|png)$”>
  order deny,allow
  allow from all
</Files>

และข้อแนะนำเพิ่มเติม
  1. ห้ามเก็บ .htaccess ไฟล์ในไดเรกทอรีเดียวกันที่อัปโหลดไฟล์ที่เก็บไฟล์ไว้ ควรจะวางไว้ในไดเรกทอรีแม่
  2. ป้องกันการเขียนทับไฟล์ที่มีอยู่
  3. สร้างชื่อไฟล์แบบสุ่ม
  4. ห้ามใช้การตรวจสอบในแค่เพียงฝั่ง Client-side เพราะการตรวจสอบที่ดีควรทำทั้ง  Server-side และ Client-side




แนะนำบทความต่อไป
(นักพัฒนายุคเก่าๆเขาใช้ฟังชั่นอะไรกันถึงได้ถูกแฮกเว็บอัพโหลด Shell ?)
http://iak1.blogspot.com/2015/07/hackweb-upload-shell.html






Source : http://www.acunetix.com/websitesecurity/upload-forms-threat