Introdução
A injeção de comandos, ou code injection, é uma das vulnerabilidades mais críticas que podem existir. Ela pode permitir a execução de comandos diretamente no backend do sistema, comprometendo toda a rede.
Quando se diz a respeito de um OS Command Injection, o input do usuário é utilizado diretamente dentro de algum tipo de comando diretamente no sistema operacional. Toda linguagem de programação possui diferentes funcionalidades que permitem a execução de comandos diretamente no sistema operacional. Isso pode ser utilizado para diversos propósitos, como instalar plugins ou executar certos tipos de aplicações.
Exemplo em PHP
Por exemplo, uma aplicação web escrita em PHP pode usar exec
, system
, shell_exec
, passthru
ou popen
para executar comandos diretamente no sistema operacional, cada um sendo diferente para o seu caso. O seguinte código de PHP está vulnerável a o que nós chamamos de Code Injection.
<?php
if (isset($_GET['filename'])) {
system("touch /tmp/" . $_GET["filename"] . ".pdf");
}
?>
Detecção
O processo de detectar OS Command Injection é o mesmo processo que usamos para explorá-los. Nós tentamos colocar diversas cargas de comandos de diversas maneiras e métodos diferentes. Se o output mudar além do output usual, nós conseguimos explorar a vulnerabilidade. Isso pode não ser verdade para injeção de comandos mais avançadas, onde nós precisamos usar diversos métodos de fuzzing ou revisões de códigos para identificar vulnerabilidades de injeção de comandos em potencial. Nós então devemos gradualmente melhorar nosso payload até conseguirmos uma injeção de comando bem sucedida.
Métodos
Para explorar e manipular a vulnerabilidade, podemos utilizar diversos métodos, e podemos seguir os seguintes operadores:
Operador | Caractere | URL Encoded | Comando executado |
---|---|---|---|
Ponto virgula | ; | %3b | Ambos |
Nova linha | \n | %0a | Ambos |
Background | & | %26 | Ambos (o segundo comando geralmente aparece primeiro) |
Pipe | | | %7c | Ambos (somente o segundo comando aparece) |
AND | && | %26%26 | Ambos (somente se o primeiro for executado com sucesso) |
OR | || | %7c%7c | Ambos (somente se o primeiro falhar) |
Sub-Shell | “ | %60%60 | Ambos (somente em Linux) |
Sub-Shell | $() | %24%28%29 | Ambos (somente em Linux) |
Nós podemos usar esses operadores para que ambos ou algum dos comandos seja executado. Nós vamos escrever em algum comando já existente, então usar esses operadores para escrever um novo comando. |
Dica
Em adição aos acima, existem alguns operadores somente para o UNIX, que apenas funcional em Linux e macOS, mas não funcionam no Windows, como os operadores de sub-shells.
Alguns aplicações podem implementar filtros insuficientes para tentar diminuir os riscos desse tipo de ataque. Entretanto, dependendo da maneira como foram implementados, podem ser burlados.
Diferença entre
${}
e$()
Existe uma diferença crucial entre esses dois tokens. O
${}
deve ser utilizado quando existe alguma substituição de caractere numa string. O$()
é uma subshell, isso é, um segundo comando que será executado dentro do já existente. Portanto, para a maioria dos filtros, usa-se${}
Utilização de
'
e"
É necessário ter um cuidado especial em relação a utilização de aspas simples e aspas duplas. Existe uma diferença quando se diz a respeito da utilização desses caracteres em relação ao uso de subshells ou tokens de caracteres. Com aspas simples, o resultado será sempre o literal, sem a execução das subshells ou formatação dos tokens. Por outro lado, a utilização de aspas duplas sempre irá executar as subsheells e formatar os tokens.
Bypasses
Bypass em filtro de espaços
Existem diversas maneiras de burlar o filtro contra o caractere de espaço, tais como:
- Utilização do
${IFS}
para simular o caractere de espaço - Utilização do
%09
para simular o caractere de espaço - Utilização de
{}
para passar múltiplos parâmetros para um único comando (exemplo{ls,-la}
)
Bypasses em filtros de caracteres por codificação hexadecimal
Quando uma aplicação utiliza de filtros contra certos caracteres, pode-se tentar a codificação em hexadecimal. Por exemplo:
echo -e "\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"
Bypasses em filtros de palavras
Pode-se utilizar caracteres em formato de strings para executar comandos, por exemplo:
wh'o'am'i'
Existem diversos outros bypasses que vão depender do cenário que você está enfrentando.
Bypass em caracteres proibidos
LInux
Da mesma maneria que podemos simular o caractere de espaço através do código ${IFS}
, também podemos simular alguns outros caracteres usando a propriedade de slicing para conseguir acesso a alguns caracteres proibidos. Por exemplo, o caractere \
pode ser também escrito como:
echo ${PATH:0:1}
Sendo que a variável PATH
começa necessariamente com /
.
Outros caracteres também podem ser simulados, como é o caso do ;
, que pode ser adquirido através do ${LS_COLORS:10:1}
.
Windows
O mesmo conceito pode ser atingido para o Windows, sendo que a sintaxe é um pouco diferente. Para o primeiro exemplo, para o Windows Command Line (CMD)o equivalente seria igual a:
echo %HOMEPATH:~6,-11%
Já para o Windows Powershell, o equivalente seria algo como:
$env:HOMEPATH[0]
Ofuscação
Um outro método para a execução de código remoto é a ofuscação do código a ser executado. Isso pode ser feito de diversas maneiras, tais como:
Codificação em Base64
A codificação em Base64 é uma boa maneira de contornar filtros de caracteres. Isso pode ser feito como por exemplo:
echo -n 'cat /etc/passwd | grep 33' | base64
E ser executado na máquina alvo com
bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)
Porque utilizar
<<<
?Utilizamos
<<<
justamente para evitar o uso do caractere pipe (|
), que pode estar em algum tipo de blacklist.