mysql
Detayları çekilecek blogpostun id'si GET'ten "post" parametresi ile alınıyor. Ardından o blogpostun detaylarının çekilmesi için "mw_blogs" tablosundan "id" kolonu gelen değere eşit olan blogpost çekiliyor. Ardından "mw_comments" tablosundan "postid" kolonu gelen değere eşit olan commentler çekiliyor.
Bunları join ile yapmamışlar, ayrı ayrı 2 sorgu ile yapmışlar, birazdan göstereceğim.
Örnek "mw_blogs" tablom aşağıdaki gibi;
Örnek "mw_comments" tablom aşağıdaki gibi;
Sayfadaki kodlar ise şu şekil;
SELECT * FROM ".$database['prefix']."blogs
WHERE id = '$b_post'
LIMIT 1
SELECT * FROM ".$database['prefix']."comments
WHERE postid = '$b_post'
ORDER BY id ".($SETTINGS->commentsOrder=='asc' ? 'DESC' : 'DESC')."
Bug'ın detayları
Şöyleki; WHERE içerisinde 2 farklı condition OR bağlacı ile kullanıldı ise; eğer ilk condition sağlanıyor ise 2. contition'nın sağlanması için 1. condition dışında kalan row'larda işlem yapılıyor. Bu anlattığımı şöyle ifade edeyim;
select * from mw_comments where postid=1 OR email like '%a%'
gibi bir sorguda ilk condition'da postid'si 1 olan row seçilip köşeye alınıyor; 2. condition için postid'si 1 olmayan rowlarda işlem yapılıyor.
Şimdi; bu case'in bana assigne edildiği yorumda %27%20OR%20(SLEEP(10))=0--+
patternı ile PoC yapıldığı yazıyor.
Durum 1; Bu pattern'ı postid'si 1 olan blogpost için uyguladığımızda sorgu şöyle oluyor;
SELECT * FROM mw_comments
WHERE postid = '1' OR (SLEEP(10))=0 -- '
ORDER BY id ASC
Bu sorguda ilk condition postid=1 olduğundan postid'si 1 olan 4 row seçiliyor (idleri 2,3,4,5 olanlar). Geriye sadece postid'si 2 olan 1 row kalıyor.
Bu sorgu için geriye 1 row kaldığından sleep fonksiyonu 1 kere çalışıyor ve toplam süre = (1 * sleep(10)) + (normal query time) oluyor.
Durum 2; Bu pattern'ı postid'si 2 olan blogpost için uyguladığımızda sorgu şöyle oluyor;
SELECT * FROM mw_comments
WHERE postid = '2' OR (SLEEP(10))=0 -- '
ORDER BY id ASC
Bu sorguda ilk condition postid=2 olduğundan postid'si 2 olan 1 row seçiliyor. Geriye postid'si 1 olan 4 row kalıyor.
Bu sorgu için geriye 4 row kaldığından sleep fonksiyonu 4 kere çalışıyor ve toplam süre = (4 * sleep(10)) + (normal query time) oluyor.
Özetle; sleep'in kullanıldığı condition a ulaşıldığında geriye kaç row sayısı kadar dönüyor sleep. Bunu belki MySQL'e bildirebiliriz.
Bu casedeki asıl sorun bu başlıktı sanırım. Bunu araştırıken yukarıdaki detayları tespit ettim. Biz aşağıdaki gibi saldırmışız;
http://debianserver/ScanApp/maian_weblog/publish/index.php?cmd=blog&post=123%27%20OR%20(SLEEP(10))=0--+
Öncelikle şunu belirteyim; yukarıda dediğim gibi adamlar postu ve commentleri çekerken join kullanmamış. 2 ayrı query yazmış. Dolayısı ile yaptığımız injection 2 ayrı query'de çalışıyor ve 2x zamanla bize geri dönüyor.
Database'de postid'i 123 olan ne blogpost, ne comment var. O yüzden bu şekilde saldırıldığında aşağıdaki gibi bir hesaplama oluyor;
(query sayısı) * (postid'i 123 olmayan postların sayısı) * (postid'i 123 olmayan commentlerin sayısı) * (sleep)
Yukarıda verdiğim database örneğine göre; 2 * 3 * 5 * 10 = 300saniye.