Eu tenho um diretório /var/mychoot
no mesmo sistema de arquivos que /
, e iniciei o programa /var/mychroot/prog
como sudo chroot /var/mychroot /prog
, então o programa está sendo executado como EUID 0.
Se o programa executar a técnica de escape chdir("..") , ele poderá escapar do chroot e ver tudo dentro de /
. (Verifiquei isso no Linux 4.18.)
Eu quero evitar tal fuga. Na verdade, eu quero evitar todos os tipos de escapes chroot, mas nesta questão estou interessado apenas em como a técnica de escape chdir("..") pode ser evitada em sistemas Linux modernos. Para isso estou procurando alternativas da chamada de sistema chroot(2) .
Eu encontrei 2 soluções: pivot_root e MS_MOVE , mas eles só funcionam se /var/mychroot
for um ponto de montagem, então eles falham se /var/mychroot
for apenas um subdiretório dentro do sistema de /
arquivos. Existe outra solução neste caso?
Eu quero evitar técnicas usando LD_PRELOAD
(porque LD_PRELOAD
não afeta executáveis vinculados estaticamente), técnicas usando ptrace(2) (porque então não consigo executar strace
dentro do chroot, e também ptrace(2) é muito complicado de acertar: processos irão travar ou travar) e virtualização real (por exemplo, Xen ou KVM ou QEMU; devido à sobrecarga de desempenho e ao provisionamento de memória menos flexível).
Para recapitular, preciso de:
- uma alternativa de chamada de sistema chroot(2) ,
- com qual root pode restringir processos rodando como root (EUID 0),
- para um subdiretório do sistema de arquivos de
/
, - que impede a técnica de escape chdir("..") ,
- e não usa
LD_PRELOAD
ou - ptrace(2) ou
- virtualização (por exemplo, Xen, KVM ou QEMU),
- e roda em um sistema Linux moderno,
- com e kernel não corrigido.
Isto existe?
Para se proteger contra a
chdir("..")
técnica de fuga específica que você mencionou, você pode simplesmente descartar a capacidade de executarchroot(2)
novamente quando estiver chrootado a/var/mychroot
si mesmo. A técnica de escape requer outra chamada parachroot()
, portanto, bloquear isso é suficiente para impedir que funcione.Você pode fazer isso com os recursos do Linux, descartando
CAP_SYS_CHROOT
qual é o necessário parachroot(2)
estar disponível.Por exemplo:
(O segundo prompt dentro do chroot é de um shell gerado de
capsh
. Você pode fazê-lo executar outro comando com, por exemplo,capsh --drop=cap_sys_chroot -- -c 'exec ./escape_chroot'
.)Mas uma técnica muito melhor é usar apenas
pivot_root
, já que protege de muitas outras possíveis explorações quechroot(2)
não protegerão.Você mencionou que só funciona se
/var/mychroot
for um ponto de montagem, mas você pode torná-lo um ponto de montagem simplesmente vinculando-o a ele mesmo.Observe que você precisa criar um namespace de montagem para usar
pivot_root
para criar uma jaula, caso contrário, ele tentará alterar a raiz de todos os processos em seu sistema de arquivos, o que provavelmente não é o que você deseja aqui ...Então toda a sequência vai:
(Novamente, muitos desses comandos estão gerando novos shells.
unshare
faz isso, tambémchroot
. Você pode contornar isso passando comandos como argumentos extras. Em alguns casos, você pode querer passarsh -c '...'
por um script completo.)Neste ponto, você está dentro de uma
pivot_root
jaula em um namespace de montagem separado, e o fato de/var/mychroot
ser simplesmente um diretório da raiz original (e não uma montagem de um dispositivo separado ou dispositivo de loop) não impediu que isso funcionasse, graças à montagem de ligação em si.Executando o código de escape, você verá que a prisão funciona conforme o esperado (mesmo que o código de escape afirme o contrário):
Como você pode ver, ainda dentro da prisão... O código de exploração é um pouco ingênuo e assume que desde que as operações (
chroot
,chdir
) tenham sido bem sucedidas, isso foi suficiente para escapar da prisão, o que não é realmente o caso.. .Portanto, considere usar essa técnica para criar uma jaula que seja superior
chroot
e não exija o uso de recursos do Linux para bloquear operações dentro dela (como criarchroot
s adicionais, que podem ser úteis ou necessários para o que você está tentando executar em um cadeia.)Você pode tornar qualquer diretório um ponto de montagem:
mount --rbind /var/mychoot /var/mychoot
.Esta etapa - e outras que você precisará - são abordadas aqui:
Como executar chroot com namespaces do Linux?
Combine o acima com namespaces de usuário.
Alternativamente,
seccomp
. É assim que o Docker impede que processos contidos chamemmount()
, por exemplo. (Quando você monta um dispositivo de bloco pela segunda vez, obtém uma segunda visualização desse sistema de arquivos, que conta mais ou menos como um escape). Copie a lista de syscalls permitidas do Docker - o root tem muitas maneiras diferentes de escapar.https://docs.docker.com/engine/security/seccomp/
https://github.com/moby/moby/blob/master/profiles/seccomp/default.json