Vulnerabilidades de Injeção em Aplicativos Web
Vulnerabilidades de Injeção em Aplicativos Web
Uma vulnerabilidade de injeção de comando está entre os tipos mais críticos de vulnerabilidades. Ela permite
para executarmos comandos do sistema diretamente no servidor de hospedagem de back-end, o que pode levar a
comprometendo toda a rede. Se um aplicativo da web usa entrada controlada pelo usuário para executar um
comando do sistema no servidor back-end para recuperar e retornar uma saída específica, podemos estar
capaz de injetar uma carga maliciosa para subverter o comando pretendido e executar nosso
comandos.
Riscos, dado seu alto impacto e quão comuns eles são. A injeção ocorre quando a entrada controlada pelo
usuário é mal interpretada como parte da consulta da web ou do código que está sendo executado, o que
pode levar à subversão do resultado pretendido da consulta para um resultado diferente que seja
útil para o atacante.
Existem muitos tipos de injeções encontradas em aplicativos da web, dependendo do tipo de web
consulta sendo executada. A seguir estão alguns dos tipos mais comuns de injeções:
Injeção Descrição
Injeção de comando do SO Ocorre quando a entrada do usuário é usada diretamente como parte de um comando
do sistema operacional.
Injeção de código Ocorre quando a entrada do usuário está diretamente dentro de uma
função que avalia o código.
Injeções SQL Ocorre quando a entrada do usuário é usada diretamente como parte de
uma consulta SQL.
Cross-Site Scripting/HTML Ocorre quando a entrada exata do usuário é exibida em uma página
Injeção da web.
Existem muitos outros tipos de injeções além das acima, como injeção LDAP , NoSQL
Injeção , Injeção de Cabeçalho HTTP , Injeção XPath , Injeção IMAP e outros. Sempre que a entrada ORM
higienizada, pode ser possível escapar dos limites da string de entrada do usuário para o pai
Machine Translated by Google
consultar e manipulá-lo para alterar sua finalidade pretendida. É por isso que, à medida que mais tecnologias da
web são introduzidas em aplicativos da web, veremos novos tipos de injeções introduzidos em aplicativos da web.
Injeções de comando do SO
Quando se trata de Injeções de Comando do SO, a entrada do usuário que controlamos deve direta ou indiretamente
entrar (ou afetar de alguma forma) em uma consulta da web que executa comandos do sistema. Todas as linguagens de
programação da web têm funções diferentes que permitem ao desenvolvedor executar comandos do sistema
operacional diretamente no servidor back-end sempre que necessário. Isso pode ser usado para vários propósitos, como
Exemplo PHP
Por exemplo, um aplicativo web escrito em PHP pode usar as funções exec , system , shell_exec ou popen para executar
código a comandos diretamente no servidor back-end, cada passthru , tendo um caso de uso ligeiramente diferente. O
<?php
if (isset($_GET['nome do arquivo'])) {
sistema("toque /tmp/" . $_GET['nome do arquivo'] . ".pdf");
} ?>
Talvez um aplicativo da web em particular tenha uma funcionalidade que permita aos usuários criar um novo documento .pdf
que é criado no diretório /tmp com um nome de arquivo fornecido pelo usuário e pode então ser usado pelo aplicativo da web
para fins de processamento de documentos. No entanto, como a entrada do usuário do parâmetro filename na solicitação GET
é usada diretamente com o comando touch (sem ser sanitizada ou escapada primeiro), o aplicativo da web se torna vulnerável
à injeção de comando do SO. Essa falha pode ser explorada para executar comandos arbitrários do sistema no servidor
back-end.
Exemplo NodeJS
Isso não é exclusivo do PHP , mas pode ocorrer em qualquer framework ou linguagem de desenvolvimento web.
Por exemplo, se um aplicativo web for desenvolvido em NodeJS child_process.exec ou , um desenvolvedor pode usar
child_process.spawn para o mesmo propósito. O exemplo a seguir executa uma funcionalidade semelhante à que
discutimos acima:
})
O código acima também é vulnerável a uma vulnerabilidade de injeção de comando, pois usa o parâmetro
filename da solicitação GET como parte do comando sem higienizá-lo primeiro.
Tanto os aplicativos web PHP quanto os NodeJS podem ser explorados usando os mesmos métodos
de injeção de comando.
Da mesma forma, outras linguagens de programação de desenvolvimento web têm funções semelhantes
usadas para os mesmos propósitos e, se vulneráveis, podem ser exploradas usando os mesmos métodos de
injeção de comando. Além disso, vulnerabilidades de injeção de comando não são exclusivas de aplicativos web,
mas também podem afetar outros binários e thick clients se eles passarem entrada de usuário não higienizada
para uma função que executa comandos do sistema, que também pode ser explorada com os mesmos
métodos de injeção de comando.
Detecção
Podemos tentar inserir o IP do host local [Link] para verificar a funcionalidade e, como esperado,
ele retorna a saída do comando ping nos informando que o host local está realmente ativo:
Embora não tenhamos acesso ao código-fonte do aplicativo web, podemos supor com
segurança que o IP que inserimos está indo para um comando ping , já que a saída que recebemos
sugere isso. Como o resultado mostra um único pacote transmitido no comando ping, o comando
usado pode ser o seguinte:
ping -c 1 NOSSA_ENTRADA
Se nossa entrada não for sanitizada e escapada antes de ser usada com o comando ping ,
poderemos injetar outro comando arbitrário. Então, vamos tentar ver se o aplicativo web é
vulnerável à injeção de comando do SO.
Para injetar um comando adicional ao pretendido, podemos usar qualquer um dos seguintes
operadores:
Sub-Shell ``
%60%60 Ambos (somente Linux)
Podemos usar qualquer um desses operadores para injetar outro comando para que ambos ou qualquer um dos
comandos são executados. Nós escreveríamos nossa entrada esperada (por exemplo, um IP), então
use qualquer um dos operadores acima e então escreva nosso novo comando.
Dica: Além dos acima, existem alguns operadores somente Unix que funcionariam no Linux
e macOS, mas não funcionaria no Windows, como envolver nosso comando injetado com
``
acentos graves duplos ( ) ou com um operador de sub-shell ( $() ).
Em geral, para injeção de comando básico, todos esses operadores podem ser usados para comando
injeções independentemente da linguagem do aplicativo da web, estrutura ou back-end
servidor . Então, se estamos injetando em uma aplicação web PHP rodando em um servidor Linux , ou um
Aplicativo web .Net em execução em um servidor back-end do Windows ou um aplicativo web NodeJS
rodando em um servidor back-end macOS , nossas injeções devem funcionar de qualquer maneira.
Nota: A única exceção pode ser o ponto e vírgula ; sendo , que não funcionará se o comando foi
executado com a Linha de Comando do Windows (CMD) executado , mas ainda funcionaria se estivesse sendo
com o Windows PowerShell .
Na próxima seção, tentaremos usar um dos operadores de injeção acima para explorar o
Exercício do Host Checker .
Injetando comandos
Até agora, descobrimos que o aplicativo da web Host Checker é potencialmente vulnerável a
injeções de comando e discutimos vários métodos de injeção que podemos utilizar para explorar o
Machine Translated by Google
aplicação web. Então, vamos começar nossas tentativas de injeção de comando com o operador ponto e vírgula ( ; ).
[Link] (por exemplo, whoami ), de modo que a carga final que usaremos seja ( [Link]; whoami ), e o
comando final a ser executado seria:
Primeiro, vamos tentar executar o comando acima em nossa VM Linux para garantir que ele seja executado:
Como podemos ver, o comando final é executado com sucesso, e obtemos a saída de ambos os comandos
(conforme mencionado na tabela anterior para ; ). Agora, podemos tentar usar nossa carga útil anterior no aplicativo da
Como podemos ver, o aplicativo da web recusou nossa entrada, pois parece aceitar apenas entrada em um formato IP.
No entanto, pela aparência da mensagem de erro, parece que ela está se originando do
Machine Translated by Google
front-end em vez do back-end. Podemos verificar isso duas vezes com o Firefox Developer Tools clicando em [CTRL
+ SHIFT + E] para mostrar a aba Network e então clicando no botão Check novamente:
Como podemos ver, nenhuma nova solicitação de rede foi feita quando clicamos no botão Check , mas recebemos
uma mensagem de erro. Isso indica que a validação da entrada do usuário é
acontecendo no front-end .
Isso parece ser uma tentativa de nos impedir de enviar payloads maliciosos, permitindo apenas a entrada do
usuário em um formato IP. No entanto, é muito comum que desenvolvedores apenas
para executar validação de entrada no front-end sem validar ou higienizar a entrada no back-end. Isso
ocorre por vários motivos, como ter duas equipes diferentes trabalhando no front-end/back-end ou confiar na
validação do front-end para evitar payloads maliciosos.
Entretanto, como veremos, as validações de front-end geralmente não são suficientes para evitar injeções, pois
elas podem ser facilmente contornadas enviando solicitações HTTP personalizadas diretamente para o back-end.
Agora podemos personalizar nossa solicitação HTTP e enviá-la para ver como o aplicativo da web
lida com ela. Começaremos usando o mesmo payload anterior ( [Link]; whoami ). Também devemos
codificar nossa carga útil por URL para garantir que ela seja enviada como pretendemos. Podemos fazer
isso selecionando a carga útil e clicando em [CTRL + U] . Finalmente, podemos clicar em Enviar para enviar
nossa solicitação HTTP:
Como podemos ver, a resposta que obtivemos desta vez contém a saída do comando ping e o resultado do
comando whoami , o que significa que injetamos com sucesso nosso novo
comando .
Antes de prosseguirmos, vamos testar alguns outros operadores de injeção e ver como o aplicativo web os
manipularia de forma diferente.
Operador AND
Machine Translated by Google
Podemos começar com o operador AND ( && ), de modo que nossa carga útil final seria ( [Link] && whoami ), e
o comando final executado seria o seguinte:
Como sempre devemos fazer, vamos tentar executar o comando em nossa VM Linux primeiro para garantir que seja
um comando funcional:
Como podemos ver, o comando é executado, e obtemos a mesma saída que obtivemos anteriormente. Tente
consultar a tabela de operadores de injeção da seção anterior e veja como o operador && é diferente (se
não escrevermos um IP e começarmos diretamente com && ainda funciona?). , seria o comando
Agora, podemos fazer a mesma coisa que fizemos antes, copiando nossa carga útil e colando-a em nossa solicitação
HTTP no Burp Suite , codificando-o por URL e, finalmente, enviando-o:
Como podemos ver, injetamos nosso comando com sucesso e recebemos a saída esperada de ambos os comandos.
Operador OR
Machine Translated by Google
Por fim, vamos tentar o operador de injeção OR ( || ). O operador OR só executa o segundo comando se o primeiro
comando falhar na execução. Isso pode ser útil para nós em casos em que nossa injeção quebraria o comando
original sem ter uma maneira sólida de fazer ambos os comandos funcionarem. Então, usar o operador OR
faria nosso novo comando executar se o primeiro falhar.
Se tentarmos usar nossa carga útil usual com o operador || ( [Link] || whoami ), veremos que apenas o
primeiro comando será executado:
Isso ocorre devido ao modo como os comandos bash funcionam. Como o primeiro comando retorna o código de saída 0
indicando execução bem-sucedida, o comando bash para e não tenta o outro comando. Ele só tentaria
executar o outro comando se o primeiro comando falhasse e retornasse um código de saída 1 .
Tente usar a carga acima na solicitação HTTP e veja como o aplicativo web a manipula.
Vamos tentar quebrar intencionalmente o primeiro comando não fornecendo um IP e usando diretamente o
operador || ( || whoami ), de modo que o comando ping falhe e nosso comando injetado seja executado:
Como podemos ver, desta vez, o comando whoami foi executado após o comando ping falhar e nos deu uma
mensagem de erro. Então, vamos agora tentar o payload ( || whoami ) em nosso HTTP
Machine Translated by Google
solicitar:
Vemos que dessa vez só obtivemos a saída do segundo comando como esperado. Com isso,
estamos usando uma carga útil muito mais simples e obtendo um resultado muito mais limpo.
Esses operadores podem ser usados para vários tipos de injeção, como injeções de SQL, injeções de LDAP,
XSS, SSRF, XML, etc. Criamos uma lista dos operadores mais comuns que podem ser
Injeção XPath
'
ou e não substring concat contagem
`
Injeção de comando do SO ;&
'
Injeção de código ; -- /* */ $() ${} #{} %{} ^
Injeção de Shellcode \x \u %u %n
Tenha em mente que esta tabela está incompleta e muitas outras opções e operadores estão
possível. Também depende muito do ambiente com o qual estamos trabalhando e testando.
Neste módulo, estamos lidando principalmente com injeções de comando direto, nas quais nossa entrada
Para mais informações sobre injeções de comando avançadas, como injeções indiretas ou injeções cegas, você pode
consulte o Whitebox Pentesting 101: Injeção de comando módulo, que abrange conhecimentos avançados
Identificando filtros
Como vimos na seção anterior, mesmo que os desenvolvedores tentem proteger o aplicativo da web contra
injeções, ele ainda pode ser explorável se não tiver sido codificado com segurança. Outro tipo de mitigação de
injeção é utilizar caracteres e palavras da lista negra no back-end para detectar tentativas de injeção e negar a
solicitação se alguma solicitação as contiver. Outra camada sobre isso é utilizar Web Application Firewalls
(WAFs), que podem ter um escopo mais amplo e vários métodos de detecção de injeção e evitar vários outros
ataques, como injeções de SQL ou ataques XSS.
Esta seção analisará alguns exemplos de como injeções de comando podem ser detectadas e bloqueadas e
como podemos identificar o que está sendo bloqueado.
Detecção de filtro/WAF
Vamos começar visitando o aplicativo web no exercício no final desta seção. Vemos o mesmo aplicativo web Host
Checker que estávamos explorando, mas agora ele tem algumas mitigações na manga. Podemos ver que se
tentarmos os operadores anteriores que testamos, como ( , || ), obtemos a mensagem de erro invalid input :
; , &&
Isso indica que algo que enviamos acionou um mecanismo de segurança em vigor que negou nossa solicitação.
Essa mensagem de erro pode ser exibida de várias maneiras. Nesse caso, vemos isso no campo onde a saída é
exibida, o que significa que foi detectado e impedido pelo próprio aplicativo da web PHP . Se a mensagem de
erro exibiu uma página diferente, com informações como nosso IP e nossa solicitação, isso pode indicar que foi
negado por um WAF .
2. Um caractere de espaço
3. Um comando whoami
Um aplicativo web pode ter uma lista de caracteres na lista negra e, se o comando os contiver, ele negará a
solicitação. O código PHP pode ser parecido com o seguinte:
Se qualquer caractere na string que enviamos corresponder a um caractere na lista negra, nossa solicitação será
negada. Antes de começarmos nossas tentativas de contornar o filtro, devemos tentar identificar qual caractere
causou a solicitação negada.
[Link]; ):
Ainda obtemos um erro invalid input , significando que um ponto e vírgula está na lista negra. Então, vamos ver
se todos os operadores de injeção que discutimos anteriormente estão na lista negra.
Existem inúmeras maneiras de detectar tentativas de injeção, e existem vários métodos para ignorar essas
detecções. Demonstraremos o conceito de detecção e como o bypass funciona usando o Linux como
exemplo. Aprenderemos como utilizar esses bypasses e, eventualmente, seremos capazes de preveni-los. Depois
que tivermos uma boa compreensão de como eles funcionam, podemos passar por várias fontes na internet
para descobrir outros tipos de bypasses e aprender como mitigá-los.
Como podemos ver, embora nossa carga útil tenha incluído um caractere de nova linha, nossa solicitação não foi negada,
e obtivemos a saída do comando ping, o que significa que esse caractere não está na lista negra, e podemos usá-
lo como nosso operador de injeção . Vamos começar discutindo como ignorar um caractere comumente na lista negra -
um caractere de espaço.
( [Link]%0a whoami ):
Como podemos ver, ainda recebemos uma mensagem de erro de entrada inválida , o que significa que ainda temos
outros filtros para ignorar. Então, como fizemos antes, vamos adicionar apenas o próximo caractere (que é um
Machine Translated by Google
Como podemos ver, o caractere de espaço também está na lista negra. Um espaço é um caractere
comumente na lista negra, especialmente se a entrada não deve conter espaços, como um IP, por
exemplo. Ainda assim, há muitas maneiras de adicionar um caractere de espaço sem realmente usar o
caractere de espaço!
Usando abas
Usar tabulações (%09) em vez de espaços é uma técnica que pode funcionar, já que tanto o Linux
quanto o Windows aceitam comandos com tabulações entre argumentos, e eles são executados da mesma forma.
Então, vamos tentar usar uma tabulação em vez do caractere de espaço ( [Link]%0a%09 ) e ver se nossa
solicitação é aceita:
Como podemos ver, contornamos com sucesso o filtro de caracteres de espaço usando uma tabulação.
Vamos ver outro método de substituição de caracteres de espaço.
Usando $IFS
Usando o (
IFS)A variável de ambiente Linux também pode funcionar, pois seu valor padrão é um espaço e uma guia, o que seri
Machine Translated by Google
{IFS}` onde os espaços deveriam estar, a variável deveria ser automaticamente substituída por um
espaço, e nosso comando deveria funcionar.
Vemos que nossa solicitação não foi negada desta vez e ignoramos o filtro de espaço novamente.
Existem muitos outros métodos que podemos utilizar para ignorar filtros de espaço. Por exemplo, podemos
usar o recurso Bash Brace Expansion , que adiciona espaços automaticamente entre argumentos
encapsulados entre chaves, como segue:
{ls,-lá}
total 0
drwxr-xr-x 1 21y4d 21y4d 0 13 de julho 07:37 . drwxr-xr-x 1 21y4d
21y4d 0 13 de julho 13:01 ..
Como podemos ver, o comando foi executado com sucesso sem ter espaços nele. Podemos utilizar o mesmo
método em bypasses de filtro de injeção de comando, usando expansão de chaves em nossos argumentos
de comando, como ( [Link]%0a{ls,-la} ). Para descobrir mais bypasses de filtro de espaço, confira o
PayloadsAllTheThings página sobre como escrever comandos sem espaços.
Exercício: Tente procurar outros métodos para ignorar filtros de espaço e use-os com o aplicativo web
Host Checker para aprender como eles funcionam.
Além dos operadores de injeção e caracteres de espaço, um caractere muito comumente incluído na lista
negra é o caractere de barra ( / ) ou barra invertida ( \ ), pois é necessário para especificar diretórios no Linux
Machine Translated by Google
ou Windows. Podemos utilizar várias técnicas para produzir qualquer personagem que quisermos, evitando
o uso de personagens da lista negra.
Linux
Existem muitas técnicas que podemos utilizar para ter barras em nossa carga útil. Uma dessas
técnicas que podemos usar para substituir barras ( ou qualquer outro caractere ) é por meio de Variáveis de
Ambiente Linux , como fizemos com ${IFS} . Enquanto ${IFS} é substituído diretamente por um espaço, não
existe uma variável de ambiente para barras ou ponto e vírgula. No entanto, esses caracteres podem ser
usados em uma variável de ambiente, e podemos especificar o início e o comprimento de nossa string para
corresponder exatamente a esse caractere.
Por exemplo, se observarmos a variável de ambiente $PATH no Linux, ela pode ser parecida com o seguinte:
eco ${CAMINHO}
/usr/local/bin:/usr/bin:/bin:/usr/jogos
Então, se começarmos no caractere 0 e pegarmos apenas uma string de , acabaremos com apenas
comprimento 1, o caractere / , que podemos usar em nossa carga útil:
eco ${PATH:0:1}
Nota: Quando usamos o comando acima em nossa carga útil, não adicionaremos echo , , como nós somos
Podemos fazer o mesmo com as variáveis de ambiente $HOME ou $PWD também. Também podemos
use o mesmo conceito para obter um caractere ponto e vírgula, para ser usado como um operador de injeção.
Por exemplo, o comando a seguir nos dá um ponto e vírgula:
eco ${LS_COLORS:10:1}
Exercício: Tente entender como o comando acima resultou em um ponto e vírgula e, em seguida, use-o no
payload para usá-lo como um operador de injeção. Dica: O comando printenv imprime todos os
Machine Translated by Google
variáveis de ambiente no Linux, para que você possa ver quais delas podem conter caracteres úteis,
e então tente reduzir a string somente para aquele caractere.
Então, vamos tentar usar variáveis de ambiente para adicionar um ponto e vírgula e um espaço à nossa carga útil (
[Link]${LS_COLORS:10:1}${IFS} ) como nossa carga útil e veja se podemos ignorar o filtro:
Como podemos ver, também desta vez conseguimos contornar o filtro de caracteres.
Windows
O mesmo conceito funciona no Windows também. Por exemplo, para produzir uma barra no Windows
Linha de comando (CMD) , podemos ecoar uma variável do Windows ( %HOMEPATH% -> \Users\htb-
Podemos conseguir a mesma coisa usando as mesmas variáveis no Windows PowerShell . Com
PowerShell, uma palavra é considerada uma matriz, então temos que especificar o índice do caractere
precisamos. Como precisamos apenas de um caractere, não precisamos especificar o início e o fim
posições:
PS C:\htb> $env:HOMEPATH[0]
PS C:\htb>
Também podemos usar o comando Get-ChildItem Env: PowerShell para imprimir todas as variáveis de
ambiente e, em seguida, escolher uma delas para produzir um caractere que precisamos. Tente ser criativo
e encontrar comandos diferentes para produzir caracteres semelhantes.
Mudança de personagem
Existem outras técnicas para produzir os caracteres necessários sem usá-los, como a troca de caracteres . Por
exemplo, o seguinte comandodo Linux troca o caractere que
passe por 1 . Então, tudo o que temos que fazer é encontrar o caractere na tabela ASCII que está logo antes do
nosso caractere necessário (podemos obtê-lo com man ascii ), então adicioná-lo em vez de [ no exemplo abaixo.
Dessa forma, o último caractere impresso seria o que precisamos:
Podemos usar comandos do PowerShell para obter o mesmo resultado no Windows, embora eles possam ser bem
mais longos que os do Linux.
Exercício: Tente usar a técnica de mudança de caractere para produzir um caractere ponto e vírgula ; .
Primeiro, encontre o caractere antes dele na tabela ascii e, então, use-o no comando acima.
Discutimos vários métodos para ignorar filtros de caracteres únicos. No entanto, existem métodos diferentes quando
se trata de ignorar comandos na lista negra. Uma lista negra de comandos geralmente consiste em um
conjunto de palavras e, se pudermos ofuscar nossos comandos e fazê-los parecer diferentes, poderemos
ignorar os filtros.
Existem vários métodos de ofuscação de comando que variam em complexidade, como abordaremos mais tarde com
ferramentas de ofuscação de comando. Abordaremos algumas técnicas básicas que podem nos permitir mudar a
aparência do nosso comando para ignorar filtros manualmente.
Machine Translated by Google
Até agora, contornamos com sucesso o filtro de caracteres para os caracteres de espaço e ponto e vírgula em
nosso payload. Então, vamos voltar para nosso primeiro payload e adicionar novamente o comando whoami
para ver se ele é executado:
Vemos que, embora tenhamos usado caracteres que não são bloqueados pelo aplicativo da web, a solicitação é
bloqueada novamente quando adicionamos nosso comando. Isso provavelmente se deve a outro tipo de filtro, que
é um filtro de lista negra de comando.
Um filtro de lista negra de comandos básico em PHP seria parecido com o seguinte:
Como podemos ver, ele está verificando cada palavra da entrada do usuário para ver se ela corresponde a
alguma das palavras da lista negra. No entanto, esse código está procurando uma correspondência exata
do comando fornecido, então se enviarmos um comando ligeiramente diferente, ele pode não ser bloqueado. Felizmente,
podemos utilizar várias técnicas de ofuscação que executarão nosso comando sem usar a palavra exata do comando.
Linux e Windows
Uma técnica de ofuscação muito comum e fácil é inserir certos caracteres em nosso comando que geralmente são
ignorados por shells de comando como Bash ou PowerShell e irão
Machine Translated by Google
execute o mesmo comando como se eles não estivessem lá. Alguns desses caracteres são aspas simples '
e aspas duplas " , além de alguns outros.
As mais fáceis de usar são aspas, e elas funcionam tanto em servidores Linux quanto Windows. Por exemplo,
se quisermos ofuscar o comando whoami , podemos inserir aspas simples entre seus caracteres, como a
seguir:
21 anos e 4 dias
21y4d@htb[/htb]$ quem"eu"sou
21 anos e 4 dias
As coisas importantes a lembrar são que não podemos misturar tipos de citações e o número de citações deve
ser par . Podemos tentar um dos itens acima em nossa carga útil ( [Link]%0aw'h'o'am'i ) e ver se
funciona:
Somente Linux
Podemos inserir alguns outros caracteres exclusivos do Linux no meio dos comandos, e o shell bash os ignoraria
e executaria o comando. Esses caracteres incluem a barra invertida
Machine Translated by Google
\ e o caractere de parâmetro posicional $@ . Isso funciona exatamente como com as aspas, mas neste caso, o
número de caracteres não precisa ser nem mesmo um deles se quisermos: , e podemos inserir
quem$@ami
quem\sou\eu
Exercício: Tente os dois exemplos acima em seu payload e veja se eles funcionam para ignorar o filtro de comando.
Se não funcionarem, isso pode indicar que você pode ter usado um caractere filtrado.
Você conseguiria contornar isso também, usando as técnicas que aprendemos na seção anterior?
Somente Windows
Há também alguns caracteres exclusivos do Windows que podemos inserir no meio dos comandos que não afetam o
resultado, como um caractere circunflexo ( ^ ), como podemos ver no exemplo a seguir:
C:\htb> quem^sou
21 anos e 4 dias
Na próxima seção, discutiremos algumas técnicas mais avançadas para ofuscação de comandos e
desvio de filtros.
Em alguns casos, podemos estar lidando com soluções avançadas de filtragem, como Web Application Firewalls
(WAFs), e técnicas básicas de evasão podem não necessariamente funcionar. Podemos utilizar técnicas mais
avançadas para tais ocasiões, o que torna a detecção dos comandos injetados muito menos provável.
Manipulação de Casos
Uma técnica de ofuscação de comando que podemos usar é a manipulação de maiúsculas e minúsculas, como inverter as maiúsculas
e minúsculas dos caracteres de um comando (por exemplo, WHOAMI ) ou alternar entre maiúsculas e minúsculas (por exemplo, WhOaMi ).
Machine Translated by Google
Isso geralmente funciona porque uma lista negra de comandos pode não verificar variações de maiúsculas e minúsculas de uma
Se estivermos lidando com um servidor Windows, podemos alterar a caixa dos caracteres do comando e enviá-lo. No Windows,
os comandos para PowerShell e CMD não diferenciam maiúsculas de minúsculas, o que significa que eles executarão
PS C:\htb> WhOaMi
21 anos e 4 dias
No entanto, quando se trata de Linux e um shell bash, que são sensíveis a maiúsculas e minúsculas, como mencionado
anteriormente, temos que ser um pouco criativos e encontrar um comando que transforme o comando em uma palavra toda em
21 anos e 4 dias
Como podemos ver, o comando funcionou, embora a palavra que fornecemos fosse ( WhOaMi ).
Este comando usa tr para substituir todos os caracteres maiúsculos por caracteres minúsculos, o que resulta em um comando
all-minúsculo. No entanto, se tentarmos usar o comando acima com o aplicativo da web Host Checker , veremos que ele ainda
fica bloqueado:
Você consegue adivinhar o porquê? É porque o comando acima contém espaços, que é um caractere filtrado em nossa
aplicação web, como vimos antes. Então, com tais técnicas, nós
deve sempre ter certeza de não usar nenhum caractere filtrado , pois isso falhará e podemos , caso contrário, nossos pedidos
Depois de substituir os espaços por tabulações ( %09 ), vemos que o comando funciona perfeitamente:
Existem muitos outros comandos que podemos usar para o mesmo propósito, como os seguintes:
$(a="OqueOaMi";printf %s "${a,,}")
Exercício: Você pode testar o comando acima para ver se ele funciona na sua VM Linux e, então, tentar
evitar o uso de caracteres filtrados para fazê-lo funcionar no aplicativo web?
Comandos Invertidos
Outra técnica de ofuscação de comando que discutiremos é reverter comandos e ter um modelo de
comando que os troca de volta e os executa em tempo real. Neste caso, escreveremos imaohw em vez
de whoami para evitar disparar o comando na lista negra.
Podemos ser criativos com essas técnicas e criar nossos próprios comandos Linux/Windows que
eventualmente executam o comando sem nunca conter as palavras de comando reais.
Primeiro, teríamos que obter a string invertida do nosso comando em nosso terminal, como segue:
Então, podemos executar o comando original revertendo-o em um sub-shell ( $() ), como segue:
21y4d@htb[/htb]$ $(rev<<<'imaohw')
Machine Translated by Google
21 anos e 4 dias
Vemos que, embora o comando não contenha a palavra whoami real , ele funciona da mesma forma e
fornece a saída esperada. Também podemos testar esse comando com nosso exercício, e ele realmente
funciona:
Dica: Se você quiser ignorar um filtro de caracteres com o método acima, você terá que revertê-los também
ou incluí-los ao reverter o comando original.
O mesmo pode ser aplicado no Windows. Podemos primeiro inverter uma string, como segue:
imaohw
Agora podemos usar o comando abaixo para executar uma string invertida com um subshell do
PowerShell ( iex "$()" ), como segue:
21 anos e 4 dias
Comandos codificados
A técnica final que discutiremos é útil para comandos que contêm caracteres filtrados ou caracteres que
podem ser decodificados por URL pelo servidor. Isso pode permitir que o comando obtenha
Machine Translated by Google
bagunçado no momento em que chega ao shell e eventualmente falha na execução. Em vez de copiar um comando
existente online, tentaremos criar nosso próprio comando de ofuscação exclusivo desta vez. Dessa forma, é muito
menos provável que seja negado por um filtro ou um WAF. O comando que criamos será exclusivo para cada
caso, dependendo de quais caracteres são permitidos e do nível de segurança no servidor.
Podemos utilizar várias ferramentas de codificação, como base64 (para codificação b64) ou xxd (para
codificação hexadecimal). Vamos usar base64 como exemplo. Primeiro, codificaremos o payload que queremos
executar (que inclui caracteres filtrados):
Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==
Agora podemos criar um comando que decodificará a string codificada em um sub-shell ( $() ) e então passá-la
para o bash para ser executada (ou seja, bash<<< ), da seguinte maneira:
bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)
www-dados:x:33:33:www-dados:/var/www:/usr/sbin/nologin
Como podemos ver, o comando acima executa o comando perfeitamente. Não incluímos nenhum caractere
filtrado e evitamos caracteres codificados que podem levar o comando a falhar
executar.
Dica: Observe que estamos usando <<< para evitar o uso de pipe | , que é um personagem filtrado.
Agora podemos usar este comando (depois de substituir os espaços) para executar o mesmo comando
por meio de injeção de comando:
Mesmo que alguns comandos tenham sido filtrados, como bash ou base64 , poderíamos ignorar esse filtro com
as técnicas que discutimos na seção anterior (por exemplo, inserção de caracteres) ou usar outras
alternativas como sh para execução de comando e openssl para decodificação b64, ou xxd para hex
decodificação.
Usamos a mesma técnica com o Windows também. Primeiro, precisamos codificar em base64 nosso
sequência, como segue:
PS C:\htb>
[Converter] ::ToBase64String( [[Link]ção] ::[Link]('quem sou eu
'))
dwBoAG8AYQBtAGkA
Também podemos conseguir o mesmo no Linux, mas teríamos que converter a string de
utf-8 para utf-16 antes de base64 , como segue:
dwBoAG8AYQBtAGkA
Finalmente, podemos decodificar a string b64 e executá-la com um sub-shell do PowerShell ( iex
"$()" ), como segue:
PS C:\htb> iex
"$( [[Link]ção] ::[Link]( [[Link]] ::DeBase64S
string('dwBoAG8AYQBtAGkA')))"
21 anos e 4 dias
Como podemos ver, podemos ser criativos com Bash ou PowerShell e criar novos desvios
e métodos de ofuscação que não foram usados antes e, portanto, são muito propensos a
filtros de bypass e WAFs. Várias ferramentas podem nos ajudar a ofuscar automaticamente nossos comandos,
que discutiremos na próxima seção.
Além das técnicas que discutimos, podemos utilizar vários outros métodos, como
curingas, regex, redirecionamento de saída, expansão de inteiros e muitos outros. Podemos encontrar alguns
tais técnicas em PayloadsAllTheThings.
Ferramentas de Evasão
Machine Translated by Google
Se estivermos lidando com ferramentas de segurança avançadas, talvez não consigamos usar técnicas
básicas de ofuscação manual. Em tais casos, pode ser melhor recorrer a ferramentas de ofuscação
automatizadas. Esta seção discutirá alguns exemplos desses tipos de ferramentas, uma para Linux e outra
para Windows.
Linux (Bashfuscator)
Uma ferramenta útil que podemos utilizar para ofuscar comandos bash é o Bashfuscator. Podemos clonar o
repositório do GitHub e então instalar seus requisitos, da seguinte maneira:
Depois que tivermos a ferramenta configurada, podemos começar a usá-la a partir do diretório ./
bashfuscator/bin/ . Há muitos sinalizadores que podemos usar com a ferramenta para ajustar nosso comando
ofuscado final, como podemos ver no menu de ajuda -h :
cd ./bashfuscator/bin/
./bashfuscator -h
Podemos começar simplesmente fornecendo o comando que queremos ofuscar com o sinalizador -c :
[+] Mutadores usados: Token/ForCode -> Command/Reverse [+] Carga útil: ${*/+27\
[X\(} ...SNIP... ${*~}
Machine Translated by Google
No entanto, executar a ferramenta dessa forma escolherá aleatoriamente uma técnica de ofuscação, que pode
gerar um comprimento de comando variando de algumas centenas de caracteres a mais de um milhão
de caracteres! Então, podemos usar alguns dos sinalizadores do menu de ajuda para produzir um comando
ofuscado mais curto e simples, como a seguir:
pretendido:
raiz:x:0:0:raiz:/raiz:/bin/bash
...RECORTE...
Podemos ver que o comando ofuscado funciona, tudo isso parecendo completamente ofuscado, e não se
assemelha ao nosso comando original. Também podemos notar que a ferramenta utiliza muitas técnicas de ofuscação,
incluindo as que discutimos anteriormente e muitas outras.
Exercício: Tente testar o comando acima com nosso aplicativo web, para ver se ele consegue ignorar
os filtros com sucesso. Se não conseguir, você consegue adivinhar o porquê? E você consegue fazer a ferramenta
produzir uma carga útil funcional?
Windows (DOSfuscação)
Há também uma ferramenta muito semelhante que podemos usar no Windows chamada DOSfuscation. Diferente
Bashfuscator , esta é uma ferramenta interativa, pois a executamos uma vez e interagimos com ela para obter o
comando ofuscado desejado. Podemos clonar a ferramenta novamente do GitHub e então invocá-la através
do PowerShell, como segue:
Machine Translated by Google
PS C:\htb> cd Invocar-DOSfuscation
PS C:\htb> Importar-Módulo .\Invoke-DOSfuscation.psd1
PS C:\htb> Invocar-DOSfuscation
Invoke-DOSfuscation> ajuda
Podemos até usar o tutorial para ver um exemplo de como a ferramenta funciona. Uma vez que estamos definidos, nós
pode começar a usar a ferramenta, da seguinte forma:
Invoke-DOSfuscation> codificação
Invocar-DOSfuscation\Encoding> 1
...RECORTE...
Resultado:
typ%TEMP:~-3,-2% %CommonProgramFiles:~17,-11%:\Usuários\h%TMP:~-13,-12%b-
stu%SystemRoot:~-4,-3%ent%TMP:~-19,-18%%ALLUSERSPROFILE:~-4,-3%esktop\flag
.%TMP:~-13,-12%xt
Por fim, podemos tentar executar o comando ofuscado no CMD e ele , e vemos que de fato
C:\htb> tipo%TEMP:~-3,-2%
%CommonProgramFiles:~17,-11%:\Usuários\h%TMP:~-13,-12%b-
stu%SystemRoot:~-4,-3%ent%TMP:~-19,-18%%ALLUSERSPROFILE:~-4,-3%esktop\flag
.%TMP:~-13,-12%xt
sinalizador_de_teste
Dica: Se não tivermos acesso a uma VM Windows, podemos executar o código acima em uma VM Linux
através do pwsh . Execute o pwsh e siga exatamente o mesmo comando acima. Esta ferramenta é
Machine Translated by Google
instalado por padrão na sua instância `Pwnbox`. Você também pode encontrar instruções de instalação neste link.
Para mais informações sobre métodos avançados de ofuscação, você pode consultar o Secure Coding 101:
JavaScript módulo, que aborda métodos avançados de ofuscação que podem ser utilizados em vários ataques,
incluindo os que abordamos neste módulo.
Agora devemos ter um entendimento sólido de como as vulnerabilidades de injeção de comando ocorrem e como
certas mitigações, como filtros de caracteres e comandos, podem ser ignoradas. Esta seção discutirá métodos
que podemos usar para evitar vulnerabilidades de injeção de comando em nossos aplicativos da web e configurar
adequadamente o servidor da web para preveni-las.
Comandos do sistema
Devemos sempre evitar usar funções que executem comandos do sistema, especialmente se estivermos usando
entrada do usuário com elas. Mesmo quando não estamos inserindo diretamente a entrada do usuário nessas
funções, um usuário pode ser capaz de influenciá-las indiretamente, o que pode eventualmente levar a uma
vulnerabilidade de injeção de comando.
Em vez de usar funções de execução de comando do sistema, devemos usar funções internas que realizam a
funcionalidade necessária, pois as linguagens de back-end geralmente têm implementações seguras
desses tipos de funcionalidades. Por exemplo, suponha que quiséssemos testar se um host específico está ativo
com PHP . Nesse caso, podemos usar a função fsockopen em vez disso, que não deve ser explorável para
executar comandos arbitrários do sistema.
Se precisarmos executar um comando do sistema e nenhuma função interna puder ser encontrada para
executar a mesma funcionalidade, nunca devemos usar diretamente a entrada do usuário com essas funções,
mas devemos sempre validar e higienizar a entrada do usuário no back-end.
Além disso, devemos tentar limitar o uso desses tipos de funções o máximo possível e usá-las somente quando não
houver uma alternativa integrada à funcionalidade que precisamos.
Validação de entrada
Seja usando funções internas ou funções de execução de comando do sistema, devemos sempre validar e então
higienizar a entrada do usuário. A validação de entrada é feita para garantir que ela corresponda ao formato
esperado para a entrada, de modo que a solicitação seja negada se não corresponder. Em nosso aplicativo da
web de exemplo, vimos que houve uma tentativa de validação de entrada no front-
Machine Translated by Google
final, mas a validação de entrada deve ser feita tanto no front-end quanto no back-end.
fim .
Em PHP , como muitas outras linguagens de desenvolvimento web, existem filtros integrados para uma variedade de
formatos padrão, como e-mails, URLs e até mesmo IPs, que podem ser usados com o filter_var
função, como segue:
se (filter_var($_GET['ip'], FILTER_VALIDATE_IP)) {
// chamar função
} outro {
// negar solicitação
}
Se quisermos validar um formato diferente e não padrão, podemos usar um formato Regular
Expressão regex com a função preg_match . O mesmo pode ser alcançado com
se(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-
9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.( 25[0-5]|2[0-4][0-9]|
[01]?[0-9][0-9]?)$/.teste(ip)){
// chamar função
}
outro{
// negar solicitação
}
Assim como PHP , com NodeJS , também podemos usar bibliotecas para validar vários formatos padrão,
como is-ip por exemplo, que podemos instalar com npm e, em seguida, usar a função isIp(ip) em
nosso código. Você pode ler os manuais de outras linguagens, como .NET ou Java, para descobrir como
Sanitização de entrada
A parte mais crítica para evitar qualquer vulnerabilidade de injeção é a higienização de entrada, que
a sanitização é sempre realizada após a validação da entrada. Mesmo depois de validarmos que o
desde que a entrada do usuário esteja no formato adequado, ainda devemos realizar a higienização e remover
quaisquer caracteres especiais não necessários para o formato específico, pois há casos em que a entrada
Em nosso código de exemplo, vimos que quando estávamos lidando com filtros de caracteres e comandos,
ele estava colocando certas palavras na lista negra e procurando por elas na entrada do usuário. Geralmente, essa
não é uma abordagem boa o suficiente para evitar injeções, e devemos usar funções internas para remover quaisquer
caracteres especiais. Podemos usar preg_replace para remover quaisquer caracteres especiais da entrada
do usuário, como a seguir:
Como podemos ver, o regex acima permite apenas caracteres alfanuméricos ( A-Za-z0-9 ) e permite um caractere
de ponto ( . ) conforme necessário para IPs. Quaisquer outros caracteres serão removidos da string. O mesmo
pode ser feito com JavaScript , como segue:
Também podemos usar a biblioteca DOMPurify para um back-end NodeJS , da seguinte forma:
Em certos casos, podemos querer permitir todos os caracteres especiais (por exemplo, comentários do usuário),
então podemos usar a mesma função filter_var que usamos com validação de entrada e usar o filtro
escapeshellcmd para escapar quaisquer caracteres especiais, para que eles não possam causar nenhuma
injeção. Para NodeJS , podemos simplesmente usar a função escape(ip) . No entanto, como temos
visto neste módulo, escapar caracteres especiais geralmente não é considerado uma prática segura, pois muitas
vezes pode ser contornado por meio de várias técnicas .
Para mais informações sobre validação e higienização de entrada do usuário para evitar injeções de comando,
consulte Secure Coding 101: JavaScript módulo, que aborda como auditar o código-fonte de um aplicativo web
para identificar vulnerabilidades de injeção de comando e, em seguida, trabalhar para corrigir adequadamente
esses tipos de vulnerabilidades.
Configuração do servidor
Por fim, devemos garantir que nosso servidor back-end esteja configurado com segurança para reduzir o impacto
no caso de o servidor web ser comprometido. Algumas das configurações que podemos implementar são:
Use o Firewall de Aplicativo Web integrado do servidor web (por exemplo, no Apache mod_security ), além de
um WAF externo (por exemplo, Cloudflare , Fortinet , Imperva ..)
Machine Translated by Google
Cumpra o Princípio do Menor Privilégio (PoLP) executando o servidor web como um usuário com
privilégios baixos (por exemplo, www-data )
Impedir que certas funções sejam executadas pelo servidor web (por exemplo, em PHP
disable_functions=system,... )
Limitar o escopo acessível pelo aplicativo da web à sua pasta (por exemplo, em PHP
open_basedir = '/var/www/html' )
Rejeitar solicitações com codificação dupla e caracteres não ASCII em URLs
No final, mesmo depois de todas essas mitigações e configurações de segurança, temos que executar as técnicas
de teste de penetração que aprendemos neste módulo para ver se alguma funcionalidade do aplicativo da
web ainda pode ser vulnerável à injeção de comando. Como alguns aplicativos da web têm milhões de linhas
de código, qualquer erro em qualquer linha de código pode ser suficiente para introduzir uma vulnerabilidade.
Portanto, devemos tentar proteger o aplicativo da web complementando as melhores práticas de codificação
segura com testes de penetração completos.
Avaliação de habilidades
Você é contratado para executar um teste de penetração para uma empresa e, por meio do seu pentest, você
tropeça em um aplicativo web gerenciador de arquivos interessante. Como os gerenciadores de arquivos tendem
a executar comandos do sistema, você está interessado em testar vulnerabilidades de injeção de
comando.
Use as diversas técnicas apresentadas neste módulo para detectar uma vulnerabilidade de injeção de
comando e então explorá-la, evitando quaisquer filtros existentes.