wuhp commited on
Commit
1adcbad
·
verified ·
1 Parent(s): fde4d6e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +112 -229
app.py CHANGED
@@ -1,320 +1,203 @@
1
  import gradio as gr
2
  import hashlib
3
  import zlib
4
- import base64
5
- import re
6
  import bcrypt
 
7
 
8
- from passlib.hash import (
9
- md5_crypt,
10
- sha256_crypt,
11
- sha512_crypt,
12
- argon2,
13
- )
14
 
15
- # -----------------------------------
16
- # JAVA HASHCODE
17
- # -----------------------------------
18
-
19
- def java_string_hashcode(s):
20
  h = 0
21
-
22
- for ch in s:
23
- h = (31 * h + ord(ch)) & 0xFFFFFFFF
24
-
25
- # convert to signed int32
26
  if h >= 0x80000000:
27
  h -= 0x100000000
28
-
29
  return str(h)
30
 
31
 
32
- # -----------------------------------
33
- # DJB2
34
- # -----------------------------------
 
 
 
 
35
 
36
  def djb2(s):
37
  h = 5381
38
-
39
  for c in s:
40
  h = ((h << 5) + h) + ord(c)
41
-
42
  return str(h & 0xFFFFFFFF)
43
 
44
 
45
- # -----------------------------------
46
- # FNV1A 32
47
- # -----------------------------------
48
-
49
- def fnv1a_32(s):
50
  h = 0x811c9dc5
51
-
52
  for c in s:
53
  h ^= ord(c)
54
  h *= 0x01000193
55
  h &= 0xFFFFFFFF
56
-
57
  return str(h)
58
 
59
 
60
- # -----------------------------------
61
- # BASE64 CHECK
62
- # -----------------------------------
63
 
64
- def is_base64(value):
65
- try:
66
- decoded = base64.b64decode(value).decode()
67
- return decoded
68
- except:
69
- return None
70
-
71
-
72
- # -----------------------------------
73
- # IDENTIFY HASH
74
- # -----------------------------------
75
-
76
- def identify_hash(hash_value):
77
-
78
- possible = []
79
 
80
  if hash_value.startswith("$2"):
81
- possible.append("bcrypt")
82
-
83
- if hash_value.startswith("$argon2"):
84
- possible.append("argon2")
85
 
86
- if hash_value.startswith("$6$"):
87
- possible.append("sha512_crypt")
 
 
 
 
 
 
88
 
89
- if hash_value.startswith("$5$"):
90
- possible.append("sha256_crypt")
91
 
92
- if re.fullmatch(r"[a-fA-F0-9]{32}", hash_value):
93
- possible.extend(["MD5", "NTLM"])
94
 
95
- elif re.fullmatch(r"[a-fA-F0-9]{40}", hash_value):
96
- possible.append("SHA1")
 
97
 
98
- elif re.fullmatch(r"[a-fA-F0-9]{64}", hash_value):
99
- possible.append("SHA256")
 
 
 
 
 
 
 
100
 
101
- elif re.fullmatch(r"[a-fA-F0-9]{128}", hash_value):
102
- possible.append("SHA512")
103
 
104
- # Integer hashes
105
- if re.fullmatch(r"-?\d+", hash_value):
106
- possible.extend([
107
- "Java String.hashCode()",
108
- "CRC32",
109
- "Adler32",
110
- "DJB2",
111
- "FNV1a-32"
112
- ])
113
 
114
- return list(dict.fromkeys(possible))
115
 
 
116
 
117
- # -----------------------------------
118
- # VERIFY
119
- # -----------------------------------
 
 
 
 
 
120
 
121
- def verify(password, hash_value):
122
 
123
  results = []
 
124
 
125
  # -------------------------
126
- # STANDARD HASHES
127
- # -------------------------
128
-
129
- try:
130
- if hashlib.md5(password.encode()).hexdigest().lower() == hash_value.lower():
131
- results.append("✅ MD5")
132
- except:
133
- pass
134
-
135
- try:
136
- if hashlib.sha1(password.encode()).hexdigest().lower() == hash_value.lower():
137
- results.append("✅ SHA1")
138
- except:
139
- pass
140
-
141
- try:
142
- if hashlib.sha256(password.encode()).hexdigest().lower() == hash_value.lower():
143
- results.append("✅ SHA256")
144
- except:
145
- pass
146
-
147
- try:
148
- if hashlib.sha512(password.encode()).hexdigest().lower() == hash_value.lower():
149
- results.append("✅ SHA512")
150
- except:
151
- pass
152
-
153
- # -------------------------
154
- # JAVA HASHCODE
155
  # -------------------------
156
 
157
- try:
158
- if java_string_hashcode(password) == hash_value:
159
- results.append("✅ Java String.hashCode()")
160
- except:
161
- pass
162
 
163
  # -------------------------
164
  # CRC32
165
  # -------------------------
166
 
167
- try:
168
- crc = zlib.crc32(password.encode())
169
-
170
- signed_crc = crc
171
- if crc >= 0x80000000:
172
- signed_crc -= 0x100000000
173
-
174
- if str(crc) == hash_value or str(signed_crc) == hash_value:
175
- results.append("✅ CRC32")
176
- except:
177
- pass
178
 
179
  # -------------------------
180
  # ADLER32
181
  # -------------------------
182
 
183
- try:
184
- adler = zlib.adler32(password.encode())
185
-
186
- signed_adler = adler
187
- if adler >= 0x80000000:
188
- signed_adler -= 0x100000000
189
-
190
- if str(adler) == hash_value or str(signed_adler) == hash_value:
191
- results.append("✅ Adler32")
192
- except:
193
- pass
194
 
195
  # -------------------------
196
  # DJB2
197
  # -------------------------
198
 
199
- try:
200
- if djb2(password) == hash_value:
201
- results.append("✅ DJB2")
202
- except:
203
- pass
204
 
205
  # -------------------------
206
  # FNV1A
207
  # -------------------------
208
 
209
- try:
210
- if fnv1a_32(password) == hash_value:
211
- results.append("✅ FNV1a-32")
212
- except:
213
- pass
214
 
215
  # -------------------------
216
- # BCRYPT
217
- # -------------------------
218
-
219
- try:
220
- if hash_value.startswith("$2"):
221
- if bcrypt.checkpw(
222
- password.encode(),
223
- hash_value.encode()
224
- ):
225
- results.append("✅ bcrypt")
226
- except:
227
- pass
228
-
229
  # -------------------------
230
- # PASSLIB
231
- # -------------------------
232
-
233
- try:
234
- if hash_value.startswith("$6$"):
235
- if sha512_crypt.verify(password, hash_value):
236
- results.append("✅ sha512_crypt")
237
- except:
238
- pass
239
-
240
- try:
241
- if hash_value.startswith("$5$"):
242
- if sha256_crypt.verify(password, hash_value):
243
- results.append("✅ sha256_crypt")
244
- except:
245
- pass
246
-
247
- try:
248
- if hash_value.startswith("$argon2"):
249
- if argon2.verify(password, hash_value):
250
- results.append("✅ argon2")
251
- except:
252
- pass
253
-
254
- # -------------------------
255
- # BASE64
256
- # -------------------------
257
-
258
- decoded = is_base64(hash_value)
259
-
260
- if decoded is not None:
261
- if decoded == password:
262
- results.append("✅ Base64 encoded string")
263
-
264
- return results
265
-
266
 
267
- # -----------------------------------
268
- # MAIN
269
- # -----------------------------------
270
 
271
- def analyze(password, hash_value):
272
-
273
- possible = identify_hash(hash_value)
274
-
275
- results = verify(password, hash_value)
 
276
 
277
  return (
278
- "\n".join(possible) if possible else "Unknown",
279
- "\n".join(results) if results else "No matches found."
280
  )
281
 
282
 
283
- # -----------------------------------
284
  # UI
285
- # -----------------------------------
286
 
287
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
288
 
289
- gr.Markdown("# Advanced Hash / Encoding Analyzer")
290
-
291
- with gr.Row():
292
-
293
- password = gr.Textbox(
294
- label="Known Password",
295
- type="password"
296
- )
297
-
298
- hash_value = gr.Textbox(
299
- label="Hash / Encoded Value",
300
- lines=5
301
- )
302
-
303
- button = gr.Button("Analyze")
304
 
305
- alg_output = gr.Textbox(
306
- label="Possible Algorithms"
 
307
  )
308
 
309
- result_output = gr.Textbox(
310
- label="Verification Results",
311
- lines=10
 
312
  )
313
 
314
- button.click(
 
 
 
 
 
315
  analyze,
316
- inputs=[password, hash_value],
317
- outputs=[alg_output, result_output]
318
  )
319
 
320
  demo.launch()
 
1
  import gradio as gr
2
  import hashlib
3
  import zlib
4
+ import itertools
5
+ import string
6
  import bcrypt
7
+ from collections import Counter
8
 
9
+ # -----------------------------
10
+ # HASH FUNCTIONS
11
+ # -----------------------------
 
 
 
12
 
13
+ def java_hash(s):
 
 
 
 
14
  h = 0
15
+ for c in s:
16
+ h = (31 * h + ord(c)) & 0xFFFFFFFF
 
 
 
17
  if h >= 0x80000000:
18
  h -= 0x100000000
 
19
  return str(h)
20
 
21
 
22
+ def crc32_hash(s):
23
+ return str(zlib.crc32(s.encode()))
24
+
25
+
26
+ def adler32_hash(s):
27
+ return str(zlib.adler32(s.encode()))
28
+
29
 
30
  def djb2(s):
31
  h = 5381
 
32
  for c in s:
33
  h = ((h << 5) + h) + ord(c)
 
34
  return str(h & 0xFFFFFFFF)
35
 
36
 
37
+ def fnv1a(s):
 
 
 
 
38
  h = 0x811c9dc5
 
39
  for c in s:
40
  h ^= ord(c)
41
  h *= 0x01000193
42
  h &= 0xFFFFFFFF
 
43
  return str(h)
44
 
45
 
46
+ # -----------------------------
47
+ # DETECTION
48
+ # -----------------------------
49
 
50
+ def detect(hash_value):
51
+ candidates = []
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  if hash_value.startswith("$2"):
54
+ candidates.append("bcrypt")
 
 
 
55
 
56
+ if hash_value.isdigit() or (hash_value.startswith("-") and hash_value[1:].isdigit()):
57
+ candidates += [
58
+ "java_hash",
59
+ "crc32",
60
+ "adler32",
61
+ "djb2",
62
+ "fnv1a"
63
+ ]
64
 
65
+ return list(dict.fromkeys(candidates))
 
66
 
 
 
67
 
68
+ # -----------------------------
69
+ # ATTACK ENGINE
70
+ # -----------------------------
71
 
72
+ def try_match(func, target, words):
73
+ matches = []
74
+ for w in words:
75
+ try:
76
+ if func(w) == target:
77
+ matches.append(w)
78
+ except:
79
+ pass
80
+ return matches
81
 
 
 
82
 
83
+ # -----------------------------
84
+ # MAIN ANALYSIS
85
+ # -----------------------------
 
 
 
 
 
 
86
 
87
+ def analyze(hash_value, wordlist_text, charset_mode):
88
 
89
+ wordlist = []
90
 
91
+ if wordlist_text.strip():
92
+ wordlist = wordlist_text.splitlines()
93
+ else:
94
+ # default mini CTF wordlist
95
+ wordlist = [
96
+ "admin", "password", "root", "test", "user",
97
+ "login", "guest", "1234", "12345", "qwerty"
98
+ ]
99
 
100
+ detected = detect(hash_value)
101
 
102
  results = []
103
+ matches = {}
104
 
105
  # -------------------------
106
+ # JAVA HASH
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  # -------------------------
108
 
109
+ if "java_hash" in detected:
110
+ m = try_match(java_hash, hash_value, wordlist)
111
+ if m:
112
+ matches["Java hashCode"] = m
 
113
 
114
  # -------------------------
115
  # CRC32
116
  # -------------------------
117
 
118
+ if "crc32" in detected:
119
+ m = try_match(crc32_hash, hash_value, wordlist)
120
+ if m:
121
+ matches["CRC32"] = m
 
 
 
 
 
 
 
122
 
123
  # -------------------------
124
  # ADLER32
125
  # -------------------------
126
 
127
+ if "adler32" in detected:
128
+ m = try_match(adler32_hash, hash_value, wordlist)
129
+ if m:
130
+ matches["Adler32"] = m
 
 
 
 
 
 
 
131
 
132
  # -------------------------
133
  # DJB2
134
  # -------------------------
135
 
136
+ if "djb2" in detected:
137
+ m = try_match(djb2, hash_value, wordlist)
138
+ if m:
139
+ matches["DJB2"] = m
 
140
 
141
  # -------------------------
142
  # FNV1A
143
  # -------------------------
144
 
145
+ if "fnv1a" in detected:
146
+ m = try_match(fnv1a, hash_value, wordlist)
147
+ if m:
148
+ matches["FNV1a"] = m
 
149
 
150
  # -------------------------
151
+ # OUTPUT BUILDING
 
 
 
 
 
 
 
 
 
 
 
 
152
  # -------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
+ if not detected:
155
+ detected = ["Unknown / Non-integer hash"]
 
156
 
157
+ if not matches:
158
+ match_text = "No matches found (try larger wordlist)"
159
+ else:
160
+ match_text = "\n".join(
161
+ f"{k}: {v[:10]}" for k, v in matches.items()
162
+ )
163
 
164
  return (
165
+ "\n".join(detected),
166
+ match_text
167
  )
168
 
169
 
170
+ # -----------------------------
171
  # UI
172
+ # -----------------------------
173
 
174
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
175
 
176
+ gr.Markdown("# 🔍 CTF Hash Reverser (TryHackMe Tool)")
177
+ gr.Markdown(
178
+ "Detects and attempts to reverse common CTF-style hashes including Java hashCode, CRC32, and custom integer hashes."
179
+ )
 
 
 
 
 
 
 
 
 
 
 
180
 
181
+ hash_input = gr.Textbox(
182
+ label="Hash / Integer Value",
183
+ lines=3
184
  )
185
 
186
+ wordlist_input = gr.Textbox(
187
+ label="Wordlist (optional, one per line)",
188
+ lines=10,
189
+ placeholder="admin\npassword\nroot\nuser..."
190
  )
191
 
192
+ run_btn = gr.Button("Analyze & Crack")
193
+
194
+ detected_out = gr.Textbox(label="Detected Algorithms")
195
+ result_out = gr.Textbox(label="Recovered Matches")
196
+
197
+ run_btn.click(
198
  analyze,
199
+ inputs=[hash_input, wordlist_input, gr.Radio],
200
+ outputs=[detected_out, result_out]
201
  )
202
 
203
  demo.launch()