Хэш Вконтакте

Заинтересовался темой расшифровки хэша, который Контакт использует для противодействия CSRF-атакам
Если посмотреть POST-запросы, то легко увидеть параметр hash, состоящий из 18 символов.
Какие у меня догадки на этот счет

Хэш скорее всего md5 (32 символа), который потом еще раз шифруется и обрезается до 18 символов.
Несколько лет назад Контакт использовал такую схему.
1) Генерировался 25 символьный хэш (скорее всего из 32 символьного md5-хэша). Этот хэш был виден в коде html-страницы.
2) При отправке запроса он прогонялся через javascript-функцию

Данная функция просто режет хэш на части и переставляет местами символы. В итоге хэш урезается до 18 символов.

window.init_dec_hash = function() {
  window.decoded_hashes = {};
  var dec_hash = function(hash) {
    (function(_){window.decoded_hashes[_]=(function(__){var ___=ge?'':'___';for(____=0;____<__.length;++____)___+=__.charAt(__.length-____-1);return geByClass?___:'___';})(_.substr(_.length-5)+_.substr(4,_.length-12));})(hash);
  }
  window.decodehash = function(hash) {
    dec_hash(hash);
    return window.decoded_hashes[hash];
  }
}

Вот так это выглядит на php

<?php
function decodehash($a){
	$c = '';
	$b = substr($a,strlen($a)-5).substr($a,4,strlen($a)-12);
	for ($d=0;$d<strlen($b);++$d) {
		$c.=$b{(strlen($b)-$d-1)};
	}
	return $c;
}
?>

На сервере md5-хэш тоже приводится к виду 18 символов (через функцию выше) и сравнивается с хэшем, который пришел в запросе.

Не понятно зачем так было сделано. Потому что md5-хэш тоже защищал от атак. К тому же Контакт выложил в открытый доступ алгоритм повторного шифрования (javascript-функция).

Напомню, что это было в 2010 году. Сейчас хэш 18 символов формируется сразу на сервере и он же отправляется в запросе. Но я уверен, что изначально генерируется 32 символьный md5-хэш, который еще раз шифруется до 18 символов (а возможно даже 2 раза шифруется).

Как формируется md5-хэш?
Скорее всего через параметры запроса. Если открыть документацию по API, то там будет такая штука.

Параметр sig равен md5 от конкатенации следующих строк: 

mid – id текущего пользователя, полученного ранее при авторизации
пар "parameter_name=parameter_value", расположенных в порядке возрастания имени параметра (по алфавиту) за исключением параметра sid
секрета сессии secret, который был получен ранее при авторизации
sig = md5(midname1=value1name2=value2secret)

Например, md5(12345api_id=1countOfVotes=10 0500format=JSONmethod =getFreeVotesv=3.096htw82)

Однако, на практике всё не так просто.
Если посмотреть запрос на вступление в группу и запрос на выход из группы
POST http://vk.com/al_groups.php
act=enter
al=1
gid=11111
hash=c65a06b2c253161c1a

То логично предположить (если брать за образец код API), что md5-хэш формируется примерно так
md5('12345act=enteral=1gid=11111'); // для вступления в группу
md5('12345act=leaveal=1gid=11111'); // для выхода из группы

или так

md5('mid=12345&act=enter&al=1&gid=11111'); // для вступления в группу
md5('mid=12345&act=leave&al=1&gid=11111'); // для выхода из группы

или так
md5('12345method=groups.entergid=11111') // для вступления в группу
md5('12345method=groups.leavegid=11111'); // для выхода из группы

12345 — id пользователя
11111 — id группы

Но в реальности, хэш для вступления и для выхода одинаковый! Значит параметр act (enter || leave) не используется в формировании хэша. Более того, хэш для «рассказать друзьям о группе» совпадает с хэшем для вступления и хэшем для выхода.

Понятно, что параметры id пользователя и id группы используются в формировании хэша, но что еще там используется это не известно. Скорее всего еще используется какой-то ключ для «подсолки» хэша. В документации по API можно увидеть ключ приложения.

Но даже, если мы узнаем как формируется md5-хэш, то не ясно каким алгоритмом он потом урезается до 18 символов. Хотя если бы точно знать md5, то перебором можно было бы попробовать найти этот алгоритм. Скорее всего используется обычная перестановка символов в линейном порядке (см. выше).

Я вообще думаю, что 32-символьный хэш урезается по старому алгоритму 2 раза (см. выше php-функция decodehash). При каждом прогоне строка уменьшается на 7 символов (32->25->18).
Типа decodehash(decodehash(md5('mid=12345gid=11111')))

Почему по старому алгоритму? Потому что все программисты жуткие раздолбаи и скорее всего алгоритм не изменился.

Почему я решил, что всё берется из 32-символьного md5, а не из sha или другого метода шифрования? Во-первых, md5 — это латиница плюс цифры, что совпадает с символами хэшей. Во-вторых, Контакт изначально использовал md5 для шифрования паролей в куках. В-третьих, md5 используется в API Контакта.

Короче, всю ночь ломал голову и в итоге оставил это занятие. Но если у кого есть рабочие идеи по расшифровке, то готов заплатить хорошие деньги:)

#1

Насчет расшифровки лучше и не пытаться т.к. этот md5 100% подсоленный секретным "ключом", который хранится на сервере.

По поводу "Не понятно зачем так было сделано. Потому что md5-хэш тоже защищал от атак. К тому же Контакт выложил в открытый доступ алгоритм повторного шифрования (javascript-функция)." это очень интересная тема. Это одна из защит от спамеров - если ты пишешь спам-бота, то тебе придется либо разбирать обфусцированный JS код вручную, либо встраивать JS интерпретатор в бота. Как сейчас не знаю, но раньше этот JS код менялся время от времени.

Сергей, 3.06.2012 - 00:54
#2

Значит, бл*, идея такая! Правда, один момент - памяти на компе дохренища получится. Возможно что не хватит её, что наиболее вероятно. Итак, значит: 1) создать генератор простых паролей (Я, например, смог на PERL перебрать все комбинации от 2 до 6 символов. На 7 у меня не хватает места.). 2) Создать скрипт, который использует список паролей из словаря и переделывает в md5-хэш; а затем после обработки данных программа создает словарь (как базу данных) и в каждой строке прописываются значения:
pass: пароль pass_md5: пароль_мд5.

Ну, а если контакт использует подсолку на md5, то лучше всего во втором скрипте на perl - создать скрипт, который был бы идентичен js скрипту. И база данных, записывалась бы так:
pass: пароль pass_md5: пароль_мд5 pass_md5sol: пароль мд5соль.

Генератор простых паролей можно реальзовать при помощи цикла while на языке perl:
#!usr/bin/perl
open(CFG, "alfabet.txt");
open(PASS, ">>brut1.txt");
while ($p = )
{
print PASS "0$p";
}
close CFG;
print PASS "\n";
close PASS;
open(CFG, "alfabet.txt");
open(PASS, ">>brut1.txt");
while ($p = )
{
print PASS "1$p";
}
close CFG;
print PASS "\n";
close PASS;
.
.
.
И так далее. Надо обратить внимание, что таких одинаковых фрагментов кода в одном файле с расширением pl 36 штук. Где строка print PASS "1$p" - там надо ставить перед переменной один символ. Раскладка клавиатуры идет от 0 до 9 по цифрам, а потом клавиатура маленькими буквами английскими.
Также стоит напомнить, что создается файл alfabet.txt и там в построчно прописываются в нем алфавит:
0
1
2
3
...
и так далее. Данная прога создаст двухзначный код. Чтобы увеличить его на на один символ, надо создать еще одну такую же программу, но только данные берутся со словаря двухзначного пароля, чтобы создать трехзначный. Получится так:
#!usr/bin/perl
open(CFG, "brut1.txt");
open(PASS, ">>brut2.txt");
while ($p = )
{
print PASS "0$p";
}
close CFG;
print PASS "\n";
close PASS;
... И так далее.
Программа та же, но берет данные с brut1.txt и создает словарь brut2.txt. Вообщем, надеюсь смысл понятен.
На первом этапе создание словарей. А далее, сбабацать свой скрипт по переделке в мд5. Я возьму готовый с интернета скрипт, но его лучше под себя переделать. Щас я не буду голову ломать над этим. Скрипт, который переделывает с с обычного пароля делает в мд5 и ищет соотвествие, например:
#!/usr/bin/perl -w

use strict;
use Digest::MD5 qw(md5_hex);

my $correct_pass = "bb456cfc65785beda9ec0c034e2a54ae";

print "Введите пароль:\n";

my $pass = ;
chomp($pass); # обрезаем \n

if ($correct_pass eq md5_hex($pass)) {
print "Добро пожаловать!\n";
} else {
print "Пошел нафиг!\n";
}

exit;

Это уже не я придумал, ну а далее урезать его до 18 символов.

Алексей, 16.01.2015 - 23:35
#3

Ошибочка: в цикле while переменная $p равна дескриптору CFG.

Алексей, 16.01.2015 - 23:45
#4

#!/usr/bin/perl -w _input name="password

Тест, 29.01.2016 - 13:48
Оставить комментарий