SQL 101 ve SQL Injection 101

Nuri Yavuz
17 min readJun 27, 2019

--

Sql Injection Hakkında:

Sql injection saldırısı her injection saldırısı gibi genel anlamıyla kendi kodumuzu sistemimize çalışacak bir şekilde enjekte etmek demektir, bu sql injection olduğunda durum web uygulamanın arka planda çalıştırdığı sql komutlarına kendi sql komutlarımızı da web sunucusuna gönderecek şekilde enjekte etmek diyebiliriz.

Sql injection saldırısı için bir sql admin kadar sql bilmemize gerek yoktur ama veritabanı mantığını anlamak, komutların mantığını anlamak ve ilerlediğimiz mantığı anlamak bir saldırı esnasında durumu analiz etmek için şarttır, bunlar dışında injection saldırılarında önemli olan kendi kaçak, zararlı kodumuzu sisteme kabul ettirebilme kısımıdır.

Kinetik dünyadan bir örnek verecek olursak bir çocuğa aşı yapmayı ele alabiliriz, iyi bir hemşire olmanın şartı bütün aşıların ne yaptığını ezberlenmesindense çocuğa fark ettirmeden, ağlatmadan aşı yapmaktır.

Yazının giriş kısımında kısa bir şekilde sql veritabanında işimize yaracak kısımları sizlerle paylaşmaya çalıştım bundan sonrasında kademeli olarak sql injectiona giriş yapacağız.

NOT: SQL hakkında yazıları okurken sql ve sql injection arasındaki bağlantıyı daha iyi kurabilmeniz açısından temel bir sql injectionun adımlarını aşağıda sizinle paylaşıyorum yazıyı okurken bu adımların aklınızda bulundurmanızın kavramanızda daha yardımcı olacağını düşünüyorum.

Aşağıdaki adımlar şuanlık biraz havada kalabilir, yazı içerisinde ve uygulamalı örneklerde daha iyi anlayacağınızı düşünüyorum.

Temel SQL Injection Adımları:

  1. Web uygulamanın arka planda veri çektiği tablonun kolon(column) sayısı bulunur.
  2. Web uygulamanın arka planda çektiği verilerin sayfa içerisinde nerelerden bizlere iletildiği bulunur, bu kısımlar ileride veri çekmek için ihtiyacımıza yarayacak.
  3. Web uygulamasının kullandığı database isimi bulunur.
  4. Database içerisindeki tablo isimleri bulunur.
  5. Veri çekeceğimiz tablo belirlenir ve bu tablonun kolon isimleri bulunur.
  6. Kolon isimleri belirlendikten sonra bu kolonlardan veriler çekilir.

Veritabanı nedir?

En basit anlamda veritabanı, belirli bir amaca yönelik düzen verilmiş kayıt ve dosyaların tümüdür. Bilgisayar sisteminizde arkadaş ya da müşterilerinizin ad ve adreslerini toplamış olabilirsiniz. Belki, yazdığınız tüm mektupları topluyor ve alıcıya göre düzen veriyorsunuz. Ödeme ve tahsilat yapılacak hesaplarınız ya da çek defterinizin borçlar ve bakiyesi gibi finansal verilerinizi topladığınız bir grup dosyalarınız da olabilir. Konularına göre düzen verdiğiniz sözcük işlemci belgeler, en geniş anlamda, bir tür veritabanıdır. Kullanıma göre düzen verdiğiniz elektronik tablo dosyaları da ayrı bir tür veritabanıdır. Windows Başlat menüsündeki tüm program kısayolları da bir veritabanıdır. Sık Kullanılanlar klasöründe düzen verilmiş internet kısayolları bir veritabanıdır.

Çok düzenliyseniz, birkaç yüz elektronik tablo ya da kısayolunu klasör ve alt klasörleri kullanarak yönetebilirsiniz. Bunu yaptığınızda, veritabanı yöneticisi siz olursunuz. Çözmeye çalıştığınız sorunlar büyüdükçe ne yapacaksınız? Veriler çeşitli belgelerde ya da elektronik tablolarda saklanmışken, tüm müşterilerle ve onların siparişleriyle ilgili bilgileri nasıl kolayca toplayabilirsiniz? Yeni bilgiler girince dosyalar arasındaki bağlantıları nasıl koruyabilirsiniz? Verilerin doğru girildiğinden nasıl emin olursunuz? Bilgilerinizi birçok kişiyle paylaşma gereksiniminiz olup, aynı anda iki kişinin aynı verileri güncelleştirmeye çalışmasını istemediğinizde ne yapacaksınız? Bu tür güçlüklerle karşılaşmışsanız, bir veritabanı yönetim sistemine (DBMS) gereksiniminiz var demektir.

Veritabanlarının amacı büyük miktardaki kurumsal verileri işlemektir. Veriler düzenli bir biçimde elektronik ortamda kaydedilirler. Düzenli olarak yedeklenen ve kontrol edilen bu bilgiler çok sayıda uygulamanın ve kullanıcının hizmetine sunulur. Büyük miktarlardaki verilerin hızlı ve güvenli bir biçimde gereksinim duyulan bilgiye dönüştürülmesi veritabanlarının en önemli özelliklerinden birisidir.

  • Veritabanı, belli bir alanda ve birbiriyle ilişkili olarak düzenlenmiş veriler topluluğudur.
  • Veritabanı, bir çok kullanıcı tarafından kullanılan birbirleriyle ilişkili geniş bir veri kümesinin düzenlenmesi, depolanması ve sorgulanması için kurulan sistemdir.
  • Veritabanı, bir çok uygulamaya hizmet vermek için zararlı ve gereksiz veriler hariç ilişkili verilerin saklandığı bir veri topluluğudur.
  • Veritabanı, bilgisayar temelli bir kayıt tutma sistemidir. Sistemin amacı verileri kayıt etmek ve bakımını yapmaktır.
  • Veritabanı, bir organizasyonda verilerin merkezi kontrolünü sağlar.
  • Veritabanı sistemi, basitçe kompüterize edilmiş bir kayıt takip sistemidir.

Günümüzde herhangi bir veritabanı yönetim sisteminin kullanılmadığı uygulama programlarına pek rastlanmıyor. Bu talebe bağlı olarak çok sayıda veritabanı yönetim sistemi ortaya çıkmıştır. Bunlardan bazıları MySQL,Microsoft Access, Microsoft SQL Server, Oracle, Sybase’dir. Bu veritabanlarının en önemli ortak özelliği ilişkisel veritabanı teknolojisini içermeleridir.

Table nedir, column nedir?

Veritabanı tablo veya tablolardan oluşur. Tablolar da her bir bilginin saklandığı alanlardan (columns) oluşur. Veri tabanlarında tutulacak bilgilerin doğru olarak girilmesi, tekrarlı kayıtların olmaması, verilerin güvenliği gibi özellikler ancak bir veri tabanı yönetim sistemiyle sağlanmaktadır.

Aşağıdaki komutların ilk 4 tanesi injection saldırılarında veri çekerken kesinlikle kullanılır.

Bu komutlardan SELECT, WHERE, ORDER BY, UNION komutlarının çalışma mantığını öğrenmek bir sql injeciton saldırısının temel mantığını öğrenmek için kritiktir.

Bunlara ek olarak mysql içerisinde bulunan Information_schema isimli özel database’in de ne olduğunun ve ne işe yaradığının kavranması sql injection yaparken mantığının anlanmasında kritik olucaktır. Yazı içerisinde bu konuyada değineceğim.

Temel SQL Komutları

  • SELECT — Veritabanından veri çekmek için kullanılır
  • WHERE — Koşul belirtmek için kullanılır
  • ORDER BY — Veriyi kolonlara göre sıralamak için kullanılır.
  • UNION- SQL komutlarını birleştirmek için kullanılır.
  • UPDATE — Veritabanındaki veriyi güncellemek için kullanılır
  • DELETE — Veritabanındaki veriyi silmek için kullanılır
  • INSERT INTO — Bir tabloya veri yazmak için kullanılır.
  • CREATE DATABASE — Veritabanı oluşturmak için.
  • DROP TABLE — Mevcut bir tabloyu silmek için.
  • CREATE TABLE — Yeni bir tablo oluşturmak için.
  • ALTER TABLE — Mevcut bir tabloyu güncellemek için.
  • ALTER DATABASE — Veritabanını modifiye etmek için.
  • CREATE INDEX — Index oluşturmak için.
  • DROP INDEX — Index silmek için.

Komutların İncelenmesi

Bu kısımda ihtiyacımıza yaracak bazı temel sql komutlarını sizlerle uygulamalı olarak paylaşacağım.

Sql komutlarının genel mantığının anlaşılma derecesi sql injection yaparken web uygulamasının davranışınında anlaşılmasını kolaylaştıracaktır.

Bu yazı sonrasında sql hakkında daha fazla uygulayarak bilgi sahibi olabileceğiniz https://www.w3schools.com/sql/

Sayfasındaki uygulamaları çözmenizi kesinlikle tavsiye ederim.

SELECT

En sık kullanılan SQL komutu SELECT ifadesidir. SQL SELECT ifadesi, veritabanındaki bir tablodan veriyi sorgulamak veya almak için kullanılır. Bir sorgu belirtilen sütunlardan veya tablodaki tüm sütunlardan bilgi alabilir.

Tablo adı: student_details

1.) SELECT first_name FROM student_details;

2.) SELECT first_name, last_name FROM student_details;

3.) SELECT * FROM student_details;

WHERE

Sql komutlarına belirli koşullar uygulamak ve filtrelemek için kullanılır.

  1. ) SELECT first_name, last_name FROM student_details
    WHERE id = 100;

2.)SELECT first_name, last_name,age FROM student_details
WHERE age < 21 ;

ORDER BY

Order by komutu sql injection içerisindeki kritik komutlardan biridir çünkü bizim dışarıdan saldırmakta olduğumuz web uygulamasının arka planda veritabanı içerisinde veri çektiği tablonun kolon sayısını bulmamız için temel yöntemlerden bir tanesidir.(UNION Komutunda neden veri çekmek istediğimiz tabloların kolon sayılarını bulmamızın kritik bir işlem olduğunu göreceğiz.

Verileri bir veya daha fazla sütuna göre artan veya azalan düzende sıralamak için kullanılır.

Order by aracılığı ile belirtilen kolondaki veriler sayısal ise bu kolonu baz alarak tablo içerisindeki verileri büyükten küçüğe doğru sıralar, “isim” “şehir” gibi alfabetik bir veri ise alfabetik olarak çıktıyı sıralar.

Önemli:

Order by komutu (Order by [Kolon adı] şeklinde kullanılabildiği gibi Order by [kolonun_sıra_numarası] şeklinde de kullanılabilinmektedir. Yukarıda kullanmış olduğumuz tablo için

İd:0 name:1 age:2 address:3 salary:4 şeklinde numaralandırılır. Yani;

SELECT * FROM CUSTOMERS ORDER BY 4;
Yukarıdaki bir sql komutu yazıldığında CUSTOMERS tablosundaki bütün veriler çekilir ardından
4. Column olan Salary kolonundaki sahip oldukları verilerin büyüklüklerine göre sıralanırlar.

SELECT * FROM CUSTOMERS ORDER BY SALARY; = SELECT * FROM CUSTOMERS ORDER BY 4;

O halde aşağıdaki komutta olduğu olan şekilde tablonun kolon sayısından daha büyük bir numara sırası ile yani olmayan bir kolon ile Order by ifadesini kullanırsak ne elde ederiz?

SELECT * FROM CUSTOMERS ORDER BY 5; ???
Bu şekilde bir komut çalıştırdığımızda SQL veritabanı bize error verecektir(Aşağıdaki resimde görüldüğü gibi). Bu durum bize sql injection saldırıları yaparken saldırdığımız uygulamanın arka planda veritabanında eriştiği column sayısını tespit etmek için kritiktir!

UNION

UNION operatörü, iki veya daha fazla SELECT ifadesinin sonuç kümesini birleştirmek için kullanılır.

Şartları vardır;

1) UNION içindeki her SELECT ifadesi aynı sayıda sütuna sahip olmalıdır.
2) Sütunların da benzer veri türlerine sahip olması gerekir.
3) Her SELECT ifadesindeki sütunlar da aynı sırada olmalıdır.

NOT: Web uygulamaları arka planda bizlere veri getirirken genel itibari ile SELECT komutu kullanırlar, bizim bu SELECT ifadesine kendi sql kodumuzu kabul ettirmemiz için kendi SELECT komutumuzu UNION ile birleştirmemiz gerekmekte, UNION ile birleştirmek içinde UNION SELECT ifadesi ile sql veritabanına göndereceğimiz kendi enjekte edilmiş kodumuzun aynı sayıda column çekmesi gerekmektedir.

INFORMATION_SCHEMA Nedir?
Her zaman tablolara kaydedilen verileri çekmek istemeyiz bazen de veritabanındaki tabloların kendisini cekmek isteyebiliriz. Bazen tablonun kolonlarının isimlerini bazen viewlerini… İşte bu gibi durumlarda devreye Information_Schema viewleri girer. Information_Schema viewleri, seçilen veritabanına ait meta datalara ulaşmamizi sağlar. Bunlara örnek veritabaninda bulunan tablo veya view isimleri ya da onlara ait kolon bilgileri olabilir.

NOT: Information_schema içerisinde information_schema.tables ve Information_schema.columns özellikle önemlidir.

İnformation_schema.tables: Veritabanı içerisinde bulunan bütün tabloların isimlerini tutar.

İnformation_schema.columns: Veritabanın içerisindeki tablolarda bulunan bütün sütun yani column isimlerini tutar.

SQL Injection yaparken genellikle kullanılan bazı sql fonksiyonlar ve tanımlar:
Aşağıdaki fonksiyonların ve tanımların varlığının ve anlamlarının bilinmesi bir sql injection saldırısı yapılırken işimize yarayacaktır.

Version() veya @@version: Sunucuda çalışan mysql versiyonunu bize verir.
Database() veya @@database: Web uygulamasının veriyi çekerken kullandığı database isimini bize verir.
User(): Web uygulamanın arka planda sql server’a bağlanırken kullandığı veritabanı kullanıcısını bize verir.

İnformation_schema’nın sql yapısı içerisindeki table, column, database ve çeşitli başka verilerinin isimlerini barındırdığını söylemiştik. Aşağıdaki tanımlarda information_schema içerisinde çeşitli table’ler içerisinde bulunan bazı kolon isimleridir bu tanımları injection saldırıları yaparken ayrıntılı bir şekilde kullanırız.

information_schema.tables sql yapısı içerisindeki bütün tablo isimlerini tutan ve bu tabloların ait olduğu veritabanı isimlerini tutan bir tablodur;
table_name: information_schema.tables tablosu içerisinde bir kolon olan table_name bu tablo içerisinde tablo isimlerinin bulunduğu column isimidir.

table_schema: table_schema de bu tablo içerisinde bulunan table isimlerinin ait olduğu database(veritabanı) isimlerinin bulunduğu column isimidir.

information_schema.columns sql yapısı içerisindeki bütün column isimlerini tutan ve bu columnların ait olduğu table isimlerini tutan bir tablodur;

column_name: information_schema.columns tablosu içerisinde bir kolon olan column_name veritabanındaki column isimlerinin bulunduğu kolon adıdır.

Sql injection için temel sql komutlarının üstünden geçtiğimize göre artık web for pentester 1 makinamız içerisinde bulunan örneklere başlayabiliriz.

Örneği size aktarmadan önce nasıl bir düşünme sistemi ile ilerlediğimizden bahsetmeye çalışacağım,

Web For Pentester:

Örneğe geçmeden önce web for pentester kurulumu ve network ayarlarından bahsetmek isterim.

Bu makinayı https://pentesterlab.com/exercises/web_for_pentester/iso linkinden indirebilirsiniz.

Indirdikten sonra sanal makine olarak kurulurken 1 GB RAM verilmesini tavsiye ederim.

Kurulum bittikten sonra sanal makine ağ ayarlarına gelip NAT’ı seçiyoruz.

Makinamızın ip adresini öğrenmek için vmware veya virtualbox üzerinden makinamızın terminaline gelip “ifconfig” komutunu yazabiliriz.

İp adresini öğrendikten sonra browser üzerinden bu ip adresine ulaşıp web for pentestera ulaşabiliriz.

Sql Injection1:

Sayfamız açıldığında karşımıza bu geliyor.

Şimdi bu noktada arka planda nasıl bir sistem çalıştığını tahmin etmemiz gerekmekte, kendimize bu web sitesi ne yapıyor,nasıl yapıyor olabilir, bu işlemleri yaparken arka planda neleri kullanıyor olabilir şeklinde düşünmeliyiz, sistemi ne kadar kavrayabilirsek o kadar rahat kendi zararlı kodumuzu da enjekte edebiliriz.

Sayfa içerisine baktığımızda ID si:2 name:root age:30 değerlerini bir tablo içerisinde görmekteyiz.

URL’e baktığımızda da /example1.php?name=root değerini görmekteyiz.

Arka plandaki sistemi tahmin edersek acaba ne olabilir?

/example1.php bizden name şeklinde bir değişken alıp arka planda bu değişkeni bir veritabanının tablosu içerisinde aratıp ardından da name kolonu bizim gönderdiğimiz veriye eşit olan verileri bize getiriyor olabilir şeklinde bir tahmin yürütebiliriz.

Peki bunu tahmini bir mantığa dökecek olursak nasıl düşünebiliriz?

Kullanıcı tablosunu getir, isimi “root”(bizim URLden gönderdiğimiz değer) olmayanları ele, bu şarta uyanları web uygulamasına gönder.

Peki bunu tahmini bir sql komutuna dökecek olursak nasıl düşünebiliriz?

Select * from [tablo_adı] where [name_kolon_adı] = “root”;

Şeklinde genel bir tahmin yaparsak buradaki genel itibari şartları sağlamakta.

Genel tahmin işlemimiz bittiğine göre şimdi uygulamanın gerçekten kullandığı kodları da açıp inceleyelim, gerçek bir testte elbette bu kodlara erişimimiz olmayacak fakat öğrenme açısından bu şekilde ilerlememiz daha iyi olacaktır.

Yazılımın kodlarına web for pentester sanal makinasının terminaline gelip aşağıdaki görseldeki komutlarını yazarak erişebiliriz.

Example1.php arka planında çalışan kodu açtık, şimdi bu kodu 4 aşama halinde inceleyelim.

1.adımda kodun tahmin ettiğimiz gibi sql isimli bir değişkenin tanımlandığı içerisinde de

SELECT * FROM users where name= şeklinde bütün kullanıcı isimlerini getiren ardından da

2. Adımda da sql.= $_GET[“name”]’ şeklinde URL den bizim göndermiş olduğumuz name değişkenini sql değişkenine eklediğini görmekteyiz.

Yani bu işlemden sonra sql = SELECT * FROM users where name=root’ olmakta

3. adımda mysql_query($sql) fonksiyonu ile bu sql querynin çalıştırıldığını ve ardından çıktısının result isimli değişkene kayıt edildiğini görmekteyiz.

4.adımdada result içerisindeki cevabın işlenip ekrana sadece id, name ve age kolonlarında bulunan verilerinin basıldığını görmekteyiz.

Yani bu kısımdan anladığımız kadarı ile bizim gönderdiğimiz veri name değişkenine atılmakta yani bu kısıma belirli bir hakimiyetimiz var.

Peki burada url üzerinden gönderdiğimiz veri bir sql komutunun içerisine yazılıyor ise ben bu sql komutuna kendi web tarayıcım üzerinden nasıl injection yapabilirim diye düşünelim.

Öncelikle sql komutunu direktman gönderirsek;(gönderdiğim komut order by 1 her tabloda en az 1 kolon olacağından kesinlikle çalışmalı.)

Sayfanın çalışmadığını göreceğiz bunun nedeni;

SELECT * FROM users where name = ‘root order by 1’ olmasıdır yani URL üzerinden gönderdiğimzi komut arka planda tırnak “ ’ ” işaretleri arasında kaldığından string yani sadece yazı olarak algılanmakta ve name değişkeninin içine atanmakta yani arka plan kodu bunu çalıştırılacak bir kod olarak görmemekte, çocuğa aşıyı yapmayı beceremedik.

Peki bu durumda bu tırnak işaretlerinden nasıl kaçabiliriz?

Enjekte edeceğimiz kodun başına tırnak eklemeyi deneyelim;

Gene bir çıktı alamadık fakat bu sefer bir öncekinden farklı olarak sayfamız komple yüklenmedi yani aslında arka planda bir hata yaratmış olduk.

Arka planda kayıt edilmiş sql kodumuz ise;

Select * from users where name=‘root’ order by 1’ oldu. Bu noktada name parametresinin tırnaklarını kapatmayı başardık fakat sonda kalan (1den sonra gelen tırnak işareti) yüzünden kodumuz hata verdi ve çalışmadı.

Bu tırnak işaretinden de kurtulmamız gerekiyor.

Bu işaretten kurtulmak için kodun geri kalanını yazılım dillerinde bulunan commentleme yani yorum satırı haline çevirmemiz gerekiyor. Bu işlemi farklı şekillerde yapabiliriz fakat bu örnekte en temel olan ”-- -” sembolü ile ilerleyelim. Bu şekilde ” -- -” ifadesinden sonra gelen kısım kod tarafından işlenmeyecek hale gelecektir.

Komutumuzu order by 1 -- - şeklinde göndermeyi deneyelim.

Yani arka planda çalışan kodumuz select * from users where name = ‘root’ order by 1 -- -’ oldu sql için geçerli çalışabilen bir komut.

Görüldüğü üzere sayfamız sorunsuz şekilde yüklendi demek ki kod başarılı bir şekilde çalıştı.

Şimdi bu kodda çalışan where name = ‘URL’den alınan name’ kısımı tablo içerisindeki satır için doğru ise o satırdaki verilerin bize getirildiğini yanlışsa getirilmediğini düşünürsek bu koda bu çıktığı her zaman doğru(true) yapan bir sql kodu enjekte edersek içerideki bütün users tablosunu çekebiliriz, bunun testini yaparak ilerleyelim.

SQL kodunda and(ve) or(yada) gibi bazı mantık matematiğine benzer komutlar bulunmaktadır.

Eğer biz Select * from users where 1=1 şeklinde bir komut yazarsak usersdaki bütün veriler id, name, age olarak yüklenecektir.

Aynı mantık çerçevesinde select * from users where 1=0 yazarsakta hiçbir veri yüklenmeyecektir.

Bu uygulamanın arka planında değiştiremeyeceğimiz bir

Select * from users where name = ‘Gönderilen veri’ şeklinde bir komut olduğundan bunu enjekte ettiğimiz kod ile bir şekilde manipüle etmeliyiz.

Eğer biz arka planda çalışan kodu;

Select * from users where name = ‘herhangi bir veri’ or 1=1 e çevirmeyi başarabilirsek bütün users tablosundaki id, name, age kolonları yüklenmesini bekleriz, bunu deneyelim.

Şuan sunucudaki database içerisinden farklı veriler çekmek istiyorsak bizim bu kodun içerisine başka bir SELECT komutu enjekte etmemiz gerekiyor, hali hazırda da arka planda çalışan bir SELECT komutu olduğunu düşünürsek(veri çekme işlemlerinde bu her zaman böyledir.) bizim buraya kendi SELECT kodumuzu kabul ettirmemiz için UNION ifadesini kullanmamız gerekmekte. Yani kodumuz;

Select * from vs…. UNION Select vs …. Şeklinde olmalı.

Hatırlarsak UNION ifadesi iki SELECT ifadesini birleştirmesi için şartı iki SELECT ifadesinde de aynı sayıda kolon çekilmesiydi. Yani bu durumda bizim web uygulamasının arka planda çektiği kolon sayısını saldırgan olarak bulmamız gerekiyor.

Bunun için Order by komutunu kullanacağız. Order by komutunu anlattığım kısımı tekrardan ele alacak olursak order by normal kullanımında aslında verileri verilen kolondaki veriye göre sıralamak için kullanılıyordu (Ör: order by name) ama kolonun sıra numarasını verdiğimiz zamanda aynı işlevle çalışmaktaydı(Ör: order by 5). Tablonun sahip olduğu kolon sayısından daha büyük bir numara verdiğimizde de sayfa hata vermekte.

Yani “order by” komutu ile table’ın kolon sayısını bulacağız.

Şimdi order by komutunu order by 1ve order by 100000000 şeklinde iki deneme yaparak ayrı şekilde enjekte edelim ve çıktıları inceleyelim.

’ order by 1 -- -

Görüldüğü üzere arka planda kullanılan tabloda kesinlikle en az bir kolon sayısı olduğundan sayfa normal bir şekilde yüklendi. Şimdi order by 100000000 ile deneme yapalım.

’ order by 10000000000 -- -

Sayfamız yüklenmedi yani mantıken tablomuzda bu yükseklikte bir kolon sayısı olmadığından arka planda çalışan kod çıktıları 10000000000. Kolon verisine göre sıralamaya çalıştı ve böyle bir kolon bulamadığından hata verdi.

Select * from user where name = ‘root’ order by 10000000000 -- -

Şimdi deneme yanılma yaparak kolon sayısını bulalım, burada hata aldığımız rakamın her seferinde yarısını denersek daha hızlı sonuç elde edebiliriz. Yazı uzamasın diye bu kısımı yazı ile açıklayacağım.

Denemeler ve çıktıları:

’ order by 20 -- -hata alıyoruz

’ order by 10 -- -hata alıyoruz

’ order by 5 -- -hata almıyoruz. Ama hata almamız bu tablonun 5 kolona sahip olduğunu kanıtlamaz sonuçta ’ order by 1 -- -dersekte hata almazdık, bunu kanıtlamalıyız.

’ order by 6 -- -denediğimizde gene hata alıyoruz en son order by 5 denediğimiz zaman hata almadan kodumuz çalışmıştı yani users tablosunun 5 adet kolonu olduğunu kanıtladık.

Burada ilk gözümüze çarpması gerekenlerden bir tanesi de users tablosunda 5 kolon var ama ben sorgulama yaptığımda sadece 3 kolonun verilerini görebiliyorum? Demek ki bize gösterilmeyen başka user verileri de olabilir.

Arka planda veri çekilen tablonun kolon sayısını bulduk fakat aslında normal şartlarda saldırganın koda erişimi olmadığından bu tablonun adının “users” olduğunu da bilemez, bu adımdan itibaren saldırganın tarafına geri döneceğiz ve veritabanının isimini, veritabanının içerisindeki tablo isimlerini, bu tabloların sahip olduğu kolon isimlerini en sonunda da seçtiğimiz tablo ve kolonlardan veri çekerek ilerleyeceğiz.

Yazıda ilerlemeden önce 8. Sayfaya dönerek database(), table_name, table_schema, column_name ifadelerini tekrar etmenizi öneririm.

Şuan sonraki adımımız olan tablo isimlerini öğrenmemiz gerekiyor. Şuan saldırgan taraf olarak arka plandaki hiçbir veritabanındaki hiçbir tablonun adını bilmiyoruz, tek bir hariç ile: “information_schema” 7 ve 8 sayfaya dönüp tekrar edecek olursak information_schema bütün database içerisindeki veritabanı, table, column isimlerini tutan özel bir database yapısıydı.

İnformation_schema.tables tablosu bütün tablo isimlerini information_schema.columns’da bütün kolon isimlerini tutmaktaydı.

O halde ben;

union select 1,2,3,4,5 from information_schema.tables -- -(dikkat edin 5 adet)

Komutunu URL üzerinden çalıştırırsam, aşağıdaki gibi bir çıktı elde ederiz.

Bu noktada biraz kafanızın karışması normal tamam biz information_schema.tables tablosundan veri çekmeye benzer bir ifade yazdık ama nedir bu 1,2,3,4,5? Aslında burada şöyle bir durum söz konusu biz

Union select 1,2,3,4,5 from information_schema.tables -- -dediğimiz zaman information_schema.tables tablosundan herhangi bir veri çekmiyoruz sadece bu tablo içerisinde 5 kolonu temsil et tarzında bir komut çalıştırıyoruz, bu sayede hem örnek bir union aracılığı ile birleştirilmiş select sorgusunu çalıştırılmasını test etmiş hem de etkileşim kurabileceğimiz kolon numaralarını belirlemiş oluyoruz, yani biz web uygulamasında bulunan 1,2,3 kolonları üzerinden verilerimizi dışarı çıkartabiliriz.

Burada 1,2,3,4,5 ifadesinin aslında birşey ifade etmediğini açıklamak için ifadeyi ‘a’,’b’,’c’,’d’,’e’(tırnak içersinde olmaları string yani yazı olmaları kaynaklı) ile değiştirip bir istek daha attım;

Şimdi sonraki adıma geçelim ve bu web uygulamasının kullandığı veritabanıının adını ardından da bu veritabanının içerisindeki tabloları farklı select komutları enjekte ederek çekelim.

İnformation_schema.tables tablosunda her bir sütunun sql yapısı içerisindeki tabloların isim, ait olduğu database, özellikleri gibi yapılardan oluştuğunu görmüştük.

Bu sütun içerisinde table_name kolonunun tabloların adını tuttuğunu, table_schema kolonununda o sütun içerisinde tutulan tablo verisinin ve

table_schema’nın da information_schema.tables içerisinde o sütun içerisinde tutulan tablonun veritabanı isimini tuttuğunu, database() fonksiyonununda o an ki web uygulaması tarafından kullanılmakta olan veritabanı isimini verdiğini 8. Sayfada görmüştük.

Daha açık örnekler olmadan anlaşılması zor olabilir, bir kere anlaşılınca da bir daha ezbere ihtiyaç duymayacağınız ve kolay gelecek bir konudur.

O halde ben içeri;

union select table_name, table_schema, database(),4,5 from information_schema.tables -- -

Şeklinde bir komut enjekte edersem ne elde ederim? İnceleyelim.

Yukarıdaki gibi bir çıktı elde ettik.

Burada çalıştırdığımız komutu açıklayacak olursak.

İnformation_schema.tables tablosundan 1. Kolonda bütün table_name, 2.kolonda bütün table_schema verilerini sırası ile getir, 3. Kolonda da bu sayfadaki web uygulamasının arka planda bağlandığı sql veritabanı bana getir. Şeklinde özetleyebiliriz.

3. Kolonumuza dikkat edecek olursak bütün veriler “exercises” olarak geldiğini, buradan da bu web uygulamasının arka planda “exercises” isimli bir veritabanına bağlı olduğunu anlayabiliriz.

1. Kolonumuza dikkat edecek olursak burada bütün sql yapısı içerisinde bulunan table isimlerinin(table_name) basıldığını 2. Kolonda da bu tablelelerin ait olduğu database isimlerinin(table_schema) basıldığını görebiliriz.

Buradan en sondaki users tablosu haricinde bütün çekilen table isimlerinin information_schema veritabanı içerisinde bulunduğunu, bütün sql yapımızda “exercises” ve “information_schema” dışında başka bir veritabanı olmadığını anlayabiliriz.

information_schema zaten default olarak var olan bir veritabanı olduğundan içerisindeki veriler bizim ilgimizi çekmeyecektir. Burada diğer veritabanı olan “exercises” üzerinden veri çekerek ilerlememiz hassas verilere bizi götürecek olan yoldur.

O halde sonraki adıma geçelim gene information_schema.tables içerisinden bütün table isimlerini alalım fakat ekrana sadece “exercises” veritabanına ait olanları yazdıralım. Bunun için aşağıdaki gibi bir komut çalıştıralım ve çıktıyı inceleyelim;

’ union select table_name,table_schema,3,4,5 from information_schema.tables where table_schema = “exercises” -- -

Yukarıdaki gibi bir çıktı elde ettik, buradan exercises veritabanı içerisinde sadece users isimli bir tablonun var olduğunu anlayabiliriz.

Sonraki adım olan bu users tablosu içerisinde bulunan kolon isimlerini ekrana çekerek devam edelim.

İlerlemeden önce 8. sayfaya dönüp information_schema.columns ve column_name ifadelerinin ne anlama geldiğini tekrar etmekte fayda var.

İnformation_schema.columns , information_schema.tables ‘a benzer bir şekilde başka bir tablodur tek farklı information_schema.tables sql yapısı içerisindeki table verilerini tutarken, information_schema.columns sql yapısı içerisindeki bütün column ların verilerini tutar, column_name’de bu tablo içerisindeki kolon isimlerini tutan özel bir kolonun adıdır.

Öncelikle sql yapısı içerisindeki bütün column isimlerini çeken bir sql komutu yazalım ve bunu sisteme enjekte edip çıktısını inceleyelim;

union select column_name,2,3,4,5 from information_schema.columns -- -

Çıktı içerisinde bir sürü değişik veriler elde ettik, bunlar bütün sql yapısında bulunan bütün kolonların isimleridir. Bu değişik kolon isimlerinin çoğu da information_schema veritabanına aittir.

Peki ben sadece users tablosu içerisindeki kolon isimlerini elde etmek için ne yapabilirim?

Bunun gibi gene bir WHERE komutu kullanarak bütün kolon isimlerini çek ama bana sadece ait olduğu tablo users ise getir şeklinde bir komut yazabiliriz, deneyelim.

union select column_name,2,3,4,5 from information_schema.columns where table_name = “users” -- -

Görüldüğü gibi bu sefer web uygulamamızın ilk kolonunda sadece users tablosuna ait kolon isimleri geldi.

Öncedende tahmin ettiğimiz gibi bu users tablosu içerisinde groupid, passwd şeklinde bize gösterilmeyen başka verilerde varmış.

Bütün users tablosu içerisindeki hassas verileri sistemden çekerek devam edelim.

Bunun için aşağıdaki gibi basit bir komut yazmamız yeterlidir;

union select name,groupid,passwd,4,5 from users -- -

Web uygulamasının 1.kolonunda bütün kullanıcı isimleri, 2. Kolonunda bu kullanıcıların groupid(sistemsel yetki)lerini, 3. Kolonda da parolarını elde etmiş bulunmaktayız.

Sizlere temel sql injection ile aktaracaklarım bu kadardır, bu işleri otomatize bir şekilde yapan sqlmap isimli kullanımı çok basit bir araçta bulunmaktadır bu tool ile ilgili internetten çok kolay kullanımını öğreten yazılar bulabilirsiniz fakat arka planda asıl çalışan mantığı kavramak çok daha önemlidir böylece toolların işe yaramadığı anlarda kendimiz araya girip olaya müdahele edebiliriz.

Yazıları buraya kadar okuduysanız size çok teşekkür ederim, sorularınızı sormaktan yada aktarımımın yetersiz olduğu noktaları sormaktan çekinmeyiniz.

Yukarıda anlatılanların hepsini derleyip toplamak epeyce vaktimi alsada ben değdiğine ve değeceğine inanıyorum ve bu içeriği tasarlayan Nihat Alpcan Onaran a paylaşmama izin verdiği için teşekkür ederim,umarım faydalı olmuştur.

--

--

Nuri Yavuz
Nuri Yavuz

Written by Nuri Yavuz

“No effect is before the cause” in the same time “Cause doesn’t necessarily come before effect”

No responses yet