Maqolalar 10 daqiqa o‘qish 2 soat amaliyot 34 ko‘rish
Path traversal: fayl nomi shunchaki fayl nomi emas
Server rasm nomini foydalanuvchidan olib, uni papka yo'liga qo'shsa — foydalanuvchi o'sha yo'ldan chiqib, serverning istalgan faylini o'qib olishi mumkin: parollar, sozlamalar, kalitlar. Beshta labda buni ishga tushiramiz, keyin Django'da qanday yopishni ko'ramiz.
Mundarija
Ko'p sayt fayllarni nomi bo'yicha beradi: /image?filename=cat.png.
Server bu nomni papka yo'liga qo'shadi — /var/www/images/cat.png — va
faylni o'qib qaytaradi. Oddiy va foydali. Lekin agar foydalanuvchi
cat.png o'rniga ../../../etc/passwd yozsa, server o'sha yo'ldan
chiqib, butunlay boshqa faylni o'qiydi.
Bu path traversal — kursning IDOR darsiga o'xshaydi, lekin nishon ma'lumotlar bazasidagi obyekt emas, serverning fayl tizimi: sozlama fayllari, parollar, SSH kalitlar, ilovaning o'z manba kodi.
Bu darsdan keyin siz path traversal'ni topa olasiz, to'rt xil filtr chetlashini tushunasiz va Django'da fayl berishni xavfsiz qila olasiz.
Bu dars kimga
1-dars (Burp) tugagan bo'lsin. Linux fayl yo'llari — /etc/passwd,
../ nima ekani — bilan tanish bo'lsangiz osonroq.
Buzilgan taxmin#
Path traversal bitta tabiiy taxmindan tug'iladi:
"Foydalanuvchi fayl nomini beradi. Men uni papkamdagi faylga qo'shaman."
Dasturchining tasavvurida filename — bitta fayl nomi, cat.png. Lekin
fayl yo'li tili ../ degan maxsus qadamni biladi — "bitta papka yuqoriga".
Yetarlicha ../ qo'yilsa, yo'l papkadan chiqib, ildizga yetadi va u
yerdan istalgan faylga boradi.
Fayl nomi — matn emas, fayl tizimiga beriladigan yo'l: papka ichida qoladimi yoki undan chiqib ketadimi, uni yozish usuli hal qiladi. Bu XSS va SQLi'dagi bir naqsh — ma'lumot buyruq maydoniga tozalanmasdan tushmoqda.
Atamalar#
| Atama | Ma'nosi |
|---|---|
path traversal / directory traversal |
papkadan chiqib, boshqa faylga yetish |
../ (dot-dot-slash) |
fayl yo'lida "bitta papka yuqoriga" |
absolute path |
ildizdan boshlanuvchi to'liq yo'l (/etc/passwd) |
relative path |
joriy papkaga nisbatan yo'l (images/cat.png) |
/etc/passwd |
Linux'da foydalanuvchilar ro'yxati — o'qilsa, traversal isboti |
null byte (%00) |
eski tizimlarda satrni "tugatuvchi" belgi |
canonicalization |
yo'lni haqiqiy, to'liq shakliga keltirish (../ larni yechish) |
URL encoding |
belgilarni %XX shaklida yozish (/ → %2f) |
Nazariya: yo'ldan chiqish#
Zaif qolip — foydalanuvchi nomini papka yo'liga qo'shish:
# Zaif: filename to'g'ridan-to'g'ri yo'lga qo'shiladi
import os
def image(request):
filename = request.GET["filename"]
path = os.path.join("/var/www/images", filename) # <-- xavf shu yerda
with open(path, "rb") as f:
return HttpResponse(f.read(), content_type="image/png")
filename ga ../../../etc/passwd berilsa, yo'l shunga aylanadi:
/var/www/images/../../../etc/passwd
↓ (../ har biri bitta papka yuqoriga)
/etc/passwd
Server rasm papkasidan chiqib, tizim faylini o'qiydi. os.path.join ham
yordam bermaydi — u ../ ni maxsus ko'rmaydi, shunchaki qo'shadi.
Kuzating
fayl, rasm, hujjat, shablon nomi qabul qiladigan har
qanday parametrni qidiring. Unga ../ qo'shib, javob o'zgarganini
kuzating — boshqa fayl ochilsa yoki xato o'zgarsa, traversal bor.
Amaliyot#
1-labOddiy holat#
Lab: File path traversal, simple case
· APPRENTICE
Vazifa: /etc/passwd faylini o'qish.
Nimani ko'rasiz: mahsulot rasmi ?filename=... orqali yuklanadi.
Savol: filename server tomonda papka yo'liga qo'shiladi. Unga ../
qo'shsangiz, yo'l qayerga boradi?
Eng oddiy tekshiruv: filename=../../../etc/passwd.
Bu eng toza holat: filtr yo'q. ../ har biri bitta papka yuqoriga
ko'taradi, uchtasi ildizga yetkazadi, keyin etc/passwd ga boradi. Server
rasm o'rniga tizim faylini qaytaradi. Bir necha belgi — butun fayl
tizimiga eshik.
2-labAbsolute path#
Lab: Traversal sequences blocked with absolute path bypass
· PRACTITIONER
Vazifa: yana /etc/passwd, lekin ../ bloklangan.
Nimani ko'rasiz: filtr ../ ketma-ketligini rad etadi.
Savol: ../ kerakmi? Agar to'g'ridan-to'g'ri ildizdan boshlanuvchi
yo'l bersangiz, papkadan "chiqish" umuman kerak emas.
Eng oddiy tekshiruv: filename=/etc/passwd (absolute path).
Filtr ../ ni bloklaydi, lekin absolute path'ni unutadi — /etc/passwd
o'zi ildizdan boshlanadi, ../ umuman kerak emas. Filtr bitta hujum
shaklini bloklab, boshqasini ochiq qoldirdi. Denylist'ning odatiy
kamchiligi: u nimani taqiqlashni biladi, nimani unutganini bilmaydi.
3-lab — ../ olib tashlanadi#
Lab: Traversal sequences stripped non-recursively
· PRACTITIONER
Vazifa: yana /etc/passwd, lekin server ../ ni olib tashlaydi.
Nimani ko'rasiz: filtr ../ ni yo'ldan o'chiradi — lekin faqat bir
marta, qayta emas.
Savol: filtr ../ ni bir marta olib tashlasa, olib tashlagandan
keyin yana ../ paydo bo'ladigan qilib yozsangiz-chi?
Eng oddiy tekshiruv: ....// — o'rtadagi ../ olinsa, chetlaridan
../ qoladi.
Filtr ../ ni o'chiradi, lekin bir marta va qaytmasdan. ....//
ichida ../ ni o'chirsangiz, qolgan ../ yana to'liq ../ bo'ladi.
Bu — filtr mantig'ining o'ziga qarshi hujum: uning tozalash harakati yangi
teshik ochadi. Tozalash rekursiv bo'lmasa, u faqat sodda hujumni to'xtatadi.
4-labYo'l boshi tekshiriladi#
Lab: Validation of start of path
· PRACTITIONER
Vazifa: yana /etc/passwd, lekin server yo'l kutilgan papkadan
boshlanishini talab qiladi.
Nimani ko'rasiz: filtr yo'l /var/www/images/ bilan boshlanishini
tekshiradi.
Savol: yo'l kutilgan papkadan boshlansa, undan keyin ../ bilan
chiqib ketsangiz-chi? Boshi to'g'ri, davomi boshqa.
Eng oddiy tekshiruv: filename=/var/www/images/../../../etc/passwd.
Filtr faqat yo'lning boshini tekshiradi. Siz kutilgan papkadan
boshlaysiz — tekshiruvdan o'tasiz — keyin ../ bilan undan chiqib
ketasiz. Yo'lning bir qismini tekshirish yetarli emas: hujumchi tekshirilgan
qismni to'g'ri qo'yib, tekshirilmagan qismda hujum qiladi.
5-labNull byte bilan#
Lab: Validation of file extension with null byte bypass
· PRACTITIONER
Vazifa: yana /etc/passwd, lekin server fayl .png bilan tugashini
talab qiladi.
Nimani ko'rasiz: filtr yo'l .png (yoki shunga o'xshash) bilan
tugashini talab qiladi.
Savol: yo'l .png bilan tugashi kerak. Lekin .png dan oldin
"satr shu yerda tugadi" degan belgi qo'ysangiz, tizim .png ni e'tiborsiz
qoldiradimi?
Eng oddiy tekshiruv: filename=../../../etc/passwd%00.png.
Null byte (%00) — eski tizimlarda "satr shu yerda tugadi" belgisi. Filtr
.png ni ko'radi va rozi bo'ladi, lekin fayl tizimi %00 da to'xtab,
/etc/passwd ni o'qiydi. Bir xil satrni ikki qatlam ikki xil o'qiydi —
xuddi SSRF'dagi URL parse farqi kabi. Ikki komponent bitta matnni turlicha
tushunsa, oradagi farq — teshik.
Nima ishlamaydi va nega#
"../ ni bloklasam yetadi." 2-lab: absolute path'ga ../ kerak emas.
3-lab: ....// filtrning o'zidan foydalanadi. Denylist traversal'ni
hech qachon to'liq yopmaydi.
"Yo'l boshini tekshiraman." 4-lab: boshi to'g'ri bo'lsa ham, davomi
../ bilan chiqib ketadi. Yo'lning bir qismini tekshirish — hujumga
tekshirilmagan qismni qoldiradi.
"Fayl .png bilan tugasin." 5-lab: null byte .png ni e'tiborsiz
qoldiradi. Kengaytmani tekshirish ham chetlab o'tiladi.
Endi yopamiz#
Path traversal'ni "../ ni tozalash" bilan yopib bo'lmaydi — hamma labllar
buni ko'rsatdi. To'g'ri yechim: foydalanuvchidan yo'l umuman olmang,
yoki yo'lni to'liq yechib (canonicalize qilib) ruxsat etilgan papka ichida
ekanini tasdiqlang.
1. Eng yaxshi: fayl nomi emas, ID. Foydalanuvchi faylni tanlaydi, nomini yozmaydi:
# Zaif: foydalanuvchi fayl nomini beradi
filename = request.GET["filename"]
open(os.path.join(BASE, filename))
# To'g'ri: foydalanuvchi ID beradi, yo'lni server biladi
doc = get_object_or_404(Document, pk=request.GET["id"], owner=request.user)
return FileResponse(doc.file.open())
2. Yo'l olish shart bo'lsa — yechib, ichida ekanini tekshiring:
import os
def safe_path(base, filename):
# Yo'lni to'liq yechamiz (../ lar hisoblanadi), keyin base ichidami tekshiramiz
full = os.path.realpath(os.path.join(base, filename))
if not full.startswith(os.path.realpath(base) + os.sep):
raise Http404 # base'dan chiqib ketgan — rad
return full
os.path.realpath ../ larni haqiqatan yechadi (tozalash emas,
hisoblash), keyin natija ruxsat etilgan papka ichida ekanini tekshiradi.
Bu barcha labllarni bir yo'la yopadi: absolute path, ....//, boshi to'g'ri
davomi noto'g'ri — hammasi realpath'dan keyin base'dan tashqarida chiqadi.
3. Django'ning o'zi bergan vositalar:
# Statik/media fayllar uchun Django/whitenoise xavfsiz beradi —
# fayllarni qo'lda open() qilmang, storage API'dan foydalaning
from django.core.files.storage import default_storage
Muhim
yo'lni tekshirmang (denylist), yeching (canonicalize). Farq shu: tekshirish "bu yomon shaklmi?" deb so'raydi va shakllar cheksiz; yechish "bu haqiqatda qayerga boradi?" deb so'raydi va javob bitta.
Aniq misol: bu sayt maqola rasmlarini content/img/ dan beradi, lekin
fayl nomini foydalanuvchi bermaydi — u markdown fayl ichida, git'dan
keladi va deploy'da statik fayl sifatida to'planadi. WhiteNoise ularni
xavfsiz beradi. Ya'ni path traversal uchun asosiy shart — foydalanuvchi
boshqaradigan fayl yo'li — bu yerda yo'q. Kontentni koddan (git'dan)
kelishga majburlash o'zi bitta himoya qatlami.
Nazorat savollari#
- Path traversal nega ishlaydi?
../nima qiladi? /etc/passwdnima uchun traversal'ning "isboti"?- 2-labda
../kerak bo'lmadi. Nega? Absolute path nima? - 3-labda
....//nega ishlaydi? Filtrning qaysi xatosidan foydalanadi? - Yo'l boshini tekshirish nega yetarli emas (4-lab)?
- Null byte (
%00) 5-labda nima qiladi? Qaysi ikki qatlam yo'lni turlicha o'qiydi? - Nega "
../ni tozalash" path traversal'ni yopmaydi? os.path.realpathnima qiladi va u nega tozalashdan afzal?- Eng ishonchli yechim nima — nega fayl nomi emas, ID?
- "Yo'lni tekshirma, yech" — tekshirish va yechish farqini ayting.
Report uchun talablar#
- Skrinshot: kamida bitta labda
/etc/passwdmazmuni ko'ringan holat. - Filtr sindi: 2, 3, 4 yoki 5-labda filtrni qanday chetlab o'tdingiz? Kamida ikkitasini o'z so'zingiz bilan yozing.
- Bir naqsh: path traversal SSRF va IDOR bilan qanday o'xshaydi? Uch darsda takrorlangan naqshni ayting.
- Tuzatuvchi kod: o'z loyihangizdan (yoki tasavvuriy) fayl nomini
qabul qiladigan view oling. Uni
realpathtekshiruvi yoki ID yondashuvi bilan yoping. Oldingi va keyingi holatni keltiring.
Faqat ruxsat berilgan joyda
Path traversal serverning parollari va kalitlarigacha yetishi mumkin. Uni faqat PortSwigger laboratoriyasida yoki o'zingizga tegishli tizimda sinang. Birovning serveridan fayl o'qish — jinoyat.
Keyingi dars: OS command injection — kiritilgan matn serverda buyruq bo'lib bajarilganda, va nega tashqi buyruq chaqirishning o'zi xavfli.