LFI, RFI, Path Traversal Zafiyetleri ve Farklı Yazılım Dillerindeki Durumları

Akıner Kısa
7 min readSep 19, 2024

--

Bu yazımda LFI, RFI(File Inclusion) ve Path Traversal zafiyetlerini, birbirleri arasındaki farkları ve güncel durumlarını açıklayacağım.

Not: Directory Traversal ve Path Traversal aynı zafiyetin farklı isimlendirilmiş halleridir. Bu yazıda bu zafiyetten Path Traversal olarak bahsedeceğim.

LFI, RFI ve Path Traversal Nedir?

Öncelikle bu zafiyetleri tek tek ele alarak ne olduklarını incelemeden önce birşeyi ayırt etmemiz gerekiyor. LFI ve RFI zafiyetleri File Inclusion başlığı altında incelenirken Path Traversal diğer ismiyle Directory Traversal farklı bir başlıkta incelenir. Bunları ayırt etmek için şu şekilde bu zafiyetleri açıklayabiliriz:

RFI(Remote File Inclusion): Türkçesi uzaktan dosya dahil etme olan bu zafiyet hedef sunucu içerisine dışarıdan bir dosya çağırılmasını sağlayan bir zafiyettir. Ancak RFI zafiyetine sebep olan fonksiyonlar güncel yazılım dillerinde varsayılan olarak devre dışı bırakıldığı için bu zafiyet artık fazla gözükmemektedir.

LFI(Local File Inclusion): Türkçesi yerel dosya dahil etme olan bu zafiyet sunucu içerisindeki yerel dosyaların okunabilmesini sağlayan bir zafiyettir. RFI artık nadiren görülen bir zafiyet olduğu için LFI genelde File Inclusion olarak geçmektedir.

Path Traversal: Türkçesi dizin geçişi/dizin gezimi olan bu zafiyet LFI’a benzer şekilde yerel dosyaların okunmasını sağlayan bir zafiyettir.

RFI ve LFI yani File Inclusion başlığı altındaki zafiyetler hem birbirine hemde Path Traversal’a benziyor gördüğümüz gibi. Hatta açıklamaları neredeyse aynı iken bu zafiyetler arasındaki farklar nelerdir birde bunlara değinelim

LFI ve RFI:

  • LFI, sunucu üzerindeki dosyalara erişim sağlarken, RFI uzak sunuculardan dosya çalıştırmaya olanak tanır.
  • LFI genellikle daha sınırlı bir etki alanına sahipken, RFI daha geniş bir saldırı yüzeyi oluşturabilir.

File Inclusion (LFI/RFI) ve Path Traversal:

  • File Inclusion, bir dosyanın uygulamaya dahil edilmesini ve çalıştırılmasını içerir. Bu, genellikle PHP, JSP gibi dillerde “include” veya “require” fonksiyonlarıyla gerçekleştirilir.
  • Path Traversal ise dosyalara erişimi hedefler, ancak bu dosyaları çalıştırmaz. Sadece okuma işlemi gerçekleştirilir.
  • File Inclusion saldırıları genellikle daha tehlikelidir, çünkü kodu çalıştırma yeteneği vardır. Path Traversal ise genellikle hassas bilgilerin ifşa edilmesiyle sınırlıdır.
  • File Inclusion, zaman zaman belirli dosya türlerini hedef alırken Path Traversal herhangi bir dosya türüne erişim sağlayabilir.

Buradan aslında bu zafiyetlerin hem benzer olduğu senaryolar hem farklı olabileceği senaryolar olduğunu görüyoruz.

Şimdi ise bu zafiyetlerin yazılım dillerinde nasıl ortaya çıktığı ve nasıl önlemler alınabileceği konusuna farklı yazılım dilleriyle değinelim.

Local File Inclusion (LFI) PHP Örneği

Zafiyetli Örnek:

<?php
// Kullanıcıdan dosya adı alınıyor
$file = $_GET['page'];
// Dosya dahil ediliyor
include($file . '.php');
?>

Bu örnekte kullanıcının page parametresiyle belirttiği herhangi bir dosya sunucuya dahil edilir. Bu, saldırganın yerel dosyaları okumasına veya zararlı kod çalıştırmasına olanak tanır.

Güvenli Örnek:

<?php
// Dahil edilebilecek dosyaların beyaz listesi
$allowed_pages = ['home', 'about', 'contact'];
$page = $_GET['page'];

// Kullanıcının girdiği sayfa beyaz listede mi kontrol ediliyor
if (in_array($page, $allowed_pages)) {
include($page . '.php');
} else {
// Hata sayfasına yönlendirme
include('404.php');
}
?>

Kullanıcının girdiği parametre, önceden tanımlanmış izin verilen dosyalar listesiyle karşılaştırılır. Bu sayede istenmeyen dosyaların dahil edilmesi engellenir.

Remote File Inclusion (RFI) PHP Örneği

Zafiyetli Örnek:

<?php
// Kullanıcıdan URL alınıyor
$url = $_GET['url'];
// Dışarıdan dosya dahil ediliyor
include($url);
?>

Kullanıcı, herhangi bir uzak URL’yi url parametresiyle belirterek sunucuya dosya dahil edebilir. Bu, saldırganın zararlı kodları çalıştırmasına olanak tanır.

<?php
// Dışardan dosya dahil etmeyi tamamen yasaklamak
// Veya sadece güvenilir kaynaklardan veri almayı sağlamak
$allowed_domains = ['https://trusted.com', 'https://another-trusted.com'];
$url = $_GET['url'];

// URL'nin izin verilen domainlerden biri olup olmadığını kontrol et
$parsed_url = parse_url($url);
if (in_array($parsed_url['scheme'] . '://' . $parsed_url['host'], $allowed_domains)) {
include($url);
} else {
// Hata sayfasına yönlendirme
include('404.php');
}
?>

Burada normalde önceden bahsettiğimiz gibi PHP'de bu zafiyete sebep veren fonksiyon olan allow_url_include = Off şeklinde kapalı durumda bırakılmıştır. Ancak yinede kullanılacaksa bir beyaz liste oluşturulmalı ve bu domainler dışında dışarıdan dosya dahil edilmesi engellenmelidir.

Path Traversal PHP Örneği

Zafiyetli Örnek:

<?php
// Kullanıcıdan dosya yolu alınıyor
$file = $_GET['file'];
// Dosya okunuyor
$content = file_get_contents('/var/www/html/uploads/' . $file);
echo $content;
?>

Kullanıcı, file parametresiyle ../ gibi dizin geçiş karakterlerini kullanarak sunucudaki diğer dosyalara erişebilir. Gördüğümüz gibi Path Traversal zafiyeti File Inclusion’dan farklı olarak dosya dahil edilmez dosyaların okunmasına sebep olur.

Güvenli Örnek:

<?php
// Kullanıcıdan dosya adı alınıyor
$file = basename($_GET['file']); // basename kullanarak yolu temizleme
$filepath = '/var/www/html/uploads/' . $file;

// Sadece belirli dizin altında olup olmadığını kontrol et
if (file_exists($filepath) && strpos(realpath($filepath), '/var/www/html/uploads/') === 0) {
$content = file_get_contents($filepath);
echo $content;
} else {
// Hata sayfasına yönlendirme
echo "Dosya bulunamadı.";
}
?>

basename fonksiyonu ile dizin geçiş karakterleri temizlenir ve realpath kullanılarak dosyanın belirtilen dizin altında olup olmadığı doğrulanır. Bu sayede farklı dizinden bir dosya çağırılması engellenir.

Diğer Yazılım Dillerinin PHP’den Ayrılan Tarafı

Buraya kadar verdiğimiz örneklerde PHP’nin farklı yaklaşımlarından dolayı zafiyetlerin farklılaşmasını gördük. PHP, dosya dahil etme işlemlerini dinamik ve esnek bir şekilde sunan bir dildir. Özellikle include, require, include_once, require_once gibi fonksiyonlar aracılığıyla, harici dosyaları uygulamaya dahil etmek ve bu dosyaların içeriğini çalıştırmak oldukça yaygındır. Ancak diğer yazılım dillerinde bu durumlar benzer olsada tam olarak PHP’de olduğu gibi değildir. Bazı dillerde File Inclusion ve Path Traversal aynı başlıkta incelenirken bazılarında PHP’de olduğu gibi ayrılabilir.

Python, Java(JSP), Node.js, ASP.NET gibi diğer popüler programlama dillerinde bu durumu PHP ile karşılaştıracak olursak:

Dosya Dahil Etme ve Kod Çalıştırma:

  • Bu dillerde, uygulamaya harici kod dahil etme işlemleri PHP’deki kadar dinamik ve yaygın değildir.
  • Kod dahil etme ve çalıştırma genellikle derleme zamanı veya uygulamanın başlangıç aşamasında statik olarak belirlenir.
  • Kullanıcı girdisine dayalı dinamik kod dahil etme alışılmış bir yöntem değildir ve ciddi güvenlik riskleri nedeniyle tavsiye edilmez.

Dosya Okuma ve Erişim:

  • Uygulamalar, dosya okuma işlemleri için kullanıcı girdilerini kullanabilirler (örneğin, yüklenen görüntüleri görüntüleme veya kullanıcılara özel dosyaları sunma).
  • Bu durumda, kontrolsüz kullanıcı girdileri Path Traversal zafiyetlerine yol açabilir. Ancak PHP’de olduğu gibi ayrı ayrı farklı zafiyetler görülmesi pek rastlanan bir durum değildir.

Şimdi bu bahsettiğimiz dillerden örnekler vererek durumu daha detaylı ele alalım.

File Inclusion Java(JSP) Örneği

Zafiyetli Örnek:

<%
String url = request.getParameter("url");
java.net.URLConnection conn = new java.net.URL(url).openConnection();
java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println(inputLine);
}
in.close();
%>

Kullanıcı, herhangi bir uzak URL’yi url parametresiyle belirterek sunucuya dosya dahil edebilir veya içerik çekebilir.

Güvenli Örnek:

<%
String page = request.getParameter("page");
List<String> allowedPages = Arrays.asList("home", "about", "contact");

if (allowedPages.contains(page)) {
RequestDispatcher rd = request.getRequestDispatcher("/pages/" + page + ".jsp");
rd.forward(request, response);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
%>

Kullanıcının belirttiği sayfanın önceden tanımlanmış izin verilen sayfalar listesindeki olup olmadığı kontrol edilir. Bu sayede sadece belirli sayfalar sunucudan dahil edilir.

Path Traversal Java(JSP) Örneği

Zafiyetli Örnek:

<%
String filePath = request.getParameter("file");
java.io.File file = new java.io.File("/var/www/uploads/" + filePath);
java.io.FileInputStream fis = new java.io.FileInputStream(file);
// Dosya oku ve çıktı ver
%>

Kullanıcı, file parametresiyle ../ gibi dizin geçiş karakterlerini kullanarak sunucudaki diğer dizinlere erişim sağlayabilir.

<%
String file = request.getParameter("file");
String allowedDir = "/var/www/uploads/";
java.io.File fileObj = new java.io.File(allowedDir, file).getCanonicalFile();

if (fileObj.getPath().startsWith(allowedDir)) {
java.io.FileInputStream fis = new java.io.FileInputStream(fileObj);
// Dosya oku ve çıktı ver
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Erişim engellendi.");
}
%>

Dosya yolu getCanonicalFile ile temizlenir ve dosyanın izin verilen dizin altında olup olmadığı kontrol edilir. Böylece dizin geçişi engellenir.

File Inclusion Node.JS(Express.JS) Örneği

Zafiyetli Örnek:

const express = require('express');
const fs = require('fs');
const app = express();

app.get('/page', (req, res) => {
const page = req.query.page || 'home';
fs.readFile(`./pages/${page}.html`, 'utf8', (err, data) => {
if (err) {
res.status(404).send('Sayfa bulunamadı.');
} else {
res.send(data);
}
});
});

app.listen(3000, () => console.log('Sunucu çalışıyor.'));

Kullanıcı, page parametresiyle herhangi bir dosya yolu belirterek sunucudaki dosyalara erişebilir.

Güvenli Örnek:

const express = require('express');
const path = require('path');
const app = express();

const allowedPages = ['home', 'about', 'contact'];

app.get('/page', (req, res) => {
const page = req.query.page || 'home';
if (allowedPages.includes(page)) {
res.sendFile(path.join(__dirname, 'pages', `${page}.html`));
} else {
res.status(404).send('Sayfa bulunamadı.');
}
});

app.listen(3000, () => console.log('Sunucu çalışıyor.'));

Kullanıcının belirttiği sayfanın izin verilen sayfalar listesinde olup olmadığı kontrol edilir. Yalnızca bu sayfalar sunucudan dahil edilir.

Path Traversal Node.JS(Express.JS) Örneği

Zafiyetli Örnek:

const express = require('express');
const fs = require('fs');
const app = express();

app.get('/read-file', (req, res) => {
const file = req.query.file;
fs.readFile(`/var/www/uploads/${file}`, 'utf8', (err, data) => {
if (err) {
res.status(404).send('Dosya bulunamadı.');
} else {
res.send(data);
}
});
});

app.listen(3000, () => console.log('Sunucu çalışıyor.'));

Kullanıcı, file parametresiyle ../ gibi dizin geçiş karakterlerini kullanarak sunucudaki diğer dizinlere erişim sağlayabilir.

Güvenli Örnek:

const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();

app.get('/read-file', (req, res) => {
const file = path.basename(req.query.file); // Yalnızca dosya adını al
const filePath = path.join(__dirname, 'uploads', file);

// Dosyanın uploads dizini altında olup olmadığını kontrol et
if (filePath.startsWith(path.join(__dirname, 'uploads'))) {
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
res.status(404).send('Dosya bulunamadı.');
} else {
res.send(data);
}
});
} else {
res.status(403).send('Erişim engellendi.');
}
});

app.listen(3000, () => console.log('Sunucu çalışıyor.'));

path.basename ile dosya adı temizlenir ve dosyanın izin verilen dizin altında olup olmadığı kontrol edilir. Bu sayede dizin geçişi engellenir.

File Inclusion / Path Traversal ASP.net Örneği

Zafiyetli Örnek

using System;
using System.IO;
using System.Web.UI;

public partial class PageLoader : Page
{
protected void Page_Load(object sender, EventArgs e)
{
string page = Request.QueryString["page"] ?? "home";
string path = Server.MapPath("~/Pages/" + page + ".aspx");
if (File.Exists(path))
{
Server.Execute(path);
}
else
{
Response.StatusCode = 404;
Response.End();
}
}
}

Kullanıcı, page parametresiyle herhangi bir dosya yolu belirterek sunucudaki dosyalara erişebilir.

Güvenli Örnek:

using System;
using System.Web.UI;

public partial class PageLoader : Page
{
protected void Page_Load(object sender, EventArgs e)
{
string page = Request.QueryString["page"] ?? "home";
string[] allowedPages = { "home", "about", "contact" };

if (Array.Exists(allowedPages, p => p.Equals(page, StringComparison.OrdinalIgnoreCase)))
{
Server.Execute($"~/Pages/{page}.aspx");
}
else
{
Response.StatusCode = 404;
Response.End();
}
}
}

Kullanıcının belirttiği sayfanın izin verilen sayfalar listesinde olup olmadığı kontrol edilir. Bu sayede istenmeyen dosyaların dahil edilmesi engellenir.

File Inclusion / Path Traversal Python(Flask) Örneği:

Zafiyetli Örnek:

from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/page')
def page():
page = request.args.get('page', 'home')
with open(f'pages/{page}.html') as f:
content = f.read()
return render_template_string(content)

if __name__ == '__main__':
app.run()

Kullanıcı, page parametresiyle herhangi bir dosya yolu belirterek sunucudaki dosyalara erişebilir.

Güvenli Örnek:

from flask import Flask, request, abort, render_template

app = Flask(__name__)

@app.route('/page')
def page():
page = request.args.get('page', 'home')
allowed_pages = ['home', 'about', 'contact']
if page in allowed_pages:
return render_template(f'{page}.html')
else:
abort(404)

if __name__ == '__main__':
app.run()

Kullanıcının belirttiği sayfanın önceden tanımlanmış izin verilen sayfalar listesinde olup olmadığı kontrol edilir. Bu sayede istenmeyen dosyalara erişim engellenir.

Özet ve Sonuç:

İncelediğimiz durumları ele alarak bu zafiyetlerin tamamen yazılım dillerinin yaklaşımlarına göre değiştiğini görebiliriz. RFI artık modern web uygulamalarına ve yaklaşımlarına yenilmiş bir zafiyet olup File Inclusion(LFI) ve Path Traversal hala bazı durumlarda görülebilecek zafiyetler olarak devam etmektedirler. Bu zafiyetlerde bazı yazılım dillerinde aynı ele alınırken bazılarında farklı ele alınabilmektedirler.

İleri Okuma ve Farklı Kaynaklar:

--

--

Akıner Kısa
Akıner Kısa

No responses yet