Почему бит setuid работает непоследовательно?

8

Я написал код:

// a.c
#include <stdlib.h>
int main () {
  system("/bin/sh");
  return 0;
}

скомпилировано с командой:

gcc a.c -o a.out

добавлен бит setuid:

sudo chown root.root a.out
sudo chmod 4755 a.out

В Ubuntu 14.04, когда я работаю как обычный пользователь, я получил привилегию root.

но в Ubuntu 16.04 я все еще получил оболочку текущего пользователя.

Почему это отличается?

user10883182
источник

Ответы:

9

Что изменилось, так это то, что он /bin/shстал bashили остался, dashполучив дополнительный флаг, -pимитирующий поведение bash.

Bash требует, чтобы -pфлаг не сбрасывал привилегию setuid, как объяснено на его man-странице :

Если оболочка запущена с эффективным идентификатором пользователя (группы), не равным реальному идентификатору пользователя (группы), и опция -p не указана, файлы запуска не читаются, функции оболочки не наследуются от среды, SHELLOPTS Переменные BASHOPTS, CDPATH и GLOBIGNORE, если они появляются в среде, игнорируются, а эффективный идентификатор пользователя устанавливается равным реальному идентификатору пользователя . Если опция -p указана при вызове, поведение при запуске такое же, но эффективный идентификатор пользователя не сбрасывается.

Раньше dashэто не волновало и разрешало выполнение setuid (не делая ничего, чтобы предотвратить это). Но на dashman-странице Ubuntu 16.04 описана дополнительная опция, похожая на bash:

-p priv
Не пытайтесь сбросить эффективный uid, если он не совпадает с uid. Это не установлено по умолчанию, чтобы избежать неправильного использования корневыми программами setuid через system (3) или popen (3).

Эта опция не существовала ни в апстриме (которая, возможно, не реагировала на предложенный патч * ), ни в Debian 9, но присутствует в тестере Debian, который получил патч с 2018 года.

Примечание: как объяснено Стефаном Chazelas, это слишком поздно , чтобы вызвать "/bin/sh -p"в system()потому , что system()работает что - то дается через /bin/shи так УИП уже упал. Ответ Дероберта объясняет, как с этим справиться, в коде ранее system().

* подробнее об истории здесь и там .

AB
источник
system("bash -p")работает, sh -c "bash -p"так что привилегии уже были удалены при bashвыполнении.
Стефан
да ладно ладно Я все равно уберу часть «решения», лучше обработанную ответом Дероберта.
AB
Смотрите также bugs.debian.org/cgi-bin/bugreport.cgi?bug=734869
Стефан
Похоже, Ubuntu исправил черту в хитрости (15.10). bugs.launchpad.net/ubuntu/+source/dash/+bug/1215660
Марк Плотник,
1
Обратите внимание, что Debian использовался наоборот. Раньше он исправлял bash, чтобы не пропускать привилегии. Является ли это улучшение является спорным. Теперь люди, которые хотят сделать system()с повышенными привилегиями (которые, в первую очередь, не должны), в конце концов, делают setresuid()раньше, что намного хуже, так как оболочка не знает, что это suid, поэтому не делает активируйте режим, в котором он не доверяет своей среде.
Стефан
8

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

/* needs _GNU_SOURCE; non-Linux users see setregid/setreuid instead */
uid_t euid = geteuid(), egid = getegid();
setresgid(egid, egid, egid);
setresuid(euid, euid, euid);

до вашего system(). (На самом деле, даже в Linux вам, вероятно, нужно только установить реальные; сохраненные должны быть в порядке, если оставить их в покое. Это просто грубая сила для отладки. В зависимости от того, почему вы настроили id, вам, конечно, может понадобиться где-то сохранить реальные идентификаторы.)

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

derobert
источник
Я сконцентрировался на том, почему это изменилось, а вы указали, как избежать этой проблемы. +1
АВ
Конечно, если вам действительно нужно где-то сохранить реальные идентификаторы, то сохраненный идентификатор - это очень удобное место для этого. Особенно, если эффективные идентификаторы не root: root.
Кевин