Você está de plantão, soa um alerta, e o evento contém isto:
%{(#_memberAccess["allowStaticMethodAccess"]=true).(@java.lang.Runtime@getRuntime().exec("id"))}
A pergunta útil não é "isso é ruim" - obviamente é -, mas o que a carga pretendia fazer e se teria alguma chance aqui. São perguntas diferentes, com respostas diferentes, e a própria carga diz bastante sobre as duas.
O que é OGNL, e por que um framework avaliaria uma
Object-Graph Navigation Language é uma linguagem de expressão para ler e escrever propriedades de objetos Java. Um framework a usa para que a configuração alcance a aplicação em execução: buscar esta propriedade, chamar aquele método, formatar o resultado. É um recurso razoável. E é o problema inteiro, porque uma expressão capaz de chamar métodos em objetos vivos só é segura enquanto toda expressão avaliada tiver sido escrita por alguém de confiança.
O Apache Struts passou anos corrigindo uma família de falhas com um mesmo formato: entrada de uma requisição chegava a um avaliador que a tratava como configuração. A mais conhecida, em 2017, estava no parser multipart de upload, em que um cabeçalho Content-Type malformado era avaliado enquanto o framework montava a mensagem de erro sobre ele. A requisição não precisava dar certo. Precisava falhar do jeito certo.
As duas metades
Uma tentativa funcional precisava de duas coisas separadas, e distingui-las é quase todo o valor diagnóstico de uma carga.
A fuga do sandbox. A OGNL restringe o que uma expressão pode tocar, por um objeto interno chamado _memberAccess. Por padrão ele recusa chamadas estáticas, que é o que impede uma expressão de alcançar toda a biblioteca de classes Java. A fuga consiste em alcançar esse objeto e desligar a restrição:
#_memberAccess["allowStaticMethodAccess"]=true
A primitiva de execução. Uma vez permitido o acesso estático, o objeto Runtime da JVM está a uma chamada de distância, e exec inicia um processo do sistema:
@java.lang.Runtime@getRuntime().exec("id")
O que cada combinação diz
As duas presentes. Tentativa real de exploração, montada por quem entendeu o mecanismo. Apure se a requisição foi bloqueada, se o runtime está corrigido e o que a aplicação fez com ela. Trate o horário como a parte interessante da linha, não a carga.
Execução sem fuga. Comum, e bem menos alarmante. Em qualquer runtime corrigido a chamada estática é recusada, então a carga não sai da avaliação de expressão para a criação de processo. Normalmente significa que um scanner percorre uma lista, não que alguém olhou especificamente para a sua aplicação.
Fuga sem execução. Muitas vezes a primeira etapa de uma tentativa em duas partes, ou uma sondagem verificando se a manipulação é possível antes de enviar algo caro.
Nenhuma das duas, mas com sintaxe de expressão. Algo como %{1+1}. É uma sondagem com uma única pergunta: esta entrada é avaliada? Se a resposta for não, nada do resto da lista funciona, o que torna esta a requisição mais barata e mais informativa que o atacante pode enviar. É também a que mais se descarta como ruído.
O erro a evitar
Uma leitura limpa de uma carga codificada fala da codificação, não do ataque. Cargas OGNL são rotineiramente codificadas em URL, duplamente codificadas ou divididas entre parâmetros que a aplicação concatena depois. Se você colar %25%7B num decodificador e ele não achar nada, essa é a resposta certa para a pergunta errada. Decodifique primeiro, leia depois.
E uma carga prova o que foi tentado, nunca o que estava presente. Não diz a versão do framework, a configuração, nem se a requisição chegou à aplicação. Isso está no evento do e no log da aplicação - a carga é apenas a pergunta que alguém fez.
A outra metade desta história
A mesma linguagem é recurso de configuração suportado em outros produtos, onde administradores escrevem expressões de propósito. O PingFederate é o exemplo mais claro: expressões são úteis o bastante para manter, e perigosas o bastante para que escrevê-las seja um papel administrativo separado de configurar o restante. É a mesma propriedade deste artigo, vista do lado em que alguém pensou nela com antecedência.