The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Использование systemtap для устранения уязвимости в реализации /proc/pid/mem
Для устранения уязвимости CVE-2012-0056 в /proc/pid/mem без обновления ядра
Linux можно использовать systemtap для ограничения системного вызова. Systemtap
из коробки доступен в RHEL/CentOS и может быть установлен из репозитория в
Debian/Ubuntu. Без systemtap обходным путем решения проблемы является
блокирования доступа пользователя на запуск setuid-программ.

Проверим, уязвима ли наша система. Для этого загружаем, собираем и запускаем
специальную проверочную утилиту:

   $ wget http://grsecurity.net/~spender/correct_proc_mem_reproducer.c
   $ make correct_proc_mem_reproducer
   $ ./correct_proc_mem_reproducer
   vulnerable

Рассмотрим процесс установки и использования systemtap в Ubuntu и Debian.

Установим systemtap и пакет для отладки ядра (занимает около 2 Гб)

Debian:

   sudo apt-get install -y systemtap linux-image-$(uname -r)-dbg

Ubuntu (требуется подключение отладочного репозитория):

   sudo apt-get install -y lsb-release
   echo "deb http://ddebs.ubuntu.com/ $(lsb_release -cs) main restricted universe multiverse" | \\
     tee -a /etc/apt/sources.list.d/ddebs.list
   sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ECDCAD72428D7C01
   sudo apt-get update
   sudo apt-get install -y systemtap linux-image-$(uname -r)-dbgsym

Если в процессе выполнения "apt-get update" выведена ошибка, загружаем и
устанавливаем отладочные пакеты с ядром вручную:

   sudo apt-get install -y systemtap dpkg-dev
   wget http://ddebs.ubuntu.com/pool/main/l/linux/$(dpkg -l linux-image-$(uname -r) | \\
      grep ^ii | awk '{print $2 "-dbgsym_" $3}' | tail -n1)_$(dpkg-architecture -qDEB_HOST_ARCH).ddeb
   sudo dpkg -i linux-image-$(uname -r)-dbgsym.ddeb

Создаём systemtap-скрипт proc-pid-mem.stp для блокирования уязвимости (в
функции mem_write изменяем на ноль значение аргумента count, определяющего
размер записываемых данных):

   probe kernel.function("mem_write@fs/proc/base.c").call {
           $count = 0
   }

Запускаем скрипт:

   sudo stap -Fg proc-pid-mem.stp

Убедимся, что уязвимость теперь не проявляется:

   $ ./correct_proc_mem_reproducer
   not vulnerable


Чтобы каждый раз не компилировать модуль systemtap, можно собрать его загодя:

   stap -g -m cve_2012_0056 proc-pid-mem.stp -p4

(опция  "-g" включает режим гуру, при котором допускается изменение параметров
функций, опция -m cve_2012_0056 задаёт имя модуля, -p4 указывает на
необходимость остановиться на 4 шаге и не загружать модуль)

Копируем созданный модуль в область с модулями ядра:

   mkdir /lib/modules/$(uname -r)/systemtap
   cp cve_2012_0056.ko /lib/modules/$(uname -r)/systemtap

Запускаем модуль:

   staprun -L cve_2012_0056

Достоинство использования готового модуля в том, что для его запуска нет
необходимости в отладочных пакетах (для сборки они нужны), т.е. его можно
скопировать на другие системы с той же версией ядра Linux.

По аналогии можно вклиниваться в работу других системных вызовов. Некоторые 
примеры:



   Запрет на создание файлов с определённым именем:
   #!/usr/bin/env stap
   # badname.stp
   # Prevent the creation of files with undesirable names.
   # Source: http://blog.cuviper.com/2009/04/08/hacking-linux-filenames/

   # return non-zero if the filename should be blocked
   function filter:long (name:string)
   {
     return isinstr(name, "XXXbadnameXXX")
   }

   global squash_inode_permission
   probe kernel.function("may_create@fs/namei.c")
   {
     # screen out the conditions which may_create will fail anyway
     if ($child->d_inode || $dir->i_flags & 16) next

     # check that the new file meets our naming rules
     if (filter(kernel_string($child->d_name->name)))
       squash_inode_permission[tid()] = 1
   }
   probe kernel.function("inode_permission@fs/namei.c").return !,
         kernel.function("permission@fs/namei.c").return
   {
   if (!$return && squash_inode_permission[tid()])
     $return = -13 # -EACCES (Permission denied)
     delete squash_inode_permission[tid()]
   }


Блокирование работы ptrace: http://sourceware.org/systemtap/examples/process/noptrace.stp

Вывод в лог дополнительных данных о всех TCP-соединениях:

   #! /usr/bin/env stap

   probe begin {
     printf("%6s %16s %6s %6s %16s\\n",
         "UID", "CMD", "PID", "PORT", "IP_SOURCE")
   }

   probe kernel.function("tcp_accept").return?,
         kernel.function("inet_csk_accept").return? {
     sock = $return
     if (sock != 0)
       printf("%6d %16s %6d %6d %16s\\n", uid(), execname(), pid(),
           inet_get_local_port(sock), inet_get_ip_source(sock))
   }

Вывод деталей о входе и выходе из функции ядра:

   #! /usr/bin/env stap
   # Simple probe to detect when a process is waiting for more socket send
   # buffer memory. Usually means the process is doing writes larger than the
   # socket send buffer size or there is a slow receiver at the other side.
   # Increasing the socket's send buffer size might help decrease application
   # latencies, but it might also make it worse, so buyer beware.
   #
   # Typical output: timestamp in microseconds: procname(pid) event
   #
   # 1218230114875167: python(17631) blocked on full send buffer
   # 1218230114876196: python(17631) recovered from full send buffer
   # 1218230114876271: python(17631) blocked on full send buffer
   # 1218230114876479: python(17631) recovered from full send buffer

   probe kernel.function("sk_stream_wait_memory")
   {
  	printf("%u: %s(%d) blocked on full send buffer\\n",
		gettimeofday_us(), execname(), pid())
   }

   probe kernel.function("sk_stream_wait_memory").return
   {
	printf("%u: %s(%d) recovered from full send buffer\\n",
		gettimeofday_us(), execname(), pid())
   }
 
25.01.2012 , Источник: http://www.outflux.net/blog/archive...
Ключи: systemtap, kernel, linux, syscall, block, limit, debian, ubuntu / Лицензия: CC-BY
Раздел:    Корень / Безопасность / Шифрование, PGP

Обсуждение [ RSS ]
  • 1.1, x (?), 20:33, 25/01/2012 [ответить]  
  • +/
    probe kernel.function("mem_write@fs/proc/base.c").call {
               $count = 0
       }
    означает замену содержимого функции ядра mem_write() на фикцию, в данном случае установку переменной с произвольным именем? я правильно понял?
     
     
  • 2.2, Аноним (-), 10:30, 26/01/2012 [^] [^^] [^^^] [ответить]  
  • +/
    > probe kernel.function("mem_write@fs/proc/base.c").call {
    >            $count
    > = 0
    >    }
    > означает замену содержимого функции ядра mem_write() на фикцию, в данном случае установку
    > переменной с произвольным именем? я правильно понял?

    нет, он выступает в роли враппера перед вызовом, который меняет содержимое аргумента count

     

  • 1.3, eth (?), 11:06, 26/01/2012 [ответить]  
  • +/
    У меня в debian/sid этот метод почему-то не сработал.
    После запуска stap -g proc-pid-mem.stp программа correct_proc_mem_reproducer.c всё равно выдаёт vulnerable, т.е. процессу удается перезаписать указатель у себя в /proc/self/mem. Причём не срабатывает именно ограничение аргумента $count.
    Probe вызывается, проверял добавлением туда printf().
     
  • 1.4, Аноним (-), 09:52, 27/01/2012 [ответить]  
  • –1 +/
    все же тяжко в bb дистрибутивах, что бы юзеры294 (теперь уже анонимусы) не говорили...
     
     
  • 2.5, Аноним (-), 09:41, 28/01/2012 [^] [^^] [^^^] [ответить]  
  • +/
    > все же тяжко в bb дистрибутивах

    Что такое bb дистрибутивы? И есть ли какие-то там не-bb дистрибутивы, в которых stap работает иначе?

     
  • 2.7, Аноним (-), 23:49, 29/01/2012 [^] [^^] [^^^] [ответить]  
  • +/
    > все же тяжко в bb дистрибутивах, что бы юзеры294 (теперь уже анонимусы)
    > не говорили...

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

    Зачем надо столько прыжков с бубном я честно говоря не понял. Ну то-есть можно конечно сделать простую вещь сложно, но по-моему наиболее корректно было бы просто заменить бажное ядро на зафикшеное.

    В общем если это была попытка превознести sb-дистры - я так и не понял, в каком месте у вас наступил EPIC WIN. Может быть я тупой? :)

     
     
  • 3.8, Аноним (-), 23:02, 01/02/2012 [^] [^^] [^^^] [ответить]  
  • +/
    > Зачем надо столько прыжков с бубном я честно говоря не понял.

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

     
     
  • 4.10, Аноним (-), 21:52, 06/02/2012 [^] [^^] [^^^] [ответить]  
  • +/
    > Иногда нельзя прямо сейчас перезагрузиться, а ошибку исправлять нужно.

    Ну ок, допустим. Правда я так и не понял чем SB в этом плане будут лучше.

     

  • 1.6, Аноним (-), 23:44, 29/01/2012 [ответить]  
  • +/
    А не проще, пардон, кернел обновить?
    $ ./correct_proc_mem_reproducer
    write: Invalid argument
    not vulnerable
     
     
  • 2.9, chemtech (ok), 21:09, 03/02/2012 [^] [^^] [^^^] [ответить]  
  • +/
    Человек же написал:

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

     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру