setuid root não funciona

2

Objetivo : Executa um programa como root (binário em C ++). O mesmo que: Bit SetUID não funciona no Ubuntu?

E: Por que o setuid não funciona no executável?

./ a.out output:

E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied) E: Unable to lock the administration directory (/var/lib/dpkg/), are you root? psurana //output for "whoami" Look below for the code.

ls -l output:

-rwsrwxr-x 1 root root 46136 Jun 7 20:13 a.out

O código:

#include <string>
#include <stdlib.h>
int main(int argc, char *argv[]){
        std::string input = "apt-get install " + std::string(argv[1]);
        system(input.c_str());
        system("whoami");
        return 0;
}

Detalhes: : compilou o programa e fez chown root:root a.out && chmod u+s a.out . Por favor, olhe acima para a saída ls -l.

Eu ainda não recebo privilégios de root e a saída para system ("whoami") no código é meu próprio nome de usuário na máquina.

A leitura das duas perguntas relacionadas não me rendeu em nenhum lugar. :(. tanto o criador quanto o proprietário do arquivo são raiz. O bit setuid está definido, então deve funcionar. O sistema de arquivos também não é externo, é minha própria máquina. Como posso fazer isso funcionar?

    
por Pranay 08.06.2017 / 05:31

2 respostas

4

Se você alterar o código desse modo, poderá ver os UIDs efetivos e reais:

#include <string>
#include <stdlib.h>
int main(int argc, char *argv[]){
        system("id");
        system("bash -c id");
        return 0;
}

No meu sistema, isso retorna essas duas linhas (usei ... para pular grupos irrelevantes):

uid=1001(roaima) gid=1001(roaima) euid=0(root) groups=1001(roaima),24(cdrom),...,103(vboxsf)
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima),24(cdrom),...,103(vboxsf)

Como você pode ver, a chamada bruta para id retorna um UID efetivo de 0 (raiz), mas o UID real ainda é meu. Isso é o que você esperaria.

No entanto, você pode ver que a chamada bash -c id removeu o UID efetivo para que ele não seja mais executado como raiz. Isso está documentado em man bash da seguinte maneira:

If the shell is started with the effective user (group) id not equal to the real user (group) id, and the -p option is not supplied, no startup files are read, shell functions are not inherited from the environment, the SHELLOPTS, BASHOPTS, CDPATH, and GLOBIGNORE variables, if they appear in the environment, are ignored, and the effective user id is set to the real user id. If the -p option is supplied at invocation, the startup behavior is the same, but the effective user id is not reset.

Portanto, a solução aqui deve ser incluir o sinalizador -p .

(Você pode saber mais sobre o processo pelo qual bash redefine seu UID em bit Setuid parece não ter efeito sobre o bash .)

No entanto, a história não está terminada aqui porque sei que você vai dizer que você não invocou bash . Infelizmente para você, isso é basicamente o que o system() faz em seu nome e não permite que você especifique -p .

strace descarta os privilégios de root, mas aqui está o suficiente da saída strace -f ./a.out para você ver o que está acontecendo:

execve("./a.out", ["./a.out"], [/* 44 vars */]) = 0
brk(0)                                  = 0x24f1000
...
clone(child_stack=0, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7ffee0d42a1c) = 4619
wait4(4619, Process 4619 attached
 <unfinished ...>

Neste ponto, o processo filho inicia, pronto para executar nosso id

[pid  4619] rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f100eb270e0}, NULL, 8) = 0
[pid  4619] rt_sigaction(SIGQUIT, {SIG_DFL, [], SA_RESTORER, 0x7f100eb270e0}, NULL, 8) = 0
[pid  4619] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[pid  4619] execve("/bin/sh", ["sh", "-c", "id"], [/* 44 vars */]) = 0
[pid  4619] brk(0)                      = 0x7f849dd71000
[pid  4619] brk(0)                      = 0x7f849dd71000
...
[pid  4619] clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f849d1d89d0) = 4620

Agora temos um shell em execução e descartamos nosso UID efetivo. Em seguida, você verá a inicialização do comando id e a gravação de sua saída para stdout :

Process 4620 attached
[pid  4619] wait4(-1,  <unfinished ...>
[pid  4620] execve("/usr/bin/id", ["id"], [/* 44 vars */]) = 0
[pid  4620] brk(0)                      = 0x1785000
...
[pid  4620] write(1, "uid=1001(roaima) gid=1001(roaim"..., 149) = 149
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima),24(cdrom),...,103(vboxsf)
...

A solução para você aqui é usar diretamente uma das famílias exec*() ou incluir uma chamada para setuid(0) ou configurar uma ferramenta como sudo para permitir que você chame seu programa de destino diretamente e (presumivelmente) sem uma senha.

Entre essas opções, eu pessoalmente incluo a solução sudo . Os autores disso gastaram muito tempo garantindo que o código fosse seguro contra ataques de privilégio (in) planejados (a).

    
por 08.06.2017 / 15:25
2

Este é um processo de dois passos.

  1. defina o bit suid do executável como você fez.

  2. ligue para setuid(uid_t uid) em man setuid .

se o seu objetivo for somente o apt-get, você pode querer usar sudo .

    
por 08.06.2017 / 09:33