Skip to content

Instantly share code, notes, and snippets.

@danieljs777
Created September 15, 2026 19:15
Show Gist options
  • Select an option

  • Save danieljs777/42e1c101c033b21ff73b24fcbe7eb0a5 to your computer and use it in GitHub Desktop.

Select an option

Save danieljs777/42e1c101c033b21ff73b24fcbe7eb0a5 to your computer and use it in GitHub Desktop.
PFX Password Brute-Force / Sanitization Tester A Bash script to recover a PKCS#12 (.pfx) certificate password when a password manager or certificate-issuing app has silently stripped special characters (e.g. ] & | ! } $) during copy/transfer. Given the original password, it generates and tests sanitized variations against the PFX using openssl p…
#!/usr/bin/env bash
#
# bruteforce-pfx-password.sh
# Tests possibly-sanitized variations of a password against a PFX file.
#
# Focus: special characters that certificate-issuing apps tend to strip or
# alter, especially the shell metacharacters ] & | ! } $
#
# Usage: ./bruteforce-pfx-password.sh certificate.pfx
#
set -u
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
PFX="${1:?Usage: $0 file.pfx}"
[[ -f "$PFX" ]] || { echo "File not found: $PFX"; exit 1; }
# Special characters suspected of being stripped by the app.
# Adjust this list if you know which ones were in the password.
SPECIALS=(']' '&' '|' '!' '}' '$' '{' '[' '#' '%' '^' '*' '(' ')' '@' '~' '`' '\' '"' "'" ' ')
# Limit of combinations for removal of MULTIPLE characters (avoids explosion).
# Given N characters present in the password, we test removals of all
# subsets up to this size.
MAX_REMOVALS=4
# ---------------------------------------------------------------------------
# Read the password (no echo on screen)
# ---------------------------------------------------------------------------
read -rsp "Original password (from the vault): " ORIGINAL
echo
echo "Original password length: ${#ORIGINAL} bytes"
echo
# ---------------------------------------------------------------------------
# Function: test a password against the PFX
# Returns 0 if the password opens the file.
# Tries with and without -legacy (OpenSSL 3.x needs -legacy for RC2/3DES).
# ---------------------------------------------------------------------------
test_password() {
local password="$1"
openssl pkcs12 -in "$PFX" -nokeys -passin "pass:$password" -legacy \
>/dev/null 2>&1 && return 0
openssl pkcs12 -in "$PFX" -nokeys -passin "pass:$password" \
>/dev/null 2>&1 && return 0
return 1
}
# ---------------------------------------------------------------------------
# Find out which special characters actually appear in the password
# (only makes sense to generate removals for those)
# ---------------------------------------------------------------------------
PRESENT=()
for c in "${SPECIALS[@]}"; do
if [[ "$ORIGINAL" == *"$c"* ]]; then
PRESENT+=("$c")
fi
done
echo "Special characters found in the password: ${#PRESENT[@]}"
if [[ ${#PRESENT[@]} -gt 0 ]]; then
printf ' '
for c in "${PRESENT[@]}"; do printf '%s ' "$c"; done
echo
fi
echo
# ---------------------------------------------------------------------------
# Remove a set of characters from the password (all occurrences)
# ---------------------------------------------------------------------------
remove_chars() {
local s="$1"; shift
local c
for c in "$@"; do
s="${s//"$c"/}"
done
printf '%s' "$s"
}
# ---------------------------------------------------------------------------
# Generate all subsets of PRESENT up to size MAX_REMOVALS
# and produce the resulting password from removing each subset.
# Also includes common "structural" variations.
# ---------------------------------------------------------------------------
declare -A SEEN
CANDIDATES_FILE="$(mktemp)"
trap 'rm -f "$CANDIDATES_FILE"' EXIT
emit() {
local candidate="$1"
if [[ -z "${SEEN[$candidate]+x}" ]]; then
SEEN[$candidate]=1
printf '%s\n' "$candidate" >> "$CANDIDATES_FILE"
fi
}
# 1) The original password, first of all
emit "$ORIGINAL"
# 2) Frequent structural variations
emit "${ORIGINAL//[^[:alnum:]]/}" # letters and numbers only
emit "${ORIGINAL// /}" # no spaces
emit "${ORIGINAL%%\$*}" # everything before the first $
emit "$(printf '%s' "$ORIGINAL" | tr -cd '[:print:]')" # remove non-printable
emit "$(printf '%s' "$ORIGINAL" | tr -cd '[:alnum:]!@#%^&*()_+=-')" # "safe" set
# 3) Removal of subsets of the present characters (combinations)
N=${#PRESENT[@]}
if [[ $N -gt 0 ]]; then
# Iterate over bit masks from 1 to 2^N - 1
total=$(( (1 << N) - 1 ))
for (( mask=1; mask<=total; mask++ )); do
# Count set bits; skip if it exceeds MAX_REMOVALS
bits=0
for (( b=0; b<N; b++ )); do
(( (mask >> b) & 1 )) && (( bits++ ))
done
(( bits > MAX_REMOVALS )) && continue
subset=()
for (( b=0; b<N; b++ )); do
(( (mask >> b) & 1 )) && subset+=("${PRESENT[$b]}")
done
candidate="$(remove_chars "$ORIGINAL" "${subset[@]}")"
emit "$candidate"
done
fi
TOTAL_CANDIDATES=$(wc -l < "$CANDIDATES_FILE")
echo "Total candidates generated: $TOTAL_CANDIDATES"
echo "Testing..."
echo
# ---------------------------------------------------------------------------
# Test loop
# ---------------------------------------------------------------------------
FOUND=""
i=0
while IFS= read -r candidate; do
(( i++ ))
printf '\r[%d/%d] testing...' "$i" "$TOTAL_CANDIDATES"
if test_password "$candidate"; then
FOUND="$candidate"
break
fi
done < "$CANDIDATES_FILE"
echo
echo
# ---------------------------------------------------------------------------
# Result
# ---------------------------------------------------------------------------
if [[ -n "$FOUND" ]]; then
echo "✅ Valid password found!"
echo
echo " Password : »${FOUND}«"
echo " Bytes : ${#FOUND}"
echo
echo " Password hex (for verification):"
printf ' '
printf '%s' "$FOUND" | xxd -p | tr -d '\n'
echo
echo
echo " Difference from the original:"
diff <(printf '%s' "$ORIGINAL" | xxd) <(printf '%s' "$FOUND" | xxd) \
| sed 's/^/ /' || true
else
echo "❌ No variation worked (tested $TOTAL_CANDIDATES)."
echo
echo " Suggested next steps:"
echo " - Increase MAX_REMOVALS (careful: grows exponentially)."
echo " - Check Unicode normalization (NFC/NFD) if the password has accents."
echo " - Confirm the PFX opens in OpenSSL 3.x with -legacy."
echo " - If nothing works, revoke and reissue the certificate."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment