Como permitir que o apache / PHP não privilegiado faça uma tarefa raiz (CentOS)

2

Estou configurando uma espécie de caixa de depósito pessoal para nossos clientes em uma máquina CentOS 6.3. O servidor estará acessível através de SFTP e uma base de serviço http proprietária no PHP. Esta máquina estará na nossa DMZ, por isso tem que ser segura. Por causa disso, eu tenho o apache rodando como um usuário sem privilégios, endureci a segurança do apache, do sistema operacional, do PHP, apliquei muita filtragem no iptables e apliquei alguns TCP Wrappers restritivos. Agora você pode ter suspeitado que este estava chegando, o SELinux também está pronto para aplicar.

Estou configurando o PAM para usar o MySQL para que meus usuários no aplicativo da Web possam efetuar login. Esses usuários estarão todos em um grupo que pode usar o SSH somente para SFTP e os usuários serão chrooted para sua própria pasta 'home'.

Para permitir que este SELinux queira que as pastas tenham a tag user_home_t. Além disso, o diretório pai precisa ser gravável apenas pelo usuário root. Se estas restrições não forem cumpridas, o SELinux irá matar o tubo SSH imediatamente.

Os arquivos que precisam ser acessados através de http e SFTP, então eu fiz um módulo SELinux para permitir que o Apache procure / attr / read / write, etc, em diretórios com a tag user_home_dir_t.

Como os usuários do sftp são armazenados no MySQL, eu quero configurar seus diretórios iniciais na criação do usuário. Isso é um problema, já que o Apache não tem acesso de gravação ao diretório / home, ele é apenas gravável pelo root, já que é necessário manter o SELinux e o OpenSSH felizes.

Basicamente eu preciso deixar o Apache fazer apenas algumas tarefas como root e somente dentro de / home. Então eu preciso de alguma forma elevar os privilégios temporariamente ou deixar o root fazer essas tarefas para o apache.

O que eu preciso fazer com o apache com privilégios de root é o seguinte.

mkdir /home/userdir/
mkdir /home/userdir/userdir
chmod -R 0755 /home/userdir
umask 011 /home/userdir/userdir
chcon -R -t user_home_t /home/userdir
chown -R user:sftp_admin /home/userdir/userdir
chmod 2770 /home/userdir/userdir

Isso criaria um lar para o usuário, agora eu tenho uma idéia que pode funcionar, cron. Isso significaria que o servidor precisa verificar se há usuários que não têm casa a cada minuto, então, ao criar usuários, a interface congelaria por uma média de 30 segundos antes que a criação da conta pudesse ser confirmada, o que eu não prefiro. Alguém sabe se algo pode ser feito com sudoers? Ou qualquer outra idéia é bem vinda ...

Obrigado pelo seu tempo!

    
por Chris 21.11.2012 / 23:06

2 respostas

1

Crie um script que implemente os comandos descritos e execute setuid para permitir que ele seja executado como root quando alguém o invocar. Consulte o link para obter mais informações sobre o setuid.

A partir do PHP, você pode simplesmente chamar system('/bin/setupNewUser'); como de costume e o script será executado como root.

Solução alternativa que limita as oportunidades de injeção e funciona em sistemas com execução setuid em scripts desativados:

Crie um pequeno programa que tenha setuid. Um exemplo listado abaixo:

#include <stdlib.h>
#include <iostream>
#include <string>

using namespace std;

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout << "Invalid arguments";
        return 1;
    }

    //make sure the argument passed to the script has only [a-z]
    for (char* i = argv[1]; *i != '
system('/test/setupUser '.escapeshellarg($username));
'; i++) { //check if the current character falls outside an allowed range if (!( //Allowed ranges: // between a and z ('a' <= *i && *i <= 'z') // between 0 and 9 || ('0' <= *i && *i <= '9') // '_' or '-' || ('_' == *i) || ('-' == *i) )) { cout << "Illegal character in username: " << *i << endl; return 2; } } //append the username string command = string("/test/setupUser.sh "); command += string(argv[1]); //execute the command and return the result transparently // return system(command.c_str()); // * OR * // call mkdir directly }

Chame o programa setuid do php

#include <stdlib.h>
#include <iostream>
#include <string>

using namespace std;

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout << "Invalid arguments";
        return 1;
    }

    //make sure the argument passed to the script has only [a-z]
    for (char* i = argv[1]; *i != '
system('/test/setupUser '.escapeshellarg($username));
'; i++) { //check if the current character falls outside an allowed range if (!( //Allowed ranges: // between a and z ('a' <= *i && *i <= 'z') // between 0 and 9 || ('0' <= *i && *i <= '9') // '_' or '-' || ('_' == *i) || ('-' == *i) )) { cout << "Illegal character in username: " << *i << endl; return 2; } } //append the username string command = string("/test/setupUser.sh "); command += string(argv[1]); //execute the command and return the result transparently // return system(command.c_str()); // * OR * // call mkdir directly }
    
por 21.11.2012 / 23:39
3

POR FAVOR, NÃO FAÇA ISSO!

Pelo menos não da maneira que você sugere - Não há razão sã para o Apache fazer ANYTHING como root.
O nível de notoriedade do que você está sugerindo deve ser aparente pelo fato de que o Apache se recusará a executar como root (exceto a ligação do processo mãe à porta 80).

Também fazer algo como root com entrada de usuário não confiável é uma idéia terrível e uma maneira segura de descobrir todas as coisas interessantes que um hacker pode digitar em uma caixa faz com que seu sistema faça coisas que você não esperava.

Se você realmente quiser fazer isso:

  • Crie os diretórios do usuário manualmente.
    Este passo manual com validação humana salvará seu sistema. Permitir qualquer entrada de usuário não confiável dentro de uma milha de um shell de root está apenas pedindo por problemas.
    • O proprietário do diretório deve ser o usuário.
    • O grupo de diretórios deve ser o grupo que o Apache executa como.
    • As permissões do diretório provavelmente devem ser 4770 ( rwsrwx--- )

Isso permitirá que seu usuário leia / escreva / etc. o conteúdo do diretório e o bit SetUID no diretório forçará o usuário a ser o proprietário de todos os arquivos (para que possam manipulá-los quando conectados usando SCP / SFTP).

    
por 22.11.2012 / 00:29