И еще немного про уязвимости авторизации
Недавно я писал о трех видах уязвимостей авторизации:
- роль пользователя находится под его контролем;
- неполный список привилегий пользователя (в случае, если авторизация построена на черных списках);
- отсутствие обращения к механизму авторизации на пути выполнения, ведущем к защищенной функциональности.
Давайте рассмотрим вот такой код:
conn = sqlite3.connect(DATABASE)
try:
c = conn.execute('select * from users where uid=?', (uid,))
result = c.fetchone()
if not result:
return self.send_redirect(S['nonexist'])
_, user, is_admin, is_active = result
if not is_active:
return self.send_redirect(S['inactive'] % user)
if not is_admin:
self.send_redirect(S['admin'] % user)
self.process_command(conn, user, *cmd.split(' '))
finally:
conn.close()
Данный фрагмент реализует проверку прав пользователя перед доступом к защищеной функциональности. По задумке, если пользователь не является администратором, он должен быть перенаправлен на страницу с соответствующей ошибкой.
Однако, механизм авторизации реализован в данном коде некорректно: функция send_redirect только устанавливает код HTTP-ответа, но не прекращает выполнение текущей функции! Таким образом, строка
self.process_command(conn, user, *cmd.split(' '))
будет выполнена несмотря на то, что пользователь веб-приложения получит редирект и в итоге увидит перед собой страницу с ошибкой.
Полагаю, такие ошибки нужно относить к отдельному, четвертому виду ошибок авторизации. Стоит так же сказать, что данный вид ошибок крайне затруднительно обнаруживать методом черного ящика, ибо наблюдаемое поведение веб-приложения вполне соответствует ожидаемому при корреткной реализации механизма авторизации.
Такие ошибки, как мне представляется, можно довольно несложно обнаруживать с помощью статического анализа.
p.s. Данный пост навеян заданием “Challenge 6: Fear The EAR” c iCTF 2010 года.
> Такие ошибки, как мне представляется,
> можно довольно несложно обнаруживать с помощью статического анализа.
Эммм, несложно? Как ты себе это представляешь?
Как-то очень давно Raz0r такой же баг в ShopScript находил. Вот прям 1 в 1, только там PHP был c header(), а не Python.
Познавательно. Видимо, баг действительно не очень редкий, только находится black box’ом плохо…
>> Эммм, несложно? Как ты себе это представляешь?
Искать вызовы редиректов без принудительного завершения работы скрипта.
Антон совершенно правильно написал – фактически, задачка по анализу CFG
http://forum.antichat.ru/thread56756.html
Заголовок: [ header("Location: ... die(); ]
Языки меняются, принципы неизменны :)
Спасибо за ссылку – очень емко и по делу!
>Языки меняются, принципы неизменны :)
Аминь!