Защита от хакеров корпоративных сетей
Шрифт:
/* prints to stdout the error messages. Format: %error ### message
text, where ### follows rfc 640 */
void
print_error(va_alist)
va_dcl
{
va_list list;
int i;
int err_no;
char *format;
if (printed_error_flag)
{
return;
}
va_start(list);
err_no = va_arg(list, int);
for (i = 0; i < N_ERRS; i++)
{
if (errs[i].err_no == err_no)
{
printf(“%%error %s”, errs[i].msg);
break;
}
}
format = va_arg(list, char*);
if (*format)
{
printf(“: ”);
}
vprintf(format, list);
va_end(list);
printf(“\n”);
printed_error_flag = TRUE;
}В исходном тексте жирным шрифтом отмечено место передачи входных данных программы функции vprintf. Причиной уязвимости форматирующей строки является не функция vprintf, а то, как ее
В примере рассматривается функция print_error, потому что она наглядно демонстрирует причины возникновения уязвимостей форматирующей строки, которые могут быть использованы злоумышленником. Во многих программах есть функции, похожие на print_error. В некотором смысле функция print_error подобно функции syslog служит оболочкой для выдачи диагностики об ошибке. Ее параметрами являются код ошибки и параметры, аналогичные параметрам функции printf. Как уже обсуждалось в начале главы, проблема состоит в том, что программисты могут забыть о возможности передачи злоумышленником форматирующей строки через входные параметры.
Рассмотрим, что произойдет, когда клиент подключится к сервису и попытается подсунуть функции vprintf форматирующую строку, взятую из входных параметров функции оболочки print_error.
Те из читателей, которые загрузили исходный текст программы, смогут найти разбираемый фрагмент кода в функции soa_parse_args из файла с исходным текстом server/soa. Подготовительные действия функции сокращены до минимума. В 53-ей строчке вызывается функция print_error (строка выделена жирным шрифтом), которая может стать источником серьезных ошибок:..
auth_area = find_auth_area_by_name(argv[i]);
if (!auth_area)
{
print_error(INVALID_AUTH_AREA, argv[i]);
free_arg_list(argv);
dl_list_destroy(soa_arg);
return NULL;
}При вызове функции print_error ей передается параметр argv[i], который является не чем иным, как форматирующей строкой. В конечном счете эта форматирующая строка будет передана функции vprintf для обработки, как об этом уже предварительно говорилось. Средствам контроля исходного текста программ это место должно показаться очень подозрительным и подходящим для организации атаки. Для безопасной передачи параметров следовало бы вызвать функцию print_error следующим способом:
print_error(INVALID_AUTH_AREA, «%s», argv[i]);
При этом способе вызова i-й аргумент программы argv[i] передается функции print_error как переменная, соответствующая спецификации преобразования %s. При этом исключается всякая возможность передачи функции print_error злонамеренной спецификации преобразования, которая могла бы непредусмотренным образом обработаться функцией vprintf, вызванной print_error. Строка argv[i] — это не что иное, как аргумент команды – soa, передаваемой клиентом серверу.
Подводя итог, следует сказать, что когда клиент соединяется с сервером rwhoisd и передает неверную команду – soa, функция print_error выводит сообщение об ошибке. При этом выполняется следующая последовательность действий.
1. Сервер получает аргумент команды – soa и вызывает для ее обработки функцию soa_directive.
2. Функция soa_directive передает команду функции soa_parse_args для обработки.
3. При обнаружении ошибки функция soa_parse_args передает код ошибки и командную строку функции print_error в качестве аргументов форматирующей строки.
4. Функция print_error передает форматирующую строку с содержащимися в ней данными клиента функции vprintf, о которой уже говорилось, и вызывает ее.
Теперь ясно, что удаленные клиенты могут передать функции vprintf форматирующую строку, которая является аргументом команды – soa. При подключении к серверу и передаче ему злонамеренной форматирующей строки злоумышленник может записать нужные ему данные в память программы сервера.Тестирование программ способом случайной форматирующей строки
Поместив в исходный текст программы потенциально уязвимую форматирующую строку, продемонстрируем способы ее использования злоумышленником при помощи входных данных программы и изучим реакцию сервера на них.
В большинстве случаев можно создать такие условия работы программы, когда о наличии в программе уязвимости форматирующей строки можно будет судить по ее поведению. Если уязвимая программа выводит отформатированную строку, то наличие в ней уязвимости форматирующей строки очевидно. При отсутствии вывода о присутствии в программе уязвимости форматирующей строки можно судить по реакции программы на различные спецификации форматов.
Если при вводе входных данных со спецификациями преобразования %n%n процесс аварийно завершается, то, вероятнее всего, это происходит из-за нарушения доступа к памяти при попытке записи по неверным адресам памяти, прочитанным из стека. Передав программе, в которой не предусмотрен вывод отформатированной строки, через ее входные данные спецификации форматов %n%n, можно определить, уязвима она или нет. Если процесс аварийно завершается, не возвращает управления или неожиданно завершается, то вполне вероятно, что причиной этого является уязвимость форматирующей строки.
В рассматриваемом примере сервер возвращает клиенту сообщение об ошибке в виде отформатированной строки. Это облегчает действия злоумышленника, который ищет способ проникнуть на хост. В следующем примере приведен образец вызова программы rwhoisd, которая демонстрирует ошибку в форматирующей строке:
[dma@victim server]$ nc localhost 4321
%rwhois V-1.5:003fff:00 victim (by Network Solutions, Inc.
V-1.5.7.1)
– soa am_%i_vulnerable
%error 340 Invalid Authority Area: am_-1073743563_vulnerableВ этом примере причиной вывода сервером отрицательного целого числа – 1073743563 является то, что в передаваемой сервису строке содержится спецификация формата %i, на место которой в отформатированную строку записывается содержимое области памяти из стека в формате целого числа со знаком. Функция printf выводит отрицательное число после обработки содержимого области стека длиной 4 байта, в котором, как она предполагает, хранится целое число со знаком. Тем самым подтверждается наличие уязвимости форматирующей строки в программе rwhoisd.
Уязвимость форматирующей строки можно определить, анализируя исходный текст программы и ее поведение. После этого можно решить, как употребить найденную уязвимость. Уязвимостью форматирующей строки может воспользоваться удаленный сетевой клиент. Для этого аутентификация клиента не нужна, и вполне возможно, что этим сможет воспользоваться злоумышленник, чтобы получить доступ к главному хосту.
В аналогичных случаях, когда программа выводит отформатированную строку, злоумышленник может прочитать содержимое стека памяти и успешно воспользоваться его содержимым. Слова памяти могут быть прочитаны следующим способом:[dma@victim server]$ nc localhost 4321
%rwhois V-1.5:003fff:00 victim (by Network Solutions, Inc.
V-1.5.7.1)
– soa %010p
%error 340 Invalid Authority Area: 0xbffff935
– soa %010p%010p
%error 340 Invalid Authority Area: 0xbffff9350x0807fa80
– soa %010p%010p%010p
%error 340 Invalid Authority Area:
0xbffff9350x0807fa800x00000001
– soa %010p%010p%010p%010p
%error 340 Invalid Authority Area:
0xbffff9350x0807fa800x000000010x08081cd8В этом примере клиент восстановил одно, два, три и четыре слова из стека. Программа отформатировала слова таким образом, чтобы их можно было использовать для дальнейшей автоматической обработки. Хорошо написанная программа атаки может воспользоваться приведенной в примере отформатированной строкой для восстановления структуры стека процесса, выполняющегося на сервере. Программа атаки может читать данные из стека до тех пор, пока не найдет в стеке место хранения форматирующей строки, а затем автоматически вычислить в ней нужную программе позицию спецификации преобразования %n. Посмотрите на следующий пример:
%rwhois V-1.5:003fff:00 victim (by Network Solutions, Inc.
V-1.5.7.1)
– soa %010p%010p%010p%010p%010p%010p%010p%010p%010p%010p%010p
%010p%010p%010p%010p%010p%010p%010p%010p%010p%010p%010p%010p%010p
%010p%c%c%c%c%c
%error 340 Invalid Authority Area: 0xbffff9350x0807fa800x000
000010x0807fc300xbffff8f40x0804f21e0xbffff9350xbffff9350xbff
ff90c0x0804a6a30xbffff935(nil)0xbffff9300xbffffb640xbffff920
0x0804eca10xbffff9300xbffff9300x000000040xbffffb300x0804ef4e
0xbffff9300x000000050x616f732d0x31302500 010%p