Selamlar, ben Suppressor. Bugün Flask uygulamalarında Host header injection zafiyetini ele alacağım.
Konu Başlıkları:
- HTTP Headers (Başlık)
- Zafiyetin Kaynaklanma Sebebi
- Zafiyetin Flask Kodu İle Gösterilmesi
- Zafiyetin Giderilmesi
- PoC
HTTP Headers (Başlık)
HTTP başlıkları, hem HTTP isteklerinde hem de yanıtlarında isteğin meta bilgilerini taşıyan bilgilerdir.
Bu meta bilgileri, isteğin gideceği adres, kabul edilen yanıt tipi ve tarayıcının bizi tanıması için çerez (cookie) bilgileri gibi örnekler içerir.
Örnek olarak, bazı HTTP başlıkları şunlardır:
- Host: Bulunduğumuz web adresinin domain ismini veya IP adresini belirtir.
- Accept: Tarayıcının kabul edeceği içerik türlerini belirtir.
- Location: Web uygulamasında yönlendirme durumlarında (status 301, 302) yeni adresin neresi olduğunu belirtir.
Zafiyet Neden Kaynaklanıyor
Host header injection zafiyeti, HTTP host başlığının manipüle edilmesiyle ortaya çıkar.
Eğer bir Flask uygulaması dinamik olarak Host başlığını site üzerinden çekiyorsa, her site farklı bir domain veya IP adresine sahip olduğu için bu başlık kullanıcının kontrolü dışında değiştirilebilir. Saldırganlar bu durumu kötüye kullanarak uygulamanın istemeden başka bir sunucuya veya hizmete yönlendirilmesine neden olabilirler.
Zafiyetli kaynak kodu
Python:
@app.route("/host")
def index():
global mainurl
host = request.host
mainurl = "http://" + host + "/response.html"
return redirect(mainurl)
@app.route('/response.html')
def responsehtml():
return render_template('response.html',reponse="yönlendirildi", urladersi="Yölendirme Adresi" + " ~ " + mainurl)
if __name__ == "__main__":
app.run(debug=True)
Gerekli kütüphanelerin programa import edilmesi.
Python:
from flask import Flask, redirect, render_template, request
app = Flask(__name__)
Kütüphanlerin kullanım alanları
redirect:
redirect, Flask uygulamalarında kullanıcıyı başka bir URL'ye yönlendirmek için kullanılan bir fonksiyondur. Örneğin, bir formun başarıyla gönderilmesi durumunda kullanıcıyı teşekkür sayfasına yönlendirmek için redirect kullanabiliriz.
render_template:
render_template, Flask'in temel özelliklerinden biridir ve HTML dosyalarını Flask uygulamasına entegre etmemizi sağlar. Bu yöntem sayesinde, dinamik içeriklerle dolu HTML dosyalarını oluşturabilir ve kullanıcılara sunabiliriz. Örneğin, bir kullanıcı giriş sayfası veya ürün listesi gibi yapılandırılmış bir HTML sayfası oluşturmak için render_template kullanılır.
request:
request, Flask uygulamalarında kullanıcıdan gelen verileri almak veya veri transferi yapmak için kullanılır. Örneğin, HTTP istek başlıklarını (headers) veya form verilerini almak için kullanılabilir.
redirect:
redirect, Flask uygulamalarında kullanıcıyı başka bir URL'ye yönlendirmek için kullanılan bir fonksiyondur. Örneğin, bir formun başarıyla gönderilmesi durumunda kullanıcıyı teşekkür sayfasına yönlendirmek için redirect kullanabiliriz.
render_template:
render_template, Flask'in temel özelliklerinden biridir ve HTML dosyalarını Flask uygulamasına entegre etmemizi sağlar. Bu yöntem sayesinde, dinamik içeriklerle dolu HTML dosyalarını oluşturabilir ve kullanıcılara sunabiliriz. Örneğin, bir kullanıcı giriş sayfası veya ürün listesi gibi yapılandırılmış bir HTML sayfası oluşturmak için render_template kullanılır.
request:
request, Flask uygulamalarında kullanıcıdan gelen verileri almak veya veri transferi yapmak için kullanılır. Örneğin, HTTP istek başlıklarını (headers) veya form verilerini almak için kullanılabilir.
Route dekoratörü ile /host dizinine bir yönlendirme yapılacağını belirtir.index adında bir fonksiyon oluşturulması.Her fonksiyonda kullanabilmek için mainurl adında global bir değişken tanımlanması.host adında bir değişkenin tanımlanması ve request kullanarak sunucudaki host başlığının çekilmesi.Yönlendirilecek URL adresinin oluşturulması.redirect fonksiyonu ile URL adresine yönlendirilmesi.
Python:
@app.route("/host")
def index():
host = request.host
global mainurl
mainurl = "http://" + host + "/response.html"
return redirect(mainurl)
Bu kod tam olarak ne iş yapıyor derseniz, localhost/host adresine gittiğinizde sizi localhost/response.html adında bir dizine yönlendiriyor. Peki, bu dizine gelince ne oluyor derseniz? Ekrana yönlendirilen adresi yazdırıyor.
Python:
@app.route('/response.html')
def responsehtml():
return render_template('response.html',reponse="yönlendirildi", urladersi="Yölendirme Adresi" + " ~ " + mainurl)
"EE, zafiyet nerede" gibi sorularınız varsa, tam olarak burada.
Python:
host = request.host
mainurl = "http://" + host + "/response.html"
Burada host adresi statik bir şekilde girilmediği için Flask uygulaması, host başlığını çalıştırıldığı sunucuya göre dinamik olarak çektiği için bu manipülasyona açık hale geliyor.
Zafiyeti Önleme Aşaması
Normal şartlar altında URL kısmı (host) dinamik bir şekilde çekildiği için programın elinde net bir kaynak yoktu ve manipüle edilebiliyordu. Ama biz bu sefer host kısmını statik bir şekilde verdik ve artık programın bir kaynağı olduğu için manipülasyona kapalı hale geldi.
Zafiyeti Önleme Aşaması
Normal şartlar altında URL kısmı (host) dinamik bir şekilde çekildiği için programın elinde net bir kaynak yoktu ve manipüle edilebiliyordu. Ama biz bu sefer host kısmını statik bir şekilde verdik ve artık programın bir kaynağı olduğu için manipülasyona kapalı hale geldi.
Python:
@app.route("/host")
def index():
global mainurl
host = "127.0.0.1:5000"
mainurl = "http://" + host + "/response.html"
return redirect(mainurl)
Zafiyetsiz Kod
Python:
from flask import Flask, redirect, render_template, request
app = Flask(__name__)
@app.route("/host")
def index():
global mainurl
host = "127.0.0.1:5000"
mainurl = "http://" + host + "/response.html"
return redirect(mainurl)
@app.route('/response.html')
def responsehtml():
return render_template('response.html',reponse="yönlendirildi", urladersi="Yölendirme Adresi" + " ~ " + mainurl)
if __name__ == "__main__":
app.run(debug=True)
PoC
Göründüğü üzere /host dizinine giderken Burp Suite ile attığım isteği yakaladım ve şu anlık bir sorun gözükmüyor, istediğim adrese beni yönlendiriyor.
~
- "Ama burada host başlığını değiştirirsem, ne gibi bir değişiklik olacak? Tekrar bakalım."
- "Göründüğü üzere host adresi kendi localhost'um değil, attacker.com oldu."
Saldırı vektörü kısmında, eskiden okuduğum bazı makaleleri örnek vereceğim.
Host Header İnjection - Geleceği Yazanlar
~
portswigger
# Arge Ekibi ~ DevSecOps Birimi
@ExeOweR @Hea7 @Bunjo @teux