Nel password cracking, una delle tecniche più utilizzate è l’attacco Brute Force (letteralmente “Forza Bruta”). In un attacco brute force, un attaccante prova tutte le possibili combinazioni di password fino a trovare quella corretta. Ad esempio, se la password è lunga 8 caratteri e l’attaccante usa un dataset di 62 caratteri (26 lettere maiuscole + 26 minuscole + 10 numeri), il numero totale di permutazioni è:
62^(8) = 218.340.105.584.896 (218 trilioni)
Un metodo basato perlopiù sulla fortuna che non ad un metodo vero e proprio; occorre quindi concentrare l’attacco in modo da ridurre notevolmente il numero di combinazioni ad esempio utilizzando un Attacco Lessicale.
Negli attacchi lessicali, si provano permutazioni di parole comuni o frasi derivanti da liste di password comuni. L’uso di permutazioni in questo contesto implica la generazione di varianti di password comuni che possono portare a brevi tempi di cracking.
La Permutazione
Nel calcolo combinatorio, una permutazione rappresenta la riorganizzazione di tutti i membri (quindi il numero di oggetti è uguale al numero di posti ) di un insieme in qualsiasi ordine o sequenza, nel quale conta l’ordine in cui i membri si dispongono.
Ad esempio, per l’insieme ABC, le possibili permutazioni sarebbero: ABC, ACB, BAC, BCA, CAB e CBA.
Lo script Python allegato di seguito, partendo da una parola (o elenco di parole) effettua tutte le trasliterazioni possibili evitando i risultati ridondanti (nel caso che la parola in input dovesse avere uno o più caratteri duplicati)
ad esempio, per l’insieme ABAB, si otterrebbe: ABAB, ABBA, AABB, BAAB, BABA, BBAA oppure per l’insieme AAAB, si otterrebbe: AAAAB, AAABA, AABAA, ABAAA, BAAAA
# -----------------------------------------------------------------------------
# - Script file name : perm.py
# - Author : Nicola Montemurro
# - DNS administrator: Nicola Montemurro - Tel. xxx, Mobile: xxx
# - Create : 21.07.2025
# - Last Update : 24.07.2025
# - Description :
# - Position : /usr/local/script/python
# - note : NON modificare senza AUTORIZZAZIONE dell'AMMINISTRATORE
# ----------------------------------------------------------------------------
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import itertools
import argparse
import gc
import sys
import os
def do_calculation(str_word, bucket_size, chars):
#Genera tutte le permutation uniche della string (o della sua parte) e le restituisce progressivamente.
#Rilascia le permutation periodicamente dal bucket per evitare troppa memoria accumulata.
str_word = str_word[:chars] # Limita la string alla lunghezza specificata
gc.enable()
permutation = itertools.permutations(str_word)
combination = set() # Utilizziamo un set per evitare duplicazioni
counter = 0
bucket = []
for p in permutation:
str_word = ''.join(p)
if str_word not in combination:
combination.add(str_word)
bucket.append(str_word)
counter += 1
# Rilascia il bucket di permutation ogni bucket_size permutation
if counter >= bucket_size:
for item in bucket:
yield item # Restituisci una permutazione alla volta
bucket.clear() # Pulisce il bucket
counter = 0 # Reset del contatore
#sleep(0.02) # Permette di gestire altre attività (DEBUG)
# destroy objects
del combination, bucket, counter
# freeing memory
gc.collect()
# recreate objects
combination = set()
counter = 0
bucket = []
# Restituisci le restanti permutation se ci sono
for item in bucket:
yield item
def main():
def avaluate_chars(user_input):
# Controllo della lunghezza massima per la word
if args.chars:
if args.chars > len(user_input):
nchars = args.chars
nchars = args.chars
else:
nchars = len(user_input) # Se non viene specificata la lunghezza, utilizza tutta la word
return nchars
def avaluate_lenght(user_input):
# Controllo della lunghezza massima per la word
if args.lenght:
if args.lenght > len(user_input):
wlen = args.lenght
wlen = args.lenght
else:
wlen = len(user_input) # Se non viene specificata la lunghezza, utilizza tutta la word
return wlen
# Impostazione di argparse per gestire gli argomenti
parser = argparse.ArgumentParser(description="Genera tutte le permutazioni di una parola.")
parser.add_argument("-w", "--word", type=str, help="Parola dalla quale generare le permutazioni.")
parser.add_argument("-c", "--chars", type=int, help="Assume solo gli n caratteri della parola da permutare")
parser.add_argument("-l", "--lenght", type=int, help="Limita il numero di caratteri (contando dal fondo) della parola permutata")
parser.add_argument("-f", "--filename", type=str, help="Nome file contenente l'elenco di parole da cui generare le permutazioni.'")
parser.add_argument("-b", "--bucket", type=int, default=1000000, help="Set di permutazioni da generare e rilasciare. (Default: 1000000)")
args = parser.parse_args()
data = None
# Check if filename is provided
if args.filename:
# Ensure filename exists
if not os.path.isfile(args.filename):
print(f"Error: File '{args.filename}' not found or is not a valid file.")
return # Exit gracefully
try:
# Try to open and read the file
with open(args.filename, 'r') as file:
for line in file:
data = line.strip()
max_chars=avaluate_chars(data)
for word in do_calculation(data, args.bucket, max_chars):
max_len=avaluate_lenght(data)
print(word[-max_len:])
#print(word)
except IOError as e:
print(f"Error reading file '{args.filename}': {e}")
return # Exit gracefully
elif args.word:
data = args.word.strip()
max_chars=avaluate_chars(data)
for word in do_calculation(data, args.bucket, max_chars):
max_len=avaluate_lenght(data)
print(word[-max_len:])
#print(word)
# Check if input is from a pipeline
elif not sys.stdin.isatty():
#print("Input is from a pipeline.")
try:
for line in sys.stdin:
data = line.strip()
max_chars=avaluate_chars(data)
#print(f'{data}')
for word in do_calculation(data, args.bucket, max_chars):
max_len=avaluate_lenght(data)
print(word[-max_len:])
#print(word)
except Exception as e:
print(f"Error reading from pipeline: {e}")
return # Exit gracefully
# Check if both input sources are empty
# if data is None:
#print("No input provided. Please specify a filename or pipe input.")
#return # Exit gracefully
if __name__ == '__main__':
main()
In Conclusione
Le permutazioni sono un metodo utilizzato frequentemente durante la generazione delle password, di conseguenza l’utilizzo dello stesso per il password cracking potrebbe rappresentare una soluzione ottimale.