Asosiy kontentga o‘tish

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.

security backend linux

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:

Python
# 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:

Fayl tuzilishi
/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:

Python
# 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:

Python
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:

Python
# 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#

  1. Path traversal nega ishlaydi? ../ nima qiladi?
  2. /etc/passwd nima uchun traversal'ning "isboti"?
  3. 2-labda ../ kerak bo'lmadi. Nega? Absolute path nima?
  4. 3-labda ....// nega ishlaydi? Filtrning qaysi xatosidan foydalanadi?
  5. Yo'l boshini tekshirish nega yetarli emas (4-lab)?
  6. Null byte (%00) 5-labda nima qiladi? Qaysi ikki qatlam yo'lni turlicha o'qiydi?
  7. Nega "../ ni tozalash" path traversal'ni yopmaydi?
  8. os.path.realpath nima qiladi va u nega tozalashdan afzal?
  9. Eng ishonchli yechim nima — nega fayl nomi emas, ID?
  10. "Yo'lni tekshirma, yech" — tekshirish va yechish farqini ayting.

Report uchun talablar#

  1. Skrinshot: kamida bitta labda /etc/passwd mazmuni ko'ringan holat.
  2. Filtr sindi: 2, 3, 4 yoki 5-labda filtrni qanday chetlab o'tdingiz? Kamida ikkitasini o'z so'zingiz bilan yozing.
  3. Bir naqsh: path traversal SSRF va IDOR bilan qanday o'xshaydi? Uch darsda takrorlangan naqshni ayting.
  4. Tuzatuvchi kod: o'z loyihangizdan (yoki tasavvuriy) fayl nomini qabul qiladigan view oling. Uni realpath tekshiruvi 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.

10 daqiqa 34 marta o‘qildi