View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0001670 | Far Manager | _Common | public | 2011-01-17 19:41 | 2011-03-17 23:10 |
Reporter | alexeypa | Assigned To | DrKnS | ||
Priority | high | Severity | major | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Platform | x64 | OS | Windows | OS Version | 7 |
Product Version | 2.0 | ||||
Fixed in Version | 2.0 | ||||
Summary | 0001670: Класс elevation реализует файловые операции небезопасно и крайне неэффективно. | ||||
Description | Отсюда http://bugs.farmanager.com/view.php?id=1668 Класс elevation реализует файловые операции, например fReadFile следующим образом. При открытии файла привилегированный процесс отдает непривилегированному копию значения хендла открытого файла. Эта копия затем передается вместе с командой C_FUNCTION_READFILE. Привилегированный процесс читает данные используя переданный хендл и возвращает прочитанные данные по тому же именованному каналу. Проблема первая. Такой дизайн открывает дырку в безопасности. Привилегированный процесс доверяет хендлу от непривилегированного процесса, позволяя тому читать из любого открытого привилегированным процессом файла. Проблема вторая. Качать данные по каналу крайне неэффективно. Вместо этого обработчик C_FUNCTION_CREATEFILE должен копировать хендл открытого файла в непривилегированный процесс с помощью DuplicateHandle. После чего тот сможет пользоваться этим хендлом как же как и любым другим. | ||||
Tags | No tags attached. | ||||
Build | 1799 | ||||
|
> Привилегированный процесс доверяет хендлу от непривилегированного процесса, позволяя тому читать из любого открытого привилегированным процессом файла. Ну, проблема не здесь - привилегированный процесс вообще всегда доверяет непривилегированному. Затыкается простым сравнением имён модулей. > обработчик C_FUNCTION_CREATEFILE должен копировать хендл открытого файла в непривилегированный процесс с помощью DuplicateHandle. После чего тот сможет пользоваться этим хендлом как же как и любым другим. А это будет работать в случаях, когда вызывающий должен обладать дополнительными привилегиями (как, например, SE_CREATE_SYMBOLIC_LINK_NAME для DeviceIoControl+FSCTL_SET_REPARSE_POINT+IO_REPARSE_TAG_SYMLINK? Ну и, к сожалению, у вас далеко не весь API в HANDLE-формате, остальное всё равно придётся гонять через пайп. |
|
> Ну, проблема не здесь - привилегированный процесс вообще всегда доверяет непривилегированному. Это означает, что дыра гораздо больше и серьезней. Привилегированный процесс должен проверять максимум того, что ему говорит непривилегированный. В противном случае нет никакой надобности разделять приложение на два процесса. Можно просто запускать непривилегированный процесс с максимальными привилегиями. > Затыкается простым сравнением имён модулей. Не закрывается. Caller authorization - так еще дыра. > А это будет работать в случаях, когда вызывающий должен обладать дополнительными привилегиями (как, например, SE_CREATE_SYMBOLIC_LINK_NAME для DeviceIoControl+FSCTL_SET_REPARSE_POINT+IO_REPARSE_TAG_SYMLINK? Нет. Для этих операций нужно оставить текущую реализацию. > Ну и, к сожалению, у вас далеко не весь API в HANDLE-формате, остальное всё равно придётся гонять через пайп. Совсем без пайпа не обойтись, конечно. Но все что можно сделать без него лучше сделать без него. |
|
> Не закрывается. Caller authorization - так еще дыра. Ок. Как рекомендуется проверять подлинность родителя? |
|
> Как рекомендуется проверять подлинность родителя? Никак. Вместо этого привелигерованный процесс должен писаться из предположения, что его может запустить кто угодно, и проверять разрешена ли конкретная операция для вызывающего исходя из его security context. Возьмем, к примеру, создание символической ссылки для которой нужны дополнительные привилегии. Тот факт, что такой сервис предоставляется непривилегированному приложению означает, что вы снижаете требования для этой операции ниже "системного" уровня. В данном случае - это нормально, так как именно этого вы и добиваетесь! Но при этом вы не хотите снизить уровень необходимых привилегий ниже необходимого. Напрмер вы не хотите разрешить создавать линки приложению, которое не имеет прав на запись в директорию вообще. Делается это так же как и в Win32 API. Вариант первый: CreateSymLink(source, target) – сервер проверяет security token процесса, чтобы удостоверится, что тот имеет право на создание линка. В user mode это несколько усложняется тем, что нужно найти токен того процесса/потока, от которого исходит запрос, не доверяя при этом клиенту. Вариант второй: CreateSymLink(HANDLE handle, source, target) – в это случае сервер уже установил права процесса и выдал ему handle. Внутри CreateSymLink сервер по Handle находит сохраненную ранее маску разрешенный операций и смотрит разрешена ли данная операция с этим конкретным handle. |
|
> привелигерованный процесс должен писаться из предположения, что его может запустить кто угодно, и проверять разрешена ли конкретная операция для вызывающего исходя из его security context. Ну, у нас "слегка" другой случай. Привилегированный процесс запускается единственно возможным родителем (собой же), других подключений не бывает. >> А это будет работать в случаях, когда вызывающий должен обладать дополнительными привилегиями (как, например, SE_CREATE_SYMBOLIC_LINK_NAME для DeviceIoControl+FSCTL_SET_REPARSE_POINT+IO_REPARSE_TAG_SYMLINK? > Нет. Для этих операций нужно оставить текущую реализацию. Кстати, таки работает :) > Такой дизайн открывает дырку в безопасности. Привилегированный процесс доверяет хендлу от непривилегированного процесса, позволяя тому читать из любого открытого привилегированным процессом файла. Не могу сказать, что идея отдавать наружу "готовый к употреблению" привилегированный хендл и никак не контролировать его дальнейшее использование выглядит "безопаснее" текущей, но код куда компактнее, прозрачнее и быстрее, это да. В первом приближении - build 1793. |
|
> Ну, у нас "слегка" другой случай. Привилегированный процесс запускается единственно возможным родителем (собой же), других подключений не бывает. Этот тот же самый случай. Эквивалент текущей ситуации - просто запускать Far всегда elevated. То, что так фар запускается только самим фаром не имеет с точки зрения безопасности никакого значения. > Не могу сказать, что идея отдавать наружу "готовый к употреблению" привилегированный хендл и никак не контролировать его дальнейшее использование выглядит "безопаснее" текущей. Посмотрите как работает CreateFile. Вроде бы тоже выдает наружу (в user mode) "готовый к употреблению" привилегированный хендл. Но почему-то считается что это более безопастно, чем просто разрешать всем, кто может вызвать функцию CreateFile создавать/открывать любое файлы (а ведь ядро это может). Ваша ситуцаия польностью аналогична. > никак не контролировать его дальнейшее использование Это не совем так. Win32 хендл нельзя передать в другой процесс по значению. Вернее бесполезно. Нужно звать DuplicateHandle. В случае вашего сервиса нужно аналогичное поведение. > Кстати, таки работает :) Баба с возу - кобыле легче. > В первом приближении - build 1793. Посмотрю на досуге. |
|
> Эквивалент текущей ситуации - просто запускать Far всегда elevated. Эквивалент? Не мне же вам рассказывать :) , что приподнятый "на постоянной основе" Far будет: 1) содержать приподнятый же код плагинов, что не всегда желательно; 2) порождать приподнятые же процессы, что совсем не желательно. А так и окружение остаётся ограниченным, и операции, требующие административных привилегий, могут быть доступны без перезапуска. |
|
> Эквивалент? Именно что эквивалент. Имя этому эквиваленту - дыра "размером с Шеви 60-го года" (c). > 1) содержать приподнятый же код плагинов, что не всегда желательно; > 2) порождать приподнятые же процессы, что совсем не желательно. А это список причин почему так делать нельзя. С которым я полностью согласен. > А так и окружение остаётся ограниченным, Каким образом оно остается ограниченным, если кто угодно может выполнять привилегированные операции? Скажем бесправный guest может удалять файлы из вашей папки Documents? > и операции, требующие административных привилегий, могут быть доступны без перезапуска. Я понимаю мотивацию и не имею больших возражений по ней. У меня больщие возражения по части реализации и дизайна. |
|
> Каким образом оно остается ограниченным, если кто угодно может выполнять привилегированные операции? Скажем бесправный guest может удалять файлы из вашей папки Documents? Эксплоит в студию :) |
|
> Каким образом оно остается ограниченным, если кто угодно может выполнять привилегированные операции? Скажем бесправный guest может удалять файлы из вашей папки Documents? Дополню, что есть два способа сделать дизайн приемлемо безопасным. 1. Реализовать проверку прав для каждой операции (с хенлод или без). 2. _Доказать_, что неавторизированные пользователи не смогут запросить привилегированную операцию. Причем достигается это опять же проверкой прав при коннекте к сервису. Этот подход чреват тем, что в одно мгновения ока может открыться ящик пандоры, если непривилегированные клиенты найдут обходной способ передать команды серверу. #1 гораздо стабильнее. Например, что будет если guest присоединится с elevated far первым, до того, как с нем присоединится non elevated far? Позволяются ли паралельные соединения с elevated far от нескольких клиентов? И так далее. Сценариев очень много. |
|
> Например, что будет если guest присоединится с elevated far первым, до того, как с нем присоединится non elevated far? > Позволяются ли паралельные соединения с elevated far от нескольких клиентов? Давайте не будем опускаться до гадания на кофейной гуще? 1. Пайп создаётся непривилегированным процессом. В единичном экземпляре. 2. Привилегированный процесс подключается к нему. Эксклюзивно. |
|
> Давайте не будем опускаться до гадания на кофейной гуще? Это не гадание на кофейной гуще. Это толстый намек на то, что чтобы убедится, что применяемое решение безопасно нужно внимательно проанализировать все возможные сценарии. Пример, который я привел из головы, просто один из возможных сценариев, которых много. А с ходу заявлять о своем специальном случае - не лучшая стратегия. У всех и всегда специальные случае. А потом находится куча дыр. Я пока что не вижу, что подобный анализ был сделан. Если я ошибаюсь - замечательно. |
|
Ну вот, например, я заглянул в исходники и вижу следующее. Non elevated far создает канал, запускает elevated far и ждет коннекта. При вызове CreateNamedPipe в качестве lpSecurityAttributes передается nullptr что означает: If lpSecurityAttributes is NULL, the named pipe gets a default security descriptor and the handle cannot be inherited. The ACLs in the default security descriptor for a named pipe grant full control to the LocalSystem account, administrators, and the creator owner. They also grant read access to members of the Everyone group and the anonymous account. Иначе говоря anonynous может подключится до того, как успеет подключится elevated far, блокируя тем самом оба фара, так как nMaxInstances == 1. anonymous не сможет ничего прочитать из канала, так как non elevated far жидает, что elevated туда что-то напишет. Но denial of service мы схлопотали на ровном месте. |
|
Еще до кучи. ReadFile(Pipe) волен вернуть меньше байт, чем было запрошено. Это совсем не учитывается в функциях вида ReadPipeXxx. |
|
> anonymous не сможет ничего прочитать из канала, так как non elevated far жидает, что elevated туда что-то напишет. Но denial of service мы схлопотали на ровном месте. И это даёт повод к громким заявлениям типа "бесправный guest может удалять файлы из вашей папки Documents"? Но - не вопрос, после 1794 канал откроется только администраторам. > Еще до кучи. ReadFile(Pipe) волен вернуть меньше байт, чем было запрошено. Это совсем не учитывается в функциях вида ReadPipeXxx. Разумеется. Но на данном этапе это не критично т. к. и читателем, и писателем является один и тот же модуль. |
|
> И это даёт повод к громким заявлениям типа "бесправный guest может удалять файлы из вашей папки Documents"? Вы правда, что ли, не понимаете о чем я толкую? Ну какое это, так его рас так, "громкое заявление"? Я покопался в коде пару минут и тут же наткнулся на стандартную дырку. Вернее на семейство дырок. И сходу предложил реализацию DoS из под локального анонимуса. А если я там покопаюсь немного дольше, то видимо найду больше? Вас не смущает тот факт, что код, работающий с повышенными привилегиями, не анализировался на предмет безопасности? И что изменится от того, что случай "бесправный guest может удалять файлы из вашей папки Documents" по счастливой случайности не реализуется на практике? От этого непроверенный код станет более безопасным что-ли? Вот еще один вариант DoS - анонимус создает каналы с именами вида \\.\pipe\FarPipeXXX. После чего ломается elevation в Far-е, вне зависимости от уровня привилегий, под которым запущен Far. Лечится данные проблема например одним из двух способов ниже: 1. Использованием неименованных каналов вместо именованного. Хендлы передаются в запускаемый процесс с помошью механизма наследования хендлов. (Не скажу сходу, заботает ли это в случае elevation при запуске процесса). Численные значения хенлов передаются ребенку в командной строке. 2. Генерированием уникального имени канала, с передачей этого имени через командную строку. > Разумеется. Но на данном этапе это не критично т. к. и читателем, и писателем является один и тот же модуль. В своем коде я бы не стал на это рассчитывать, но да, похоже что в этом случае это работает: The ReadFile function returns when one of the following conditions occur: - A write operation completes on the write end of the pipe. - ... При условии, конечно, в коде гарантируется неподключение rogue клиентов или серверов. |
|
> И сходу предложил реализацию DoS из под локального анонимуса. > еще один вариант DoS - анонимус создает каналы с именами вида \\.\pipe\FarPipeXXX Осталось выяснить, кому и зачем надо это надо. Локальный маргинальный файлменеджер - не корпоративный сайт конкурентов, профита нет. > А если я там покопаюсь немного дольше, то видимо найду больше? Копайтесь на здоровье, анализируйте, только спасибо скажем. Но, пожалуйста, давайте говорить о _реально_ существующих проблемах, а не о том, что произошло бы, если бы у бабушки кое-что было. > что изменится от того, что случай ... по счастливой случайности не реализуется на практике? Я не вижу здесь случайностей, нереализуемость этого случая этим методом заложена изначально. > 1. Использованием неименованных каналов вместо именованного. Хендлы передаются в запускаемый процесс с помошью механизма наследования хендлов. Это, действительно, прекрасная идея. И если бы она была возможна - уверяю вас, никто бы не возился со строками. Но, увы - чтобы ребёнок унаследовал хендлы родителя, нужно передать bInheritHandles=TRUE в CreateProcess. А CreateProcess, как известно, совсем не поддерживает elevation и вместо него нужно использовать ShellExecute[Ex]. А ShellExecute[Ex] внутри всегда вызывает CreateProcess с bInheritHandles=FALSE, и изменить это нельзя. > 2. Генерированием уникального имени канала, с передачей этого имени через командную строку. Возможно, но см. первый абзац. |
|
Дополнительная информация в тему: http://www.codeproject.com/KB/vista-security/UAC__The_Definitive_Guide.aspx |
|
> Осталось выяснить, кому и зачем надо это надо. Локальный маргинальный файлменеджер - не корпоративный сайт конкурентов, профита нет. А разве это может быть причиной писать некачественный код? Уточню, пожалуй, чтобы избежать недопонимания. У меня нет в данный момент на руках конкретных фактов, демонстрирующих "некачественность" обсуждаемого кода. Факты которые у меня были - уже реализовались в зачекиненых исправлениях. Но, у меня есть предчуствие, gut feeling, если хотите, что зачекиненные исправления - это только верхушка айсберга. Предчуствие базируется на легкости обнаружения проблем, вашем утверждении о том, что привилегированный код полностью доверяет непривилегированному и некотором опыте. Я, откровенно, ожидал от вас услышать либо "Мы этот код проанализировали уже. И вот список причин, почему атака не возможна. А вот список вещей, что мы сознательно решили не исправлять.", либо "Да, мы на этот код еще толком не смотрели. Надо бы его прорецензировать. Заведу баг специально для этой цели". Короче я не заметил попыток сделать шаг назад и посмотреть на проблему в целом. Но, конечно же, вы мне ничего не должны & vice versa. > Я не вижу здесь случайностей, нереализуемость этого случая этим методом заложена изначально. Возможность подключения анонимного пользователя тоже была заложена изначально? |
|
==> resolved. Насколько я могу судить, больше изменений по данному багу пока не предполагается. |
|
> Я, откровенно, ожидал от вас услышать либо "Мы этот код проанализировали уже. И вот список причин, почему атака не возможна. А вот список вещей, что мы сознательно решили не исправлять.", либо "Да, мы на этот код еще толком не смотрели. Надо бы его прорецензировать. Заведу баг специально для этой цели" Ок, изложу популярно: Код писался не от фонаря. Возможность атаки рассматривалась изначально. По причинам, изложенным в #6159, управление привилегированным процессом злоумышленником "извне" считается невозможным. Некоторые вещи (например, проверка идентичности сервера клиенту по GetNamedPipeServerProcessId, расширенная обработка ошибок передачи и обрывов соединения, случайное имя канала, возможно, асинхронная передача) - пока что сознательно проигнорированы как несущественные. Несмотря на это, рецензия никогда не помешает. Как и любому другому коду. Если у вас есть желание и возможность - welcome. > Возможность подключения анонимного пользователя тоже была заложена изначально? Не "заложена", но проигнорирована, как крайне маловероятная и недеструктивная. > Насколько я могу судить, больше изменений по данному багу пока не предполагается. Смотрите сами. Обе описанных проблемы решены, для других вопросов наверное лучше будет завести новый инцидент. |
|
> По причинам, изложенным в #6159 Что это за номер? |
|
0001670:0006159 |
|
> 0001670:0006159 Ну вот еще сценарий атаки. До того, как привилегированная копия фара успеет подсоединится к родителю, злоумышленник прибивает родителя и создает канал с именем \\.\pipe\FarPipeXXX, где XXX - PID убитого родителя. Результат - повышение привилегий с уровня интерактивного пользователя до администратора без UAC consent. Вернее Far показывает UAC consent, злоумышлениик делает все что угодно от имени Far. |
|
GUID, генерируемый каждый раз, в качестве pipe name - это решение проблемы? |
|
Кстати вот еще одно решение: При запуске elevated копии FAR проверять Process ID родительского процесса. Если не совпадает c Process ID переданным в параметрах командной строки - не соединяться к pipe. http://www.codeproject.com/KB/threads/ParentPID.aspx |
|
> GUID, генерируемый каждый раз, в качестве pipe name - это решение проблемы? Учитывая что подобная атака и сейчас маловероятна - то можно сказать, что да, это проблему решит. Однако я бы пока не торопился и попатылся найти способ надежно передать хендл канала напрямую из процесса в процесс. 1. Наследование не работает. 2. Делать из привилегированного процесса OpenProcess для PID'а родителя, а затем - DuplicateHandle - работает, но, теоретически, PID может быть переиспользован. Т.е. можно убить родителя и создать процесс с таким же PIDом. Крайне маловероятно, конечно. Еще есть варианты типа использовать elevation с CoCreateInstance, но там другие сложности, а именно нужно создавать ключи в HKLM, что без формальной установки не работает. |
|
> Т.е. можно убить родителя и создать процесс с таким же PIDом. > Крайне маловероятно, конечно. А это можно решить передавая в дополнении к ProcessId еще и Process Creation Time в качестве параметра в elevated FAR и потом дальнейшего сравнения. Использовать функцию GetProcessTimes(): http://msdn.microsoft.com/en-us/library/ms683223%28v=VS.85%29.aspx |
|
> А это можно решить передавая в дополнении к ProcessId еще и Process Creation Time в качестве параметра в elevated FAR и потом дальнейшего сравнения. Это сложнее, чем генерировать GUID, уникальность GUID'а выше и код с генерацией GUID'а проще и понятнее. |
|
Ок. имя канала - GUID; elevated process проверяет, что pid создателя канала соответствует переданному. elevated process проверяет, что процесс с переданным pid существует, и что полное имя этого процесса равно его собственному. 1795. |
|
(Process ID + ProcessCreationTime) дают уникальность и одновременно возможность проверки родителя ДО соединения с pipe. GUID можно использовать для именования pipe - как дополнительную меру защиты (но не основную), и чтобы исключить вероятность создания PIPE чужим процессом с именем pipe FAR (т.е. исключить DoS aтаку). |
|
> (Process ID + ProcessCreationTime) дают уникальность Строго говоря - не дают. > проверки родителя ДО соединения с pipe. "Проверка родителя" (оно же - caller authorization) почти всегда - дырка в безопасности. С точки зрения правильного дизайна этого делать не нужно. Нужно проверять права на выполнение операции, тем или иным безопасным способом. Для чего годится проверка родителя - немного затруднить жизнь злоумышленнику. Генерация имени из GUID - вполе себе справляется с этой задачей. Правильный способ решения этой проблемы - вообще избежать возможности перехвата имени канала. Да и имя канала ни к чему. Тут только elevation мешает. > elevated process проверяет, что процесс с переданным pid существует, и что полное имя этого процесса равно его собственному. Сдается мне - это перебор. |
|
Ну вы уж определитесь какие атаки нужно закрывать, а какие можно оставить :) В конечном итоге все равно получается, что непривилигерованный процесс FAR управляет другим привилегированным процессом FAR. Т.е. как только канал налажен сразу же появляется огромадная дыра :) --- Например, что мешает какому-то процессу MyAttack.exe передать в непривилигированный FAR набор команд для удаления файлов, которые он затем передаст в привилегирированный FAR для исполнения? Например: использовать CreateRemoteThread() и затем последовательность SendInput(). |
|
> В конечном итоге все равно получается, что непривилигерованный процесс FAR управляет другим привилегированным процессом FAR. Т.е. как только канал налажен сразу же появляется огромадная дыра :) Так и есть. Более того, это справедливо для любой elevated программы. Однако это не означает, что нужно открывать двери неприятностям, если их можно не открывать. |
|
Я думаю можно минимизировать возможность использования дыры 0001670:0006222, если закрывать pipe через некоторое время неактивности с завершением elevated FAR. Время может быть конфигурируемым. |
|
Перемудрили с параноей... Запускаем фар (2.0 build 1797 x86) Пробуем что-то требующее elevation (например, создать подпапку в "C:\Program Files (x86)\Far\"). На запрос фара (Access denied) говорим "Ok", а на подтверждение самой винды (UAC) говорим "Нет", получаем ожидаемое: ╔═════════ Error ══════════╗ ║ Operation cancelled ║ ║ Cannot create the folder ║ ║ 1797 ║ ╟──────────────────────────╢ ║ { Retry } [ Cancel ] ║ ╚══════════════════════════╝ Жмем Retry, Ok, Да Теперь получаем неожиданное ╔═════════════ Error ══════════════╗ ║ Процесс был неожиданно завершен. ║ ║ Cannot create the folder ║ ║ 1797 ║ ╟──────────────────────────────────╢ ║ { Retry } [ Cancel ] ║ ╚══════════════════════════════════╝ Все, в этом сеансе фара Elevation больше не заработает. |
|
1798 |
|
Разбор полетов с отладчиком выявил еще один интересный момент (отладочное сообщение): Not Trusted Server! strCurrentProcess=C:\Program Files (x86)\xxFar\Far.exe strParentProcess=C:\Program Files (x86)\xxFar\far.exe TrustedServer=0 В итоге, админская копия фара по завершается, а юзер получает ошибку ╔═════════════ Error ══════════════╗ ║ Процесс был неожиданно завершен. ║ ║ Cannot create the folder ║ ║ xxxx ║ ╟──────────────────────────────────╢ ║ { Retry } [ Cancel ] ║ ╚══════════════════════════════════╝ |
|
> strCurrentProcess=C:\Program Files (x86)\xxFar\Far.exe > strParentProcess=C:\Program Files (x86)\xxFar\far.exe и как ты это получил? |
|
int _tmain(int argc, _TCHAR* argv[]) { STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {NULL}; wchar_t szPath[MAX_PATH]; lstrcpy(szPath, L"far.exe"); if (CreateProcess(NULL, szPath, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } return 0; } |
|
Мда. 1799. |
Date Modified | Username | Field | Change |
---|---|---|---|
2011-01-17 19:41 | alexeypa | New Issue | |
2011-01-17 20:51 | DrKnS | Note Added: 0006149 | |
2011-01-17 21:04 | alexeypa | Note Added: 0006150 | |
2011-01-17 21:21 | DrKnS | Note Added: 0006151 | |
2011-01-17 21:21 | DrKnS | Assigned To | => DrKnS |
2011-01-17 21:21 | DrKnS | Status | new => assigned |
2011-01-17 21:41 | alexeypa | Note Added: 0006152 | |
2011-01-17 22:56 | DrKnS | Note Added: 0006153 | |
2011-01-17 23:07 | alexeypa | Note Added: 0006154 | |
2011-01-17 23:07 | alexeypa | Note Edited: 0006154 | |
2011-01-17 23:42 | DrKnS | Note Added: 0006155 | |
2011-01-17 23:50 | alexeypa | Note Added: 0006156 | |
2011-01-17 23:50 | alexeypa | Note Edited: 0006156 | |
2011-01-18 00:00 | DrKnS | Note Added: 0006157 | |
2011-01-18 00:05 | alexeypa | Note Added: 0006158 | |
2011-01-18 00:37 | DrKnS | Note Added: 0006159 | |
2011-01-18 00:46 | alexeypa | Note Added: 0006160 | |
2011-01-18 01:40 | alexeypa | Note Added: 0006161 | |
2011-01-18 06:13 | alexeypa | Note Added: 0006163 | |
2011-01-18 12:52 | DrKnS | Note Added: 0006164 | |
2011-01-18 12:52 | DrKnS | Status | assigned => feedback |
2011-01-18 17:31 | alexeypa | Note Added: 0006173 | |
2011-01-18 17:31 | alexeypa | Status | feedback => assigned |
2011-01-18 18:16 | DrKnS | Note Added: 0006179 | |
2011-01-18 18:54 | alexmitin | Note Added: 0006184 | |
2011-01-18 19:04 | alexeypa | Note Added: 0006185 | |
2011-01-18 19:13 | alexeypa | Note Added: 0006186 | |
2011-01-18 19:13 | alexeypa | Status | assigned => resolved |
2011-01-18 19:50 | DrKnS | Note Added: 0006187 | |
2011-01-19 05:35 | alexeypa | Note Added: 0006190 | |
2011-01-19 10:14 | DrKnS | Note Added: 0006192 | |
2011-01-19 16:21 | alexeypa | Note Added: 0006212 | |
2011-01-19 17:48 | alexmitin | Note Added: 0006214 | |
2011-01-19 17:53 | alexmitin | Note Added: 0006215 | |
2011-01-19 17:58 | alexeypa | Note Added: 0006216 | |
2011-01-19 18:26 | alexmitin | Note Added: 0006217 | |
2011-01-19 19:13 | alexeypa | Note Added: 0006218 | |
2011-01-19 19:25 | DrKnS | Note Added: 0006219 | |
2011-01-19 19:25 | alexmitin | Note Added: 0006220 | |
2011-01-19 19:35 | alexeypa | Note Added: 0006221 | |
2011-01-19 21:23 | alexmitin | Note Added: 0006222 | |
2011-01-19 21:27 | alexmitin | Note Edited: 0006222 | |
2011-01-19 21:29 | alexmitin | Note Edited: 0006222 | |
2011-01-19 22:00 | alexeypa | Note Added: 0006223 | |
2011-01-19 22:53 | alexmitin | Note Added: 0006224 | |
2011-01-22 16:09 | Maximus | Note Added: 0006230 | |
2011-01-22 16:10 | Maximus | Status | resolved => feedback |
2011-01-22 16:36 | DrKnS | Note Added: 0006232 | |
2011-01-23 00:52 | Maximus | Note Added: 0006233 | |
2011-01-23 00:58 | DrKnS | Note Added: 0006234 | |
2011-01-23 01:15 | Maximus | Note Added: 0006235 | |
2011-01-23 11:10 | DrKnS | Note Added: 0006236 | |
2011-01-27 14:38 | DrKnS | Build | => 1799 |
2011-01-27 14:38 | DrKnS | Status | feedback => closed |
2011-01-27 14:38 | DrKnS | Resolution | open => fixed |
2011-01-27 14:38 | DrKnS | Fixed in Version | => 2.0 |