Справочник по SysAdm для UNIX и Linux :Почему кэшированные справочные страницы представляют собой «угрозу безопасности»?

Поскольку отладочный вывод динамического компоновщика/загрузчика ldподтверждает, что обе программы victimи spyзагружают правильный входной файл, следующим шагом будет проверка того, действительно ли ядро ​​настроило физический файл. страницы, где libmyl.soзагружаются в память для совместного использования victimи spy.

В Linux это можно проверить, начиная с версии ядра 2.6.25, через интерфейсpagemapв ядре, который позволяет программам пользовательского пространства проверять таблицы страниц и соответствующую информацию, читая файлы в /proc.

Общая процедура использования карты страниц для определения того, разделяют ли два процесса память, выглядит следующим образом:

  1. Прочтите /proc//mapsдля обоих процессов, чтобы определить, какие части пространства памяти каким объектам сопоставляются.
  2. Выберите карты, которые вас интересуют, в данном случае страницы, на которые отображается libmyl.so.
  3. Открыть /proc//pagemap. pagemapсостоит из 64 -битовых дескрипторов карты страниц, по одному на страницу. Сопоставление между адресом страницы и адресом ее дескриптора в pagemapравно адресу страницы/размеру страницы *размеру дескриптора . Найдите дескрипторы страниц, которые вы хотите изучить.
  4. Считать 64-битный -дескриптор как целое число без знака для каждой страницы из pagemap.
  5. Сравните номер кадра страницы (PFN )в битах 0 -54 дескриптора страницы между страницами libmyl.soдля victimи spy. Если PFN совпадают, два процесса совместно используют одни и те же физические страницы.

В следующем примере кода показано, как можно получить доступ к pagemapи распечатать его внутри процесса. Он используетdl_iterate_phdr()для определения виртуального адреса каждой совместно используемой библиотеки, загруженной в пространство памяти процессов, затем ищет и печатает соответствующий pagemapиз /proc//pagemap.

#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define E_CANNOT_OPEN_PAGEMAP 1
#define E_CANNOT_READ_PAGEMAP 2

typedef struct __attribute__ ((__packed__)) {
    union {
        uint64_t pmd;
        uint64_t page_frame_number : 55;
        struct {
            uint64_t swap_type: 5;
            uint64_t swap_offset: 50;
            uint64_t soft_dirty: 1;
            uint64_t exclusive: 1;
            uint64_t zero: 4;
            uint64_t file_page: 1;
            uint64_t swapped: 1;
            uint64_t present: 1;
        };
    };
} pmd_t;


static int print_pagemap_for_phdr(struct dl_phdr_info *info,
                                  size_t size, void *data)
{
    struct stat statbuf;

    size_t pagesize = sysconf(_SC_PAGESIZE);

    char pagemap_path[BUFSIZ];
    int pagemap;

    uint64_t start_addr, end_addr;

    if (!strcmp(info->dlpi_name, "")) {
        return 0;
    }

    stat(info->dlpi_name, &statbuf);

    start_addr = info->dlpi_addr;
    end_addr = (info->dlpi_addr + statbuf.st_size + pagesize) & ~(pagesize-1);

     printf("\n%10p-%10p %s\n\n",
            (void *)start_addr,
            (void *)end_addr,
            info->dlpi_name);

     snprintf(pagemap_path, sizeof pagemap_path, "/proc/%d/pagemap", getpid());

     if ((pagemap = open(pagemap_path, O_RDONLY)) < 0) {
         error(E_CANNOT_OPEN_PAGEMAP, errno, 
               "cannot open pagemap: %s", pagemap_path);
     }

     printf("%10s %8s %7s %5s %8s %7s %7s\n",
            "", "", "soft-", "", "file /", "", "");
     printf("%10s %8s %7s %5s %11s %7s %7s\n",
            "address", "pfn", "dirty", "excl.",
            "shared anon", "swapped", "present");

     for (unsigned long i = start_addr; i < end_addr; i += pagesize) {
          pmd_t pmd;

          if (pread(pagemap, &pmd.pmd, sizeof pmd.pmd, (i / pagesize) * sizeof pmd) != sizeof pmd) {
              error(E_CANNOT_READ_PAGEMAP, errno,
                    "cannot read pagemap: %s", pagemap_path);
          }

          if (pmd.pmd != 0) {
              printf("0x%10" PRIx64 " %06" PRIx64 " %3d %5d %8d %9d %7d\n", i,
                     (unsigned long)pmd.page_frame_number,
                     pmd.soft_dirty,
                     pmd.exclusive,
                     pmd.file_page,
                     pmd.swapped,
                     pmd.present);
          }
    }

    close(pagemap);

    return 0;
}

int main()
{
    dl_iterate_phdr(print_pagemap_for_phdr, NULL);

    exit(EXIT_SUCCESS);
}

Вывод программы должен выглядеть следующим образом:

$ sudo./a.out

0x7f935408d000-0x7f9354256000 /lib/x86_64-linux-gnu/libc.so.6

                      soft-         file /                
   address      pfn   dirty excl. shared anon swapped present
0x7f935408d000 424416   1     0        1         0       1
0x7f935408e000 424417   1     0        1         0       1
0x7f935408f000 422878   1     0        1         0       1
0x7f9354090000 422879   1     0        1         0       1
0x7f9354091000 43e879   1     0        1         0       1
0x7f9354092000 43e87a   1     0        1         0       1
0x7f9354093000 424790   1     0        1         0       1
...

где:

  • address— виртуальный адрес страницы
  • pfn— номер кадра страницы
  • soft-dirtyуказывает, установлен ли программный -грязный бит в записи таблицы страниц (PTE ).
  • excl.указывает, отображается ли страница исключительно (, т. е. страница отображается только для этого процесса ).
  • file / shared anonуказывает, является ли страница файловой страницей или общей анонимной страницей.
  • swappedуказывает, что страница в данный момент заменена. (означает, что presentравно нулю ).
  • presentуказывает, присутствует ли страница в данный момент в резидентном наборе процессов. (означает, что swappedравно нулю ).

(Примечание :Я запускаю пример программы с sudo, так как начиная с Linux 4.0 только пользователи с возможностью CAP_SYS_ADMINмогут получать PFN из /proc//pagemap. Начиная с Linux 4.2 поле PFN обнуляется, если у пользователя нет CAP_SYS_ADMIN. Причина этого изменения заключается в том, чтобы затруднить использование другой уязвимости, связанной с памятью, атаки Rowhammer , с использованием информации о физическом отображении виртуального -в -, раскрываемом PFN.)

Если вы запустите пример программы несколько раз, вы должны заметить, что виртуальный адрес страницы должен измениться (из-за ASLR ), но PFN для разделяемых библиотек, которые используются другими процессами должно остаться прежним.

Если PFN для libmyl.soсовпадают между программами victimи spy, я бы начал искать причину неудачи атаки в самом коде атаки. Если PFN не совпадают, дополнительные биты могут подсказать, почему страницы не настроены для совместного использования. Биты pagemapуказывают следующее:

present file exclusive state:
   0      0     0      non-present
   1      1     0      file page mapped somewhere else
   1      1     1      file page mapped only here
   1      0     0      anonymous non-copy-on-write page (shared with parent/child)
   1      0     1      anonymous copy-on-write page (or never forked)

Копировать -на -страницы записи в области (MAP_FILE | MAP_PRIVATE)в этом контексте являются анонимными.

Бонус:Чтобы получить количество раз отображения страницы, можно использовать PFN для поиска страницы в /proc/kpagecount. Этот файл содержит 64-битное число -числа отображений каждой страницы, проиндексированных PFN.

28
02.06.2021, 15:05
5 ответов

Предположим, рассматриваемая система является веб-сервером. Предположим также, что администратор сервера предоставляет некоторое программное обеспечение, установленное в системе, для широкой публики (или корпоративной интрасети )через веб-страницу. Это может быть так же просто, как изменение размера изображения, калькулятор или словарь.

Если программное обеспечение имело справочные страницы, связанные с ним при установке, то администратор — будучи добрым и внимательным человеком — мог бы решить, что сделать эти справочные страницы доступными для пользователей веб-службы также будет хорошая идея.

Итак, значок «Справка» на веб-странице запускает сценарий, который захватывает одну или несколько — кэшированных — справочных страниц и отправляет их в браузер пользователя.

Любой человек или код, имеющий доступ на запись к каталогу кеша, может изменить эти файлы на:

  • внедрить произвольный Javascript, который будет выполняться при посещении браузеров пользователя
  • собирать данные телеметрии от всех посещающих пользователей и пересылать их в какой-либо репозиторий для последующей обработки/профилирования
  • собирать учетные данные для аутентификации — возможно, даже учетные данные привилегированного пользователя системы (, например администратора)

Любой человек с воображением и распущенной моралью/этикой может злоупотреблять любым из вышеперечисленных способов множеством различных способов.

6
28.07.2021, 11:27

Большинство современных дистрибутивов предварительно -кэшируют справочные страницы (путем обработки с помощью troff ), когда установлен соответствующий пакет. Это не проблема.

Проблема возникает, когда исходные справочные файлы присутствуют, но кеш пуст (, т. е. файлы кеша не были предварительно -сгенерированы ).

Есть два способа справиться с этим:

  1. Запускать справочную страницу через troff каждый раз от имени пользователя
  2. Запустите справочную страницу через troff один раз как root и сохраните в каталоге кеша

Для запуска от имени root man должен иметь setuid. Если в что-нибудь были какие-либо недостатки безопасности, например. синтаксический анализ командной строки, злоумышленник может получить повышенные привилегии

Вот соответствующий источник:https://git.savannah.gnu.org/cgit/man-db.git/tree/src/man.c

К счастью, все основные дистрибутивы теперь предварительно -кэшируют справочные страницы, так что не о чем беспокоиться

5
28.07.2021, 11:27

Каждый раз, когда каталог становится доступным для глобальной записи, возникает брешь в системе безопасности. Игнорирование того, какова предполагаемая цель каталога и как это можно подорвать, просто сделать его доступным для записи - проблема.

Вот несколько возможных проблем, не связанных с функцией каталога:

  • Если в файловой системе нет других каталогов, доступных для записи пользователю, это предоставит любому пользователю возможность использовать пространство в этой файловой системе, которое он не мог бы использовать иначе
  • Любой пользователь мог сохранять файлы в каталоге, заполняя файловую систему, чтобы вызвать атаку типа «отказ в обслуживании». Если это та же файловая система, что и /var/log, это может помешать записи журналов
  • .
  • Файлы могли быть скрыты в этом каталоге за пределами ожидаемых местоположений. Они могут сохраняться после удаления учетной записи, и если файловая система таинственным образом заполнена, их может быть трудно найти
  • .
  • Если файлы или каталоги создаются с тем же именем, что и будущие кэшированные файлы, это может помешать правильному функционированию предполагаемого использования каталога (, даже если содержимое этих файлов само по себе не является вредоносным ). Настройка разрешений для этих файлов может затруднить автоматическое исправление.
6
28.07.2021, 11:27

Уместной здесь концепцией является поверхность атаки .

Поверхность атаки — это диапазон мест, где злоумышленник может искать и потенциально находить уязвимость.

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

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

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


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

6
28.07.2021, 11:27

Другой риск :Переполнение буфера. Что, если поддельная справочная страница содержит смехотворно длинную строку, которая выходит за пределы буфера строк вашего пейджера и каким-то образом запускает выполнение escape-последовательности? Подобные проблемы все еще обнаруживаются направо и налево; похоже, что не раньше, чем исправлена ​​одна ошибка, обнаруживается другая.

Или это может быть не переполнение буфера, а какая-то другая атака, основанная на неверном вводе. Открытие «справочных страниц», созданных ненадежными пользователями, похоже на открытие всех вложений, пришедших с подозрительными электронными письмами :. В этом случае злоумышленник может использовать любую известную уязвимость программы, читающей файл (., ваш пейджер. )Может ли он безопасно обрабатывать любой мыслимый ввод? Нет никакого способа узнать наверняка.

1
28.07.2021, 11:27

Теги

Похожие вопросы