Полное руководство по John the Ripper. Ч.6: брут-форс нестандартных хешей


Оглавление

1. Знакомство и установка John the Ripper

2. Утилиты для извлечения хешей

3. Как запустить взлом паролей в John the Ripper (как указать маски, словари, хеши, форматы, режимы)

4. Практика и примеры использования John the Ripper

5. Атака на основе правил

6. Брут-форс нестандартных хешей

6.1 Взлом итерированных, солёных и произвольных хешей на основе MD5, SHA1 и прочих сырых хешей

6.2 Виды хешей

6.3 Dynamic в John the Ripper

6.4 Синтаксис форматов режима dynamic

6.5 Примеры использования настраиваемых форматов dynamic в john

6.6 Константы и соли

6.7 Как указать пользовательский формат хеша dynamic в командной строке

6.8 Как правильно записать хеш с солью и именем пользователя для John the Ripper

6.9 Встроенные форматы dynamic

6.10 Как сохранить пользовательский формат хеша dynamic в конфигурационном файле

6.11 Как записывать соли со специальными символами

7. Johnny — графический интерфейс для John the Ripper

8. 

9. 



Взлом итерированных, солёных и произвольных хешей на основе MD5, SHA1 и прочих сырых хешей

John the Ripper и Hashcat поддерживают большое количество хешей для брут-форса паролей. Список поддерживаемых в John the Ripper хешей можно посмотреть командой:

john --list=formats

Чтобы посмотреть поддерживаемые хеши в Hashcat вы можете перейди на страницу https://kali.tools/?p=578 или обратиться к справке программы:

hashcat -h

Списки поддерживаемых хешей внушительный у обеих программ.

Виды хешей

Хеши можно разделить на следующие группы:

  • Сырые (md2, md4, md5, sha1, sha224, sha256, sha384, sha512, tiger, sha3_224, sha3_256, sha3_384, sha3_512, keccak_256, keccak_512, ripemd128, ripemd160, ripemd256, ripemd320, whirlpool, gost, skein224, skein256, skein384, skein512, panama, haval_128_3, haval_128_4, haval_128_5, haval_160_3, haval_160_4, haval_160_5, haval_192_3, haval_192_4, haval_192_5, haval_256_3, haval_256_4, haval_256_5). Это самостоятельные алгоритмы хеширования, вычисления контрольных сумм
  • Солёные хеши. Основываются на сыром хеше, но к строке пароля добавляется соль, например, md5($pass.$salt)
  • Итерированные. Также основываются на сырых хешах, но результат хеширования затем вновь подвергается хешированию — это может происходить много раз. Пример: md5($salt.sha1($salt.$pass))

Кроме этих основных групп, можно разделить хеши по области применения:

  • Аутентификация
  • Сетевые протоколы
  • Операционные системы
  • Сервера баз данных
  • Сервера FTP, HTTP, SMTP, LDAP
  • Enterprise Application Software (EAS)
  • Полнодисковое шифрование
  • Документы
  • Менеджеры паролей
  • Архивы
  • Веб-приложения (форумы, CMS, E-Commerce)

В этих группах какие-то хеши являются самостоятельными, то есть они рассчитываются по собственным алгоритмам), но также довольно часто, особенно в веб-приложениях, операционных системах, хранящих пароли в хешированном виде, применяются солёные и итерированные хеши, которые основаны на сырых хешах, например:

  • sha1($s.sha1($s.sha1($p)))
  • sha1($s.sha1($p))
  • sha256(sha256($p).$s)

Если это популярное приложение, то поддержка его типа хеша обычно добавляется в John the Ripper и Hashcat и нам, на самом деле, не нужно знать, по какому именно алгоритму рассчитывается хеш.

Но представьте ситуацию, вы получили хеш от узкоспециальной программы, разобрались, что хеш вычисляется, например, по следующему алгоритму: md5(md5(md5($p).$s).$s2). Но поддержка этого алгоритма (этого типа хеша) отсутствует и в John the Ripper, и в Hashcat, то что делать в данной ситуации?

Ответу на этот вопрос как раз и посвящена данная часть — мы научимся взламывать хеши, вычисленные с использованием сырых, солёных и итерированных алгоритмов.

Смотрите также: Хеши: определение типа, подсчёт контрольных сумм, нестандартные и итерированные хеши

Dynamic в John the Ripper

Динамический «самостоятельно описывающий» формат (a.k.a. Динамический компилятор выражений (dynamic expression compiler)). Это режим в котором пользователь без использования программирования описывает формулу, по которой хешируются пароли.

Допустим, мы добыли хеш пароля:

838c9416a8d094b7e660a0f3b12e3e543c71f7f4

И его соль:

mial

С помощью обратной инженерии выяснено, что хеш высчитывается по следующей формуле:

sha1(md5(sha512($p.$s).$p).$s)

Нам нужно записать хеш в файл в следующем формате:


ХЕШ$СОЛЬ

То есть хеш и соль разделяются знаком доллара.

Создаём файл hash.txt и записываем:

838c9416a8d094b7e660a0f3b12e3e543c71f7f4$mial

Создадим крошечный словарик, назовём его wordlist.txt и запишем в него:

123
hackware
123567890
123456
111111111111111111

Команда для запуска взлома по словарю:

john -form=dynamic='sha1(md5(sha512($p.$s).$p).$s)' --wordlist=wordlist.txt hash.txt

Или по маске:

john -form=dynamic='sha1(md5(sha512($p.$s).$p).$s)' --mask='?l?l?l?l?l?l?l?l' hash.txt

Пароль успешно взломан, это «hackware»:

В данном примере мы использовали нашу собственную формулу, по которой вычислялся хеш, но в John the Ripper много встроенных динамичных форматов. Более того, вы можете записать ваш динамический формат в конфигурационном файле и использовать его по присвоенному имени, вместо того, чтобы каждый раз вводить формулу. Сначала мы познакомимся со встроенными форматами, а затем вернёмся к синтаксису динамических форматов, которые вы можете составить сами.

Хотя нет, чтобы понимать обозначения встроенных форматов, нужно знать синтаксис — поэтому начнём всё-таки с синтаксиса написания пользовательских форматов dynamic.

Синтаксис форматов режима dynamic

Выражение ДОЛЖНО быть единичным выражением вычисления крипто хеша. Это означает, что последним действием является вычисление хеша, но не нескольких хешей, объединённых друг с другом. То есть md5($p) это верно, а md5($p).md5($p) это НЕ верно.

Все соединения строк должны иметь между собой символ '.' (точки). Поэтому md5($p.$p) это верно, а md5($p$s) это неверно.

Переменные:

  • $p или $pass используется для кандидата в пароли
  • $s или $salt используются как константа 'соль'
  • $s2 используется для второй солёной константы
  • $u используется для id пользователя (который является первым полем во входном файле)
  • с $c1 до $c8. Эти переменные являются 'константами'. ПОМНИТЕ, они должны использоваться по порядку, то есть если у вас есть $c2, значит у вас уже должна быть $c1. Поэтому md5($s.$c1.$p.$c1),c1=x даёт нам md5($s."x".$p."x")

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

  • lc($u) для нижнего регистра имени пользователя (правильный нижний регистр Unicode)
  • uc($u) для верхнего регистра имени пользователя (опять же, правильный верхний регистр Unicode)
  • lc($p) и uc($p) предназначены для нижнего/верхнего регистра пароля.

ВАЖНО: Если uc($u) или lc($u) используются в выражении, тогда ВСЕ $u должны быть сделаны в одном ключе. Это также относится и к паролю. Поэтому md5($u.$p.$) это верно, а md5(uc($u).$p.$u) это неверно. Это ограничение динамического формата в целом.

При использовании констант они должны быть добавлены через запятую в конец выражения. ВАЖНО: если используются символы «:» (двоеточие) в константах, то их нужно записывать в шестнадцатеричной форме. Например: md5($c1.$p),c1=test_\x3a_test. Из этого получится md5("test_:_test".$p)


Проблемным символам будет посвящён раздел ниже. Сейчас же просто упомянем, что имеется утилита raw2dyna (входит в пакет John the Ripper). Для конвертации любой строки в шестнадцатеричную, используется опция -2h, например, следующая команда выведет шестнадцатеричную запись для двоеточия:

raw2dyna -2h=':'
$HEX$3a

Необязательно кодировать всю строку — можно кодировать отдельные символы, как это показано выше.

Эта же программа с помощью опции -2r может конвертировать шестнадцатеричную запись в сырые данные:

raw2dyna -2r='3a'

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

Группирование. Все выражения должны быть единичным «внешним» выражением, но внутри внешнего выражения, может быть множество сгруппированных данных. Функции начинаются с имени функции и используют ( и ) для группирования данных, присутствующих в хеше. Поэтому такие вещи как md5($p) или md5(md5(md5($s.$p))) или md5(md5($p).$s.md5($s.$p)) являются верными, поскольку они имеют единое внешнее (последнее) выражение и все необходимые символы для правильного синтаксиса.

У функций хеширования есть несколько «разновидностей», которые делают несколько разные вещи. Например:


  • md5(ВЫРАЖЕНИЕ)
  • MD5(ВЫРАЖЕНИЕ)
  • md5_raw(ВЫРАЖЕНИЕ)
  • md5_64(ВЫРАЖЕНИЕ)
  • md5_64c(ВЫРАЖЕНИЕ)

Вариант записи в нижнем регистре (такой как md5(…)) вернёт результаты в виде base16 числа, записанного в нижнем регистре. То есть md5("password") вернёт 5f4dcc3b5aa765d61d8327deb882cf99,

Вариант записи в верхнем регистре вернёт результаты в виде base16 числа, записанного в верхнем регистре. То есть MD5("password") вернёт 5F4DCC3B5AA765D61D8327DEB882CF99. Функция хеширования к которой добавлено _raw, возвращает просто «сырой» двоичный объект. То есть md5_raw("password") даст нам 16 байт, первым из которых будет '\0x5f', а затем ещё 15 других.

md5_64("password") вернёт mime base-64 результат, то есть X03MO1qnZdYdgyfeuILPmQ (это сырые байты хеша в кодировке base64)

md5_64c("password") возвращает строку crypt alphabet base64, для нашего примера является LorACpebNRMRUmTSi69DaE.

Обычно _64 и _64c используются в качестве внешней функции, информируя john о том, как «выглядит» тип входного хеша (т.е. хеши находятся в base64). То же самое и с верхним регистром. Если внешняя функция имеет верхний регистр, то будут действительны только шестнадцатеричные строки в верхнем регистре правильной длины.

Функции хеширования (каждая из которых имеет версию в нижнем регистре, верхнем регистре, а также с добавлением _raw, _64 и _64c):

  • md2
  • md4
  • md5
  • sha1
  • sha224
  • sha256
  • sha384
  • sha512
  • tiger
  • sha3_224
  • sha3_256
  • sha3_384
  • sha3_512
  • keccak_256
  • keccak_512
  • ripemd128
  • ripemd160
  • ripemd256
  • ripemd320
  • whirlpool
  • gost
  • skein224
  • skein256
  • skein384
  • skein512
  • panama
  • haval_128_3
  • haval_128_4
  • haval_128_5
  • haval_160_3
  • haval_160_4
  • haval_160_5
  • haval_192_3
  • haval_192_4
  • haval_192_5
  • haval_256_3
  • haval_256_4
  • haval_256_5

Эти функции можно смешивать практически любым способом. Поэтому хеш sha512(md5(panama($p).$s.ripmd128($s.$p))) совершенно верен с точки зрения синтаксиса.

Примеры использования настраиваемых форматов dynamic в john 

1. Хеш вычисляется как MD5 от пароля:

md5($p)

2. Хеш вычисляется как MD5 от пароля, а затем полученная строка хешируется ещё раз с помощью MD5:

md5(md5($p))

3. Хеш вычисляется как MD5 от пароля, а затем полученный хеш кодируется в Base64 и эта новая строка хешируется ещё раз с помощью MD5:

md5(md5_64($p))

4. К паролю добавляется соль, для полученной объединённой строки считается MD5 хеш:

md5($p.$s)

5. Пароль хешируется алгоритмом sha1:

sha1($p)

6. Пароль хешируется алгоритмом MD5, а затем полученная строка хешируется алгоритмом sha1:

sha1(md5($p))

7. Пароль объединяется с солью, полученная строка хешируется алгоритмом sha512, затем берётся соль, полученный хеш и пароль, и все они объединяются в одну строку, которая хешируется алгоритмом sha512:

sha512($s.sha512($p.$s).$p)

Константы и соли

Выше были упомянуты константы — их функции похожи на функцией солей, тогда для чего они нужны? В принципе, константа это и есть соль, но она передаётся в John the Ripper другим способом. Соль указывается вместе с хешем, а константа указывается в формуле (которая используется с опцией -form или хранится в конфигурационном файле).

Пример использования константы:

md5($c1.$p),c1=hackware

То есть в качестве константы следует использовать статичные, не меняющиеся данные. А соль индивидуальна для каждого пароля.

Как указать пользовательский формат хеша dynamic в командной строке

Пользовательский динамический формат указывается с опцией -form=dynamic='ВЫРАЖЕНИЕ'

Например:

-form=dynamic='sha1(md5(sha512($p.$s).$p).$s)'

Обратите внимание, что кавычки являются обязательными и должны использоваться именно одинарные кавычки!

Вы можете убедиться в этом сами — возьмите своё выражение, поместите в двойные кавычки и выведите его в терминал с помощью echo, например:

echo "sha1(md5(sha512($p.$s).$p).$s)"

От выражения осталось следующее:

sha1(md5(sha512(.).).)

То есть именно в таком виде его и увидела бы программа.

Как правильно записать хеш с солью и именем пользователя для John the Ripper

Общая формула записи хешей для dynamic следующая:

userID:$dynamic_#$base_16_hash[$salt]

Где:

  • userID — имя пользователя (если для вычисления хеша оно необходимо)
  • $dynamic_# (номер встроенного динамического формата — о них будет ниже)
  • $base_16_hash — сам хеш
  • $salt — соль

Кроме хеша, все остальные данные для большинства хешей не требуются.

Пример хеша с солью (соль отделена от хеша символом $):

699fce08bf085fb80f5ae1f240cbbe720aa62278$jxV9tvClmWz0

Пример хеша с именем пользователя:

user:1c3470194afdc84b90a0781c5e4462fc

Встроенные форматы dynamic

Чтобы просмотреть список встроенных форматов введите команду:

john --list=subformats

Пример первых строк:

Format = dynamic_0 type = dynamic_0: md5($p) (raw-md5)
Format = dynamic_1 type = dynamic_1: md5($p.$s) (joomla)
Format = dynamic_2 type = dynamic_2: md5(md5($p)) (e107)
Format = dynamic_3 type = dynamic_3: md5(md5(md5($p)))
Format = dynamic_4 type = dynamic_4: md5($s.$p) (OSC)
Format = dynamic_5 type = dynamic_5: md5($s.$p.$s)
Format = dynamic_6 type = dynamic_6: md5(md5($p).$s)
Format = dynamic_8 type = dynamic_8: md5(md5($s).$p)

Строки dynamic_* это имена форматов, их нужно использовать при выборе того или иного формата. Также вы можете увидеть формулы по которым вычисляется каждый формат. Для некоторых форматов имеется краткий комментарий.

Вы можете обратить внимание, что выведены строки с двумя разными началами:

  • "Format = …"
  • "UserFormat = …"

Они отличаются тем, что Format — это встроенные в John the Ripper форматы, а UserFormat, в принципе, это тоже встроенные форматы, но от сообщества. В файле dynamic.conf (может быть расположен по пути /usr/share/john/dynamic.conf) вы можете увидеть и добавить свои собственные UserFormat.

Для Format используются имена вида dynamic_# где # это число. John резервирует числа от dynamic_0 до dynamic_999 для «встроенных» форматов. Ещё не все из них определены.

Для UserFormat также используются имена вида dynamic_# где # это число от 1001 до 9999. Опять же, ещё не все из этих форматов определены.

Форматы dynamic запускаются как и обычные форматы хешей, то есть они указываются опцией —format, в качестве имени нужно указать dynamic_#, заменив # на номер нужного вам формата, например:

john --test --format=dynamic_1030

Как сохранить пользовательский формат хеша dynamic в конфигурационном файле

Свои собственные форматы dynamic можно записать в файлы john.conf (john.ini), dynamic.conf (включён в john.conf) или john.local.conf.

Недостаточно просто записать формулу — разработан язык примитивов, который довольно близок уже к программированию.

Документацию вы найдёте в файлах:

  • ./doc/DYNAMIC
  • ./doc/DYNAMIC_SCRIPTING

Как записывать соли со специальными символами

Соли могут содержать проблематичные символы. Некоторыми из них могут быть такие символы как: : \r \n \ NULL и так далее.

Символ : (двоеточие) используется в JtR как разделитель полей. Если он существует в соли, то он разобьёт соль на несколько полей (что неправильно).

Символ возврата каретки или перевод строки приведёт к разбиению строчки и JtR прочитает её неправильно.

NULL байты это проблема в любой C программе, использующей нормальные «строковые» функции.

Символ \ используется для экранирования символов внутри dynamic и может стать причиной проблем.

Ещё одна найденная проблема: если соль заканчивается на ' ' или '\t' (пробел или Tab), то они удаляются в процессе подготовки и очистки строк (программа не ожидает, что конечный пробел или табуляция могут быть частью строки).

Из-за всех этих проблем, в dynamic была добавлена поддержка шестнадцатеричной записи соли.

$dynamic_#$ХЕШ$HEX$ШЕСТНАДЦАТЕРИЧНЫЙ_БАЙТЫ_СОЛИ

В этом формате если соль была 1234, тогда эквивалентным значением будет $HEX$31323334.

Это позволяет кодировать и использовать соли вроде таких:

$\x0:\r\nBadSalt

Даже такую соль МОЖНО использовать, после кодирования она пример следующий вид:

$HEX$003a0a0d42616453616c74

Кодировать символы и конвертировать соли можно с помощью уже упомянутой программы raw2dyna. Она позволяет делать различные модификации с хешами — посмотрите её справку.

Самое простое использование показано выше — конвертировать отдельные символы:

raw2dyna -2h='СТРОКА'

Рекомендуется Вам:

One Comment to Полное руководство по John the Ripper. Ч.6: брут-форс нестандартных хешей

  1. Виктор:

    Большое спасибо за познавательную статью!

    Применил эту функцию для брутфорса CHAP challenge из захваченного трафика установления PPPoE-сессии.
    Захватил и подобрал захэшированный пароль PPPoE (CHAP MD5), который передаёт мой роутер в момент установления PPPoE-сессии.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *