
Я пытаюсь выполнить скомпилированную программу C++ от имени пользователя root, будучи другим пользователем.
Программа успешно выполняется, но от имени обычного пользователя, а не root.
Однако, как говорят в интернете, chmod u+s
команда заставляет его запускаться от имени владельца (в моем случае - root).
Программа представляет собой простую system(argv[1])
строку, которая выполнит все, что находится внутри аргумента командной строки.
Например - Вывод для whoami
возвращает моего пользователя, а не root.
Попытка вывести список содержимого также /root
заканчивается сообщением «Отказано в доступе».
Разрешения файла -
-rwsr-xr-x 1 root root 16608 Aug 25 15:20 test
В этот момент я попытался настроить права доступа к файлу 4755
(безуспешно).
Перемещение файла /root
также оказалось неудачным.
решение1
Вызов system() использует execl()
системный вызов для создания нового процесса оболочки. Но системный вызов игнорирует эффективный идентификатор пользователя и возвращает ошибку EPERM (отказано в доступе).
Это потому, что оболочки Linux не наследуют бит seteuid. Почему? Ну, потому что есть реальные опасения по поводу запуска скрипта с эффективным идентификатором пользователя в качестве root. Для более подробной информации по теме см.здесь.
Можно запустить оболочку, которая действует на эффективный UID, передав параметр -p
. Из sh
страницы руководства:
-p приват Не пытайтесь сбросить эффективный uid, если он не совпадает с uid. Это не установлено по умолчанию, чтобы помочь избежать неправильного использования setuid root-программами через system(3) или popen(3).
Ограничение, конечно, не распространяется на системные вызовы. В качестве демонстрации эта программа на языке C пытается перечислить /root с помощью system()
, а затем делает то же самое с помощью системных вызовов opendir()
и readdir()
.
Если двоичный файл принадлежит пользователю root с установленным идентификатором пользователя, то запуск программы пользователем, не являющимся пользователем root, приведет к тому, что первый листинг /root завершится ошибкой, второй (с использованием display_dir()
works.
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<dirent.h>
#include<errno.h>
int display_dir(const char *dirname)
{
DIR *dp = opendir(dirname);
struct dirent *sd=NULL;
if (!dp) return(errno);
while ((sd = readdir(dp)) != NULL)
{
printf("%s\n", sd->d_name);
}
closedir(dp);
return 0;
}
int main()
{
system("ls /root");
printf("Display returned %d\n", display_dir("/root"));
}